4 * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved
6 * Contact: Kidong Kim <kd0228.kim@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
26 #include <sys/types.h>
38 #include <sys/smack.h>
39 #include <linux/capability.h>
40 #include <sys/capability.h>
45 #include "privilege-control.h"
46 #include "access-db.h"
51 #define DEVELOPER_GID 5100
52 #define DEVELOPER_UID 5100
54 #define APP_USER_NAME "app"
55 #define DEV_USER_NAME "developer"
57 #define APP_HOME_DIR TOSTRING(HOMEDIR) "/app"
58 #define DEV_HOME_DIR TOSTRING(HOMEDIR) "/developer"
60 #define APP_GROUP_PATH TOSTRING(SHAREDIR) "/app_group_list"
61 #define DEV_GROUP_PATH TOSTRING(SHAREDIR) "/dev_group_list"
63 #define SMACK_APP_LABEL_TEMPLATE "~APP~"
64 #define SMACK_SHARED_DIR_LABEL_TEMPLATE "~APP_SHARED_DIR~"
66 #define SMACK_SRC_FILE_SUFFIX "_src_file"
67 #define SMACK_SRC_DIR_SUFFIX "_src_dir"
68 #define SMACK_DATA_SUFFIX "_data"
69 #define WRT_BASE_DEVCAP "WRT"
70 #define WRT_CLIENT_PATH "/usr/bin/wrt-client"
72 #define TIZEN_PRIVILEGE_ANTIVIRUS "http://tizen.org/privilege/antivirus"
73 #define TIZEN_PRIVILEGE_APPSETTING "http://tizen.org/privilege/appsetting"
74 #define PATH_RULES_PUBLIC_RO "PATH_RULES_PUBLIC_RO.smack"
75 #define PATH_RULES_GROUP_RW "PATH_RULES_GROUP_RW.smack"
91 typedef int (*label_decision_fn)(const FTSENT*);
97 API int control_privilege(void)//deprecated
99 C_LOGD("Enter function: %s", __func__);
100 if(getuid() == APP_UID) // current user is 'app'
101 return PC_OPERATION_SUCCESS;
103 if(perm_app_set_privilege("org.tizen.", NULL, NULL) == PC_OPERATION_SUCCESS)
104 return PC_OPERATION_SUCCESS;
106 return PC_ERR_NOT_PERMITTED;
110 * TODO: this function should be moved to libsmack in open-source.
112 API int get_smack_label_from_process(pid_t pid, char smack_label[SMACK_LABEL_LEN + 1])
114 C_LOGD("Enter function: %s", __func__);
117 int PATH_MAX_LEN = 64;
118 char path[PATH_MAX_LEN + 1];
121 ret = PC_ERR_INVALID_PARAM;
125 if(smack_label == NULL) {
126 C_LOGE("Invalid param smack_label (NULL).");
127 ret = PC_ERR_INVALID_PARAM;
131 bzero(smack_label, SMACK_LABEL_LEN + 1);
132 if (!have_smack()) { // If no smack found just return success and empty label
133 C_LOGD("No SMACK. Return empty label");
134 ret = PC_OPERATION_SUCCESS;
138 bzero(path, PATH_MAX_LEN + 1);
139 snprintf(path, PATH_MAX_LEN, "/proc/%d/attr/current", pid);
140 fd = open(path, O_RDONLY);
142 C_LOGE("cannot open file %s (errno: %s)", path, strerror(errno));
143 ret = PC_ERR_FILE_OPERATION;
147 ret = read(fd, smack_label, SMACK_LABEL_LEN);
149 C_LOGE("cannot read from file %s", path);
150 ret = PC_ERR_FILE_OPERATION;
154 ret = PC_OPERATION_SUCCESS;
160 API int smack_pid_have_access(pid_t pid,
162 const char *access_type)
164 C_LOGD("Enter function: %s", __func__);
166 char pid_subject_label[SMACK_LABEL_LEN + 1];
168 cap_flag_value_t cap_v;
171 C_LOGD("No SMACK. Return access granted");
176 C_LOGE("Invalid pid.");
181 C_LOGE("Invalid object param.");
185 if(access_type == NULL) {
186 C_LOGE("Invalid access_type param");
190 //get SMACK label of process
191 ret = get_smack_label_from_process(pid, pid_subject_label);
192 if (PC_OPERATION_SUCCESS != ret) {
193 C_LOGE("get_smack_label_from_process %d failed: %d", pid, ret);
196 C_LOGD("pid %d have label: %s", pid, pid_subject_label);
198 // do not call smack_have_access() if label is empty
199 if (pid_subject_label[0] != '\0') {
200 ret = smack_have_access(pid_subject_label, object, access_type);
202 C_LOGE("smack_have_access failed");
205 if ( 1 == ret ) { // smack_have_access return 1 (access granted)
206 C_LOGD("smack_have_access returned 1 (access granted)");
211 // smack_have_access returned 0 (access denied). Now CAP_MAC_OVERRIDE should be checked
212 C_LOGD("smack_have_access returned 0 (access denied)");
213 cap = cap_get_pid(pid);
215 C_LOGE("cap_get_pid failed");
218 ret = cap_get_flag(cap, CAP_MAC_OVERRIDE, CAP_EFFECTIVE, &cap_v);
220 C_LOGE("cap_get_flag failed");
224 if (cap_v == CAP_SET) {
225 C_LOGD("pid %d has CAP_MAC_OVERRIDE", pid);
229 C_LOGD("pid %d doesn't have CAP_MAC_OVERRIDE", pid);
234 static int set_dac(const char *smack_label, const char *pkg_name)
236 C_LOGD("Enter function: %s", __func__);
237 FILE* fp_group = NULL; // /etc/group
238 uid_t t_uid = -1; // uid of current process
239 gid_t *glist = NULL; // group list
240 gid_t temp_gid = -1; // for group list
241 char buf[10] = {0, }; // contents in group_list file
242 int glist_cnt = 0; // for group list
246 unsigned *additional_gids = NULL;
249 * initialize user structure
251 C_LOGD("initialize user structure");
252 memset(usr.user_name, 0x00, 10);
253 memset(usr.home_dir, 0x00, 64);
254 memset(usr.group_list, 0x00, 64);
259 C_LOGD("Current uid is %d", t_uid);
261 if(t_uid == 0) // current user is 'root'
263 if(!strncmp(pkg_name, "developer", 9))
265 strncpy(usr.user_name, DEV_USER_NAME, sizeof(usr.user_name));
266 usr.uid = DEVELOPER_UID;
267 usr.gid = DEVELOPER_GID;
268 strncpy(usr.home_dir, DEV_HOME_DIR, sizeof(usr.home_dir));
269 strncpy(usr.group_list, DEV_GROUP_PATH, sizeof(usr.group_list));
273 strncpy(usr.user_name, APP_USER_NAME, sizeof(usr.user_name));
276 strncpy(usr.home_dir, APP_HOME_DIR, sizeof(usr.home_dir));
277 strncpy(usr.group_list, APP_GROUP_PATH, sizeof(usr.group_list));
281 * get group information
283 C_LOGD("get group information");
284 if(!(fp_group = fopen(usr.group_list, "r")))
286 C_LOGE("File open error: %s", usr.group_list);
287 result = PC_ERR_FILE_OPERATION; // return -1
291 while(fgets(buf, 10, fp_group) != NULL)
294 temp_gid = strtoul(buf, 0, 10);
295 if(errno != 0) // error occured during strtoul()
297 C_LOGE("Cannot change string to integer: %s", buf);
298 result = PC_ERR_INVALID_OPERATION;
302 glist = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + 1));
305 result = PC_ERR_MEM_OPERATION; // return -2
306 C_LOGE("Cannot allocate memory");
309 glist[glist_cnt] = temp_gid;
315 if(NULL != smack_label)
320 result = get_app_gids(smack_label, &additional_gids, &cnt);
321 if (result != PC_OPERATION_SUCCESS)
325 glist_new = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + cnt));
326 if (glist_new == NULL) {
327 result = PC_ERR_MEM_OPERATION; // return -2
328 C_LOGE("Memory allocation failed");
332 for (i = 0; i < cnt; ++i) {
333 C_LOGD("Additional GID based on enabled permissions: %u", additional_gids[i]);
334 glist[glist_cnt++] = additional_gids[i];
342 C_LOGD("Adding process to the following groups:");
343 for(i=0; i<glist_cnt; ++i) {
344 C_LOGD("glist [ %d ] = %d", i, glist[i]);
346 C_LOGD("setgroups()");
347 if(setgroups(glist_cnt, glist) != 0)
349 C_LOGE("setgroups failed");
350 result = PC_ERR_NOT_PERMITTED; // return -3
360 * setuid() & setgid()
362 C_LOGD("setgid( %d ) & setuid( %d )", usr.gid, usr.uid);
363 if(setgid(usr.gid) != 0) // fail
365 C_LOGE("Failed to execute setgid().");
366 result = PC_ERR_INVALID_OPERATION;
369 if(setuid(usr.uid) != 0) // fail
371 C_LOGE("Failed to execute setuid().");
372 result = PC_ERR_INVALID_OPERATION;
376 SECURE_SLOGD("setenv(): USER = %s, HOME = %s", usr.user_name, usr.home_dir);
377 if(setenv("USER", usr.user_name, 1) != 0) //fail
379 C_LOGE("Failed to execute setenv() [USER].");
380 result = PC_ERR_INVALID_OPERATION;
383 if(setenv("HOME", usr.home_dir, 1) != 0) // fail
385 C_LOGE("Failed to execute setenv() [HOME].");
386 result = PC_ERR_INVALID_OPERATION;
390 else // current user is not only 'root' but 'app'
392 C_LOGE("Current user is NOT root");
393 result = PC_ERR_NOT_PERMITTED; // return -3
397 result = PC_OPERATION_SUCCESS;
404 free(additional_gids);
410 * Get SMACK label from EXEC label of a file.
411 * SMACK label should be freed by caller
413 * @param path file path to take label from
414 * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
416 static int get_smack_from_binary(char **smack_label, const char* path, app_type_t type)
418 C_LOGD("Enter function: %s", __func__);
421 C_LOGD("Path: %s", path);
424 if (type == APP_TYPE_WGT
425 || type == APP_TYPE_WGT_PARTNER
426 || type == APP_TYPE_WGT_PLATFORM) {
427 ret = smack_lgetlabel(path, smack_label, SMACK_LABEL_EXEC);
429 ret = smack_getlabel(path, smack_label, SMACK_LABEL_EXEC);
432 C_LOGE("Getting exec label from file %s failed", path);
433 return PC_ERR_INVALID_OPERATION;
436 return PC_OPERATION_SUCCESS;
440 * Set process SMACK label.
441 * This function is emulating EXEC label behavior of SMACK for programs
442 * run by dlopen/dlsym instead of execv.
445 * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
447 static int set_smack_for_self (char *smack_label)
449 C_LOGD("Enter function: %s", __func__);
452 if (smack_label == NULL) {
453 /* No label to set, just return with success */
454 C_LOGD("No label to set, just return with success");
455 ret = PC_OPERATION_SUCCESS;
458 C_LOGD("label = %s", smack_label);
460 ret = smack_set_label_for_self(smack_label);
461 C_LOGD("smack_set_label_for_self returned %d", ret);
463 ret = PC_OPERATION_SUCCESS;
469 static int is_widget(const char* path)
471 C_LOGD("Enter function: %s", __func__);
472 char buf[sizeof(WRT_CLIENT_PATH)];
475 ret = readlink(path, buf, sizeof(WRT_CLIENT_PATH));
477 C_LOGD("readlink(%s) returned error: %s. Assuming that app is not a widget", path, strerror(errno));
478 else if (ret == sizeof(WRT_CLIENT_PATH))
479 C_LOGD("%s is not a widget", path);
480 if (ret == -1 || ret == sizeof(WRT_CLIENT_PATH))
483 C_LOGD("buf = %s", buf);
485 ret = !strcmp(WRT_CLIENT_PATH, buf);
486 C_LOGD("%s is %s widget", path, ret ? "a" : "not a");
491 * Partially verify, that the type given for app is correct.
492 * This function will use some heuristics to check whether the app type is right.
493 * It is intended for security hardening to catch privilege setting for the
494 * app type not corresponding to the actual binary.
495 * Beware - when it detects an anomaly, the whole process will be terminated.
497 * @param type claimed application type
498 * @param path file path to executable
499 * @return return void on success, terminate the process on error
501 static app_type_t verify_app_type(const char* type, const char* path)
503 C_LOGD("Enter function: %s", __func__);
504 /* TODO: this should actually be treated as error, but until the old
505 * set_privilege API is removed, it must be ignored */
507 C_LOGD("PKG_TYPE_OTHER");
508 return APP_TYPE_OTHER; /* good */
511 if (is_widget(path)) {
512 if (!strcmp(type, "wgt")) {
513 C_LOGD("PKG_TYPE_WGT");
514 return APP_TYPE_WGT; /* good */
515 } else if (!strcmp(type, "wgt_partner")) {
516 C_LOGD("PKG_TYPE_WGT_PARTNER");
517 return APP_TYPE_WGT_PARTNER; /* good */
518 } else if (!strcmp(type, "wgt_platform")) {
519 C_LOGD("PKG_TYPE_WGT_PLATFORM");
520 return APP_TYPE_WGT_PLATFORM; /* good */
524 if (type == NULL || (strcmp(type, "wgt")
525 && strcmp(type, "wgt_partner")
526 && strcmp(type, "wgt_platform"))){
527 C_LOGD("PKG_TYPE_OTHER");
528 return APP_TYPE_OTHER; /* good */
533 C_LOGE("EXIT_FAILURE");
537 API int set_app_privilege(const char* name, const char* type, const char* path)//deprecated
539 return perm_app_set_privilege(name, type, path);
542 API int perm_app_set_privilege(const char* name, const char* type, const char* path)
544 C_LOGD("Enter function: %s", __func__);
545 SECURE_SLOGD("Function params: name = %s, type = %s, path = %s", name, type, path);
546 int ret = PC_OPERATION_SUCCESS;
547 int were_rules_loaded = 0;
548 char *smack_label AUTO_FREE;
551 C_LOGE("Error invalid parameter");
552 return PC_ERR_INVALID_PARAM;
555 if (path != NULL && have_smack()) {
556 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
557 if (ret != PC_OPERATION_SUCCESS)
560 were_rules_loaded = check_if_rules_were_loaded(smack_label);
561 if (were_rules_loaded < 0) {
562 C_LOGE("Error while check_if_rules_was_loaded");
563 return PC_ERR_INVALID_OPERATION;
565 if (!were_rules_loaded) { // first run of application
566 C_LOGD("This is first run of this application. Adding SMACK rules");
567 ret = add_app_first_run_rules(smack_label);
568 if (ret != PC_OPERATION_SUCCESS ) {
569 C_LOGW("Warning: add_app_first_run_rules failed");
570 // should we return here with error code?
572 mark_rules_as_loaded(smack_label);
575 ret = set_smack_for_self(smack_label);
576 if (ret != PC_OPERATION_SUCCESS)
580 if (path != NULL && !have_smack()) {
581 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
582 if (ret != PC_OPERATION_SUCCESS)
586 return set_dac(smack_label, name);
589 API int set_privilege(const char* pkg_name)//deprecated
591 C_LOGD("Enter function: %s", __func__);
592 return perm_app_set_privilege(pkg_name, NULL, NULL);
595 static inline const char* app_type_name(app_type_t app_type)
602 case APP_TYPE_WGT_PARTNER:
603 return "WRT_partner";
604 case APP_TYPE_WGT_PLATFORM:
605 return "WRT_platform";
606 case APP_TYPE_OSP_PARTNER:
607 return "OSP_partner";
608 case APP_TYPE_OSP_PLATFORM:
609 return "OSP_platform";
617 static inline const char* app_type_group_name(app_type_t app_type)
621 case APP_TYPE_WGT_PARTNER:
622 case APP_TYPE_WGT_PLATFORM:
625 case APP_TYPE_OSP_PARTNER:
626 case APP_TYPE_OSP_PLATFORM:
636 * This function changes permission URI to basename for file name.
637 * For e.g. from http://tizen.org/privilege/contact.read will be
638 * created basename : org.tizen.privilege.contact.read
641 static int base_name_from_perm(const char *perm, char **name) {
643 char *host_dot = NULL;
644 char *rest_slash = NULL;
647 ip = iri_parse(perm);
648 if (ip == NULL || ip->host == NULL) {
649 C_LOGE("Bad permission format : %s", perm);
651 return PC_ERR_INVALID_PARAM;
654 if (ip->path == NULL) {
660 host_dot = strrchr(ip->host, '.');
667 while ((rest_slash = strchr(ip->path, '/'))) {
671 ret = asprintf(name, "%s%s%s%s",
672 host_dot ? host_dot : "", host_dot ? "." : "",
673 ip->host ? ip->host : "", ip->path);
675 C_LOGE("asprintf failed");
677 return PC_ERR_MEM_OPERATION;
681 return PC_OPERATION_SUCCESS;
684 static int perm_file_path(char** path, app_type_t app_type, const char* perm, const char *suffix, bool is_early)
686 const char* app_type_prefix = NULL;
687 char* perm_basename = NULL;
690 if (perm == NULL || strlen(perm) == 0) {
691 C_LOGE("empty permission name");
692 return PC_ERR_INVALID_PARAM;
695 app_type_prefix = app_type_group_name(app_type);
697 ret = base_name_from_perm(perm, &perm_basename);
698 if (ret != PC_OPERATION_SUCCESS) {
699 C_LOGE("Couldn't get permission basename");
704 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s%s",
705 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
706 perm_basename, "_early", suffix);
709 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s",
710 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
711 perm_basename, suffix);
714 C_LOGE("asprintf failed");
715 return PC_ERR_MEM_OPERATION;
718 C_LOGD("Path : %s", *path);
720 return PC_OPERATION_SUCCESS;
723 static int perm_to_smack_from_file(struct smack_accesses* smack,
724 const char* app_label,
725 const char* app_label_template,
726 const char* rules_file_path)
728 C_LOGD("Enter function: %s", __func__);
730 char* format_string AUTO_FREE;
731 char smack_subject[SMACK_LABEL_LEN + 1];
732 char smack_object[SMACK_LABEL_LEN + 1];
733 char smack_accesses[10];
734 FILE* file AUTO_FCLOSE;
736 if (asprintf(&format_string,"%%%ds %%%ds %%%lus\n",
737 SMACK_LABEL_LEN, SMACK_LABEL_LEN, (unsigned long)sizeof(smack_accesses)) == -1) {
738 C_LOGE("asprintf failed");
739 return PC_ERR_MEM_OPERATION;
742 file = fopen(rules_file_path, "r");
743 C_LOGD("path = %s", rules_file_path);
745 C_LOGW("fopen failed [%s] %s", rules_file_path, strerror(errno));
746 return PC_OPERATION_SUCCESS;
749 while (fscanf(file, format_string, smack_subject, smack_object, smack_accesses) == 3) {
750 if (!strcmp(smack_subject, app_label_template))
751 strcpy(smack_subject, app_label);
753 if (!strcmp(smack_object, app_label_template))
754 strcpy(smack_object, app_label);
756 C_LOGD("smack_accesses_add_modify (subject: %s, object: %s, access: %s)", smack_subject, smack_object, smack_accesses);
757 if (smack_accesses_add_modify(smack, smack_subject, smack_object, smack_accesses, "") != 0) {
758 C_LOGE("smack_accesses_add_modify failed");
759 return PC_ERR_INVALID_OPERATION;
763 return PC_OPERATION_SUCCESS;
766 static int perm_to_smack_generic(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm, bool is_early)
768 C_LOGD("Enter function: %s", __func__);
771 char* path AUTO_FREE;
773 // get file name for permission (devcap)
774 ret = perm_file_path(&path, app_type, perm, ".smack", is_early);
775 if (ret != PC_OPERATION_SUCCESS) {
776 C_LOGD("No smack config file for permission %s", perm);
780 ret = perm_to_smack_from_file(smack, app_label, SMACK_APP_LABEL_TEMPLATE, path);
781 if (ret != PC_OPERATION_SUCCESS) {
785 return PC_OPERATION_SUCCESS;
788 static int perm_to_smack_early(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
790 C_LOGD("Enter function: %s", __func__);
792 return perm_to_smack_generic(smack, app_label, app_type, perm, 1);
795 static int perm_to_smack(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
797 C_LOGD("Enter function: %s", __func__);
799 return perm_to_smack_generic(smack, app_label, app_type, perm, 0);
802 static int perm_to_dac(const char* app_label, app_type_t app_type, const char* perm)
804 C_LOGD("Enter function: %s", __func__);
806 char* path AUTO_FREE;
807 FILE* file AUTO_FCLOSE;
810 ret = perm_file_path(&path, app_type, perm, ".dac", 0);
811 if (ret != PC_OPERATION_SUCCESS) {
812 C_LOGD("No dac config file for permission %s", perm);
816 file = fopen(path, "r");
817 C_LOGD("path = %s", path);
819 C_LOGW("fopen failed");
820 return PC_OPERATION_SUCCESS;
823 while (fscanf(file, "%d\n", &gid) == 1) {
824 SECURE_SLOGD("Adding app_id %s to group %d", app_label, gid);
825 ret = add_app_gid(app_label, gid);
826 if (ret != PC_OPERATION_SUCCESS) {
827 C_LOGE("sadd_app_gid failed");
832 return PC_OPERATION_SUCCESS;
835 static int label_all(const FTSENT* ftsent)
837 return DECISION_LABEL;
840 static int label_execs(const FTSENT* ftsent)
842 C_LOGD("Mode: %d", ftsent->fts_statp->st_mode);
843 // label only regular executable files
844 if (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR))
845 return DECISION_LABEL;
846 return DECISION_SKIP;
849 static int label_dirs(const FTSENT* ftsent)
851 // label only directories
852 if (S_ISDIR(ftsent->fts_statp->st_mode))
853 return DECISION_LABEL;
854 return DECISION_SKIP;
857 static int label_links_to_execs(const FTSENT* ftsent)
860 char* target AUTO_FREE;
862 // check if it's a link
863 if ( !S_ISLNK(ftsent->fts_statp->st_mode))
864 return DECISION_SKIP;
866 target = realpath(ftsent->fts_path, NULL);
868 C_LOGE("Getting link target for %s failed. Error %s", ftsent->fts_path, strerror(errno));
869 return PC_ERR_FILE_OPERATION;
871 if (-1 == stat(target, &buf)) {
872 C_LOGE("stat failed for %s, error: %s",target, strerror(errno));
873 return PC_ERR_FILE_OPERATION;
875 // skip if link target is not a regular executable file
876 if (buf.st_mode != (buf.st_mode | S_IXUSR | S_IFREG)) {
877 C_LOGD("%s is not a regular executable file. Skipping.", target);
878 return DECISION_SKIP;
881 return DECISION_LABEL;
884 static int dir_set_smack_r(const char *path, const char* label,
885 enum smack_label_type type, label_decision_fn fn)
887 C_LOGD("Enter function: %s", __func__);
888 const char* path_argv[] = {path, NULL};
889 FTS *fts AUTO_FTS_CLOSE;
893 fts = fts_open((char * const *) path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
895 C_LOGE("fts_open failed");
896 return PC_ERR_FILE_OPERATION;
899 while ((ftsent = fts_read(fts)) != NULL) {
900 /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
901 if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
902 C_LOGE("FTS_ERR error or failed stat(2) (FTS_NS)");
903 return PC_ERR_FILE_OPERATION;
911 if (ret == DECISION_LABEL) {
912 C_LOGD("smack_lsetlabel (label: %s (type: %d), path: %s)", label, type, ftsent->fts_path);
913 if (smack_lsetlabel(ftsent->fts_path, label, type) != 0) {
914 C_LOGE("smack_lsetlabel failed");
915 return PC_ERR_FILE_OPERATION;
920 /* If last call to fts_read() set errno, we need to return error. */
922 C_LOGE("Last errno: %s", strerror(errno));
923 return PC_ERR_FILE_OPERATION;
925 return PC_OPERATION_SUCCESS;
928 API char* app_id_from_socket(int sockfd)//deprecated
930 return perm_app_id_from_socket(sockfd);
933 API char* perm_app_id_from_socket(int sockfd)
935 C_LOGD("Enter function: %s", __func__);
942 ret = smack_new_label_from_socket(sockfd, &app_id);
944 C_LOGE("smack_new_label_from_socket failed");
948 SECURE_SLOGD("app_id: %s", app_id);
953 static int app_add_rule(const char *app_id, const char *object, const char *perm)
955 C_LOGD("Enter function: %s", __func__);
958 char *smack_path AUTO_FREE;
959 struct smack_accesses* smack AUTO_SMACK_FREE;
961 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
962 if (ret != PC_OPERATION_SUCCESS) {
963 C_LOGE("load_smack_from_file failed");
967 ret = smack_accesses_add_modify(smack, app_id, object, perm, "");
969 C_LOGE("smack_accesses_add_modify failed");
970 return PC_ERR_INVALID_OPERATION;
973 if (have_smack() && smack_accesses_apply(smack)) {
974 C_LOGE("smack_accesses_apply failed");
975 return PC_ERR_INVALID_OPERATION;
978 if (smack_accesses_save(smack, fd)) {
979 C_LOGE("smack_accesses_save failed");
980 return PC_ERR_INVALID_OPERATION;
983 return PC_OPERATION_SUCCESS;
988 app_register_appsetting(const char *app_id, struct smack_accesses *smack)
990 C_LOGD("Enter function: %s", __func__);
994 char **label_app_list AUTO_FREE;
995 char **label_dir_list AUTO_FREE;
996 int app_list_len = 0;
997 int dir_list_len = 0;
999 if (!smack_label_is_valid(app_id))
1000 return PC_ERR_INVALID_PARAM;
1003 /* writing appsetting_id (app_id) to "database"*/
1004 ret = add_appsetting_id_to_databse(app_id);
1005 if (ret != PC_OPERATION_SUCCESS)
1009 /* Reading labels of all installed apps from "database"*/
1010 ret = get_all_apps_ids(&label_app_list, &app_list_len);
1011 if (ret != PC_OPERATION_SUCCESS) {
1012 C_LOGE("Error while getting data from database");
1016 /*Add smack rules with rx access to each app*/
1017 for (i = 0; i < app_list_len; ++i) {
1018 C_LOGD("Appsetting: applying rx rule for %s", label_app_list[i]);
1019 if (smack_accesses_add_modify(smack, app_id,
1020 label_app_list[i], "rx", "") == -1) {
1021 C_LOGE("smack_accesses_add_modify failed");
1022 ret = PC_ERR_INVALID_OPERATION;
1027 /* Reading labels of all registered settings dirs from "database"*/
1028 ret = get_all_settings_dir_ids(
1029 &label_dir_list, &dir_list_len);
1030 if (ret != PC_OPERATION_SUCCESS) {
1031 C_LOGE("Error while getting data from database");
1034 /*Add smack rules with rwx access to each app*/
1035 for (i = 0; i < dir_list_len; ++i) {
1036 C_LOGD("Appsetting: applying rwx rule for %s", label_dir_list[i]);
1037 if (smack_accesses_add_modify(smack, app_id,
1038 label_dir_list[i], "rwx", "") == -1) {
1039 C_LOGE("smack_accesses_add_modify failed");
1040 ret = PC_ERR_INVALID_OPERATION;
1042 /* Should we abort adding rules if
1043 * smack_accesses_add_modify fails once?*/
1048 for (i = 0; i < app_list_len; ++i) {
1049 free(label_app_list[i]);
1051 for (i = 0; i < dir_list_len; ++i) {
1052 free(label_dir_list[i]);
1058 static int app_register_av_internal(const char *app_av_id, struct smack_accesses* smack)
1060 C_LOGD("Enter function: %s", __func__);
1064 char** smack_label_app_list AUTO_FREE;
1065 int smack_label_app_list_len = 0;
1067 if (!smack_label_is_valid(app_av_id) || NULL == smack)
1068 return PC_ERR_INVALID_PARAM;
1070 // writing anti_virus_id (app_av_id) to "database"
1071 ret = add_av_id_to_databse(app_av_id);
1072 if (ret != PC_OPERATION_SUCCESS )
1075 // Reading labels of all installed apps from "database"
1076 ret = get_all_apps_ids(&smack_label_app_list, &smack_label_app_list_len);
1077 if (ret != PC_OPERATION_SUCCESS ) {
1078 C_LOGE("Error while geting data from database");
1081 for (i = 0; i < smack_label_app_list_len; ++i) {
1082 C_LOGD("Applying rwx rule for %s", smack_label_app_list[i]);
1083 if (smack_accesses_add_modify(smack, app_av_id, smack_label_app_list[i], "wrx", "") == -1) {
1084 C_LOGE("smack_accesses_add_modify failed");
1085 ret = PC_ERR_INVALID_OPERATION;
1087 // Should we abort adding rules once smack_accesses_add_modify will fail?
1092 for (i = 0; i < smack_label_app_list_len; ++i) {
1093 free(smack_label_app_list[i]);
1100 * This function will find labels of all anti viruses in database
1101 * and for all of them will add a rule "anti_virus_label app_id rwx".
1102 * This should be called in app_install function.
1104 static int register_app_for_av(const char * app_id)
1107 char** smack_label_av_list AUTO_FREE;
1108 int smack_label_av_list_len = 0;
1110 // Reading labels of all installed anti viruses from "database"
1111 ret = get_all_avs_ids(&smack_label_av_list, &smack_label_av_list_len);
1112 if (ret != PC_OPERATION_SUCCESS) {
1113 C_LOGE("Error while geting data from database");
1117 // for each anti-virus label put rule: "anti_virus_label app_id rwx"
1118 for (i = 0; i < smack_label_av_list_len; ++i) {
1119 SECURE_SLOGD("Antivirus: app_add_rule (%s, %s rx)", smack_label_av_list[i], app_id);
1120 if (strcmp(app_id, smack_label_av_list[i])==0) {
1121 SECURE_SLOGW("Trying to add antivirus rule for self. Skipping");
1124 ret = app_add_rule(smack_label_av_list[i], app_id, "wrx");
1125 if (ret != PC_OPERATION_SUCCESS) {
1126 C_LOGE("app_add_rule failed");
1130 free(smack_label_av_list[i]);
1133 ret = PC_OPERATION_SUCCESS;
1136 // If something failed, then no entry of smack_label_av_list[i]
1137 // was deallocated. They all must be freed.
1138 for(; i<smack_label_av_list_len; ++i) {
1139 free(smack_label_av_list[i]);
1146 * This function will find labels of all setting applications in database
1147 * and for all of them will add a rule "appsetting_id app_id rwx".
1148 * This should be called in app_install function.
1150 static int register_app_for_appsetting(const char *app_id)
1152 C_LOGD("Enter function: %s",__func__);
1154 char **smack_label_list AUTO_FREE;
1155 int smack_label_list_len = 0;
1157 /* Reading labels of all installed setting managers from "database"*/
1158 ret = get_all_appsetting_ids(&smack_label_list, &smack_label_list_len);
1159 if (ret != PC_OPERATION_SUCCESS) {
1160 C_LOGE("Error while geting data from database");
1164 /* for each appsetting put rule: "appsetting_id app_id rx"*/
1165 for (i = 0; i < smack_label_list_len; ++i) {
1167 SECURE_SLOGD("Appsetting: app_add_rule (%s, %s rx)", smack_label_list[i], app_id);
1168 if (strcmp(app_id, smack_label_list[i])==0) {
1169 SECURE_SLOGW("Trying to add setting rule for self. Skipping");
1172 ret = app_add_rule(smack_label_list[i], app_id, "rx");
1173 if (ret != PC_OPERATION_SUCCESS) {
1174 C_LOGE("app_add_rule failed");
1178 free(smack_label_list[i]);
1181 ret = PC_OPERATION_SUCCESS;
1184 /* If something failed, then no entry of smack_label_list[i]
1185 was deallocated. They all must be freed.*/
1186 for (; i < smack_label_list_len; ++i) {
1187 free(smack_label_list[i]);
1195 * This function will grant app_id rx access to all public directories and
1196 * files previously designated by app_setup_path(APP_PATH_PUBLIC_RO)
1197 * This should be called in app_install function.
1199 static int register_app_for_public_dirs(const char *app_id, struct smack_accesses *smack)
1201 C_LOGD("Enter function: %s", __func__);
1203 char **public_dirs AUTO_FREE;
1204 int public_dirs_cnt = 0;
1206 ret = db_get_public_dirs(&public_dirs, &public_dirs_cnt);
1207 if (ret != PC_OPERATION_SUCCESS) {
1208 C_LOGE("Error while getting data from database");
1212 for (i = 0; i < public_dirs_cnt; ++i) {
1213 SECURE_SLOGD("Allowing app %s to access public path %s", app_id, public_dirs[i]);
1214 if (smack_accesses_add_modify(smack, app_id, public_dirs[i], "rx", "")) {
1215 C_LOGE("app_add_rule_modify failed");
1216 while (i < public_dirs_cnt)
1217 free(public_dirs[i++]);
1218 return PC_ERR_INVALID_OPERATION;
1220 free(public_dirs[i]);
1223 return PC_OPERATION_SUCCESS;
1226 static int app_add_permissions_internal(const char* app_id, app_type_t app_type, const char** perm_list, int permanent)
1228 C_LOGD("Enter function: %s", __func__);
1230 char* smack_path AUTO_FREE;
1231 char* smack_path_early AUTO_FREE;
1233 int fd_early AUTO_CLOSE;
1234 struct smack_accesses *smack AUTO_SMACK_FREE;
1235 struct smack_accesses *smack_early AUTO_SMACK_FREE;
1236 const char* base_perm = NULL;
1238 if (!smack_label_is_valid(app_id))
1239 return PC_ERR_INVALID_PARAM;
1241 if(perm_list == NULL) {
1242 C_LOGE("Invalid perm_list (NULL).");
1243 return PC_ERR_INVALID_PARAM;
1246 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1247 if (ret != PC_OPERATION_SUCCESS) {
1248 C_LOGE("load_smack_from_file failed");
1252 ret = load_smack_from_file_early(app_id, &smack_early, &fd_early, &smack_path_early);
1253 if (ret != PC_OPERATION_SUCCESS) {
1254 C_LOGE("load_smack_from_file failed");
1258 /* Implicitly enable base permission for an app_type */
1259 base_perm = app_type_name(app_type);
1261 SECURE_SLOGD("perm_to_smack params: app_id: %s, %s", app_id, base_perm);
1262 ret = perm_to_smack(smack, app_id, APP_TYPE_OTHER, base_perm);
1263 if (ret != PC_OPERATION_SUCCESS){
1264 C_LOGE("perm_to_smack failed");
1268 // Add early permission - such permissions should be enabled right after system boot
1269 SECURE_SLOGD("perm_to_smack params: app_id: %s, %s", app_id, base_perm);
1270 ret = perm_to_smack_early(smack_early, app_id, APP_TYPE_OTHER, base_perm);
1271 if (ret != PC_OPERATION_SUCCESS){
1272 C_LOGE("perm_to_smack failed");
1277 for (i = 0; perm_list[i] != NULL; ++i) {
1278 SECURE_SLOGD("perm_to_smack params: app_id: %s, perm_list[%d]: %s", app_id, i, perm_list[i]);
1279 if (strcmp(perm_list[i], TIZEN_PRIVILEGE_ANTIVIRUS) == 0) {
1280 ret = app_register_av_internal(app_id, smack);
1281 if (ret != PC_OPERATION_SUCCESS) {
1282 C_LOGE("app_register_av_internal failed");
1286 if (strcmp(perm_list[i], TIZEN_PRIVILEGE_APPSETTING) == 0) {
1287 ret = app_register_appsetting(app_id, smack);
1288 if (ret != PC_OPERATION_SUCCESS) {
1289 C_LOGE("app_register_appsetting failed");
1294 ret = perm_to_smack(smack, app_id, app_type, perm_list[i]);
1295 if (ret != PC_OPERATION_SUCCESS){
1296 C_LOGE("perm_to_smack failed");
1300 ret = perm_to_smack_early(smack_early, app_id, app_type, perm_list[i]);
1301 if (ret != PC_OPERATION_SUCCESS){
1302 C_LOGE("perm_to_smack_early failed");
1306 ret = perm_to_dac(app_id, app_type, perm_list[i]);
1307 if (ret != PC_OPERATION_SUCCESS){
1308 C_LOGE("perm_to_dac failed");
1313 if (have_smack() && smack_accesses_apply(smack)) {
1314 C_LOGE("smack_accesses_apply failed");
1315 return PC_ERR_INVALID_OPERATION;
1318 if (have_smack() && smack_accesses_apply(smack_early)) {
1319 C_LOGE("smack_accesses_apply (early) failed");
1320 return PC_ERR_INVALID_OPERATION;
1323 if (permanent && smack_accesses_save(smack, fd)) {
1324 C_LOGE("smack_accesses_save failed");
1325 return PC_ERR_INVALID_OPERATION;
1328 if (permanent && smack_accesses_save(smack_early, fd_early)) {
1329 C_LOGE("smack_accesses_save (early) failed");
1330 return PC_ERR_INVALID_OPERATION;
1333 return PC_OPERATION_SUCCESS;
1336 API int app_add_permissions(const char* app_id, const char** perm_list)//deprecated
1338 C_LOGD("Enter function: %s", __func__);
1339 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 1);
1342 API int app_add_volatile_permissions(const char* app_id, const char** perm_list)//deprecated
1344 C_LOGD("Enter function: %s", __func__);
1345 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 0);
1348 API int app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)//deprecated
1350 C_LOGD("Enter function: %s", __func__);
1351 return app_add_permissions_internal(pkg_id, app_type, perm_list, persistent);
1354 API int perm_app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)
1356 C_LOGD("Enter function: %s", __func__);
1357 return app_add_permissions_internal(pkg_id, app_type, perm_list, persistent);
1360 API int app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)//deprecated
1362 return perm_app_disable_permissions(pkg_id, app_type, perm_list);
1365 /* FIXME: this function is only a stub */
1366 API int perm_app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)
1368 C_LOGD("Enter function: %s", __func__);
1369 return PC_OPERATION_SUCCESS;
1372 static int app_revoke_permissions_internal(const char* app_id, bool persistent)
1374 C_LOGD("Enter function: %s", __func__);
1375 char* smack_path AUTO_FREE;
1378 struct smack_accesses *smack AUTO_SMACK_FREE;
1380 if (!smack_label_is_valid(app_id))
1381 return PC_ERR_INVALID_PARAM;
1383 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1384 if (ret != PC_OPERATION_SUCCESS) {
1385 C_LOGE("load_smack_from_file failed");
1389 if (have_smack() && smack_accesses_clear(smack)) {
1390 ret = PC_ERR_INVALID_OPERATION;
1391 C_LOGE("smack_accesses_clear failed");
1395 if (have_smack() && smack_revoke_subject(app_id)) {
1396 ret = PC_ERR_INVALID_OPERATION;
1397 C_LOGE("smack_revoke_subject failed");
1401 if (persistent && ftruncate(fd, 0) == -1)
1402 C_LOGW("file truncation failed");
1404 return PC_OPERATION_SUCCESS;
1407 API int app_revoke_permissions(const char* pkg_id)//deprecated
1409 return perm_app_revoke_permissions(pkg_id);
1412 API int perm_app_revoke_permissions(const char* pkg_id)
1414 C_LOGD("Enter function: %s", __func__);
1417 if (!smack_label_is_valid(pkg_id))
1418 return PC_ERR_INVALID_PARAM;
1420 ret = app_revoke_permissions_internal(pkg_id, true);
1422 C_LOGE("Revoking permissions failed");
1426 return PC_OPERATION_SUCCESS;
1429 API int app_reset_permissions(const char* pkg_id)//deprecated
1431 return perm_app_reset_permissions(pkg_id);
1434 API int perm_app_reset_permissions(const char* pkg_id)
1436 C_LOGD("Enter function: %s", __func__);
1439 if (!smack_label_is_valid(pkg_id))
1440 return PC_ERR_INVALID_PARAM;
1442 ret = app_revoke_permissions_internal(pkg_id, false);
1444 C_LOGE("Revoking permissions failed");
1448 /* Add empty permissions set to trigger re-read of rules */
1449 return perm_app_enable_permissions(pkg_id, APP_TYPE_OTHER, (const char*[]){NULL}, 0);
1452 API int app_label_dir(const char* label, const char* path)//deprecated
1454 C_LOGD("Enter function: %s", __func__);
1456 int ret = PC_OPERATION_SUCCESS;
1459 C_LOGE("Invalid argument path (NULL).");
1460 return PC_ERR_INVALID_PARAM;
1463 if (!smack_label_is_valid(label))
1464 return PC_ERR_INVALID_PARAM;
1466 //setting access label on everything in given directory and below
1467 ret = dir_set_smack_r(path, label, SMACK_LABEL_ACCESS, &label_all);
1468 if (PC_OPERATION_SUCCESS != ret)
1471 //setting execute label for everything with permission to execute
1472 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_execs);
1473 if (PC_OPERATION_SUCCESS != ret)
1476 //setting execute label for everything with permission to execute
1477 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_links_to_execs);
1481 int smack_get_access_new(const char* subject, const char* object, char** label)
1483 char buff[ACC_LEN] = {'r', 'w', 'x', 'a', 't'};
1484 char perm[2] = {'-'};
1487 if(!smack_label_is_valid(subject) || !smack_label_is_valid(object) || !label)
1488 return PC_ERR_INVALID_PARAM;
1490 for (i=0; i<ACC_LEN; ++i) {
1492 int ret = smack_have_access(subject, object, perm);
1494 return PC_ERR_INVALID_OPERATION;
1499 *label = malloc(ACC_LEN+1);
1501 return PC_ERR_MEM_OPERATION;
1503 memcpy(*label, buff, ACC_LEN);
1504 (*label)[ACC_LEN] = 0;
1505 return PC_OPERATION_SUCCESS;
1508 static int app_uninstall_remove_early_rules(const char *app_id)
1510 C_LOGD("Enter function: %s", __func__);
1512 int ret = PC_OPERATION_SUCCESS;
1513 FILE *file AUTO_FCLOSE;
1514 FILE *file_new AUTO_FCLOSE;
1515 char *tmp_filename AUTO_FREE;
1516 char *single_line_format AUTO_FREE;
1517 char subject[SMACK_LABEL_LEN + 1];
1518 char object[SMACK_LABEL_LEN + 1];
1519 char rule_add[6]; // "rwxat" + '\0'
1520 char rule_remove[6]; // "rwxat" + '\0'
1523 subject[SMACK_LABEL_LEN] = '\0';
1524 object[SMACK_LABEL_LEN] = '\0';
1526 rule_remove[5] = '\0';
1528 // Creating (opening) and waiting for semaphore
1529 sem = sem_open(PRIVILEGE_CONTROL_UNINSTALL_SEM, O_CREAT, S_IRWXU | S_IRWXU | S_IRWXO, 1);
1530 if (sem == SEM_FAILED) {
1531 C_LOGE("sem_open failed, error: %s", strerror(errno));
1532 ret = PC_ERR_INVALID_OPERATION;
1535 C_LOGD("Waiting for semaphore");
1536 ret = sem_wait(sem);
1538 C_LOGE("sem_wait failed, error: %s", strerror(errno));
1539 ret = PC_ERR_INVALID_OPERATION;
1543 ret = asprintf(&single_line_format, "%%%ds %%%ds %%5s %%5s\\n", SMACK_LABEL_LEN, SMACK_LABEL_LEN);
1545 C_LOGE("asprintf failed");
1546 ret = PC_ERR_MEM_OPERATION;
1550 ret = asprintf(&tmp_filename, "%s.tmp", SMACK_STARTUP_RULES_FILE);
1552 C_LOGE("asprintf failed");
1553 ret = PC_ERR_MEM_OPERATION;
1557 file = fopen(SMACK_STARTUP_RULES_FILE, "r");
1559 C_LOGE("fopen failed on %s", SMACK_STARTUP_RULES_FILE);
1560 ret = PC_ERR_FILE_OPERATION;
1564 file_new = fopen(tmp_filename, "w");
1566 C_LOGE("fopen failed on %s", tmp_filename);
1567 ret = PC_ERR_FILE_OPERATION;
1571 while (fscanf(file, single_line_format, subject, object, rule_add, rule_remove) == 4) {
1572 C_LOGD("Checking line \"%s %s %s %s\"", subject, object, rule_add, rule_remove);
1574 if ((strncmp(subject, app_id, SMACK_LABEL_LEN) == 0) || (strncmp(object, app_id, SMACK_LABEL_LEN) == 0)) {
1575 C_LOGD("app_id found - rule will be ignored");
1576 continue; // do not re-write this rule for new file
1579 if (0 > fprintf(file_new, "%s %s %s %s\n", subject, object, rule_add, rule_remove)) { // re-writing rule to new file
1580 C_LOGE("Write rule \"%s %s %s %s\" to file failed. %s", subject, object, rule_add, rule_remove, strerror(errno));
1581 // Should we return with error here?
1582 ret = PC_ERR_FILE_OPERATION;
1592 if (unlink(SMACK_STARTUP_RULES_FILE)) {
1593 C_LOGE("unlink failed %s", strerror(errno));
1594 ret = PC_ERR_FILE_OPERATION;
1598 if (rename(tmp_filename, SMACK_STARTUP_RULES_FILE)) {
1599 C_LOGE("rename failed. %s", strerror(errno));
1600 ret = PC_ERR_FILE_OPERATION;
1604 if (chmod(SMACK_STARTUP_RULES_FILE, 644)) {
1605 C_LOGE("chmod failed on %s file. Error: %s", tmp_filename, strerror(errno));
1606 ret = PC_ERR_FILE_OPERATION;
1610 ret = PC_OPERATION_SUCCESS;
1616 // Should we check unlink?
1617 sem_unlink(PRIVILEGE_CONTROL_UNINSTALL_SEM);
1621 API int app_label_shared_dir(const char* app_label, const char* shared_label, const char* path)//deprecated
1623 C_LOGD("Enter function: %s", __func__);
1628 C_LOGE("Invalid param path.");
1629 return PC_ERR_INVALID_PARAM;
1632 if (!smack_label_is_valid(app_label) || !smack_label_is_valid(shared_label))
1633 return PC_ERR_INVALID_PARAM;
1635 if (strcmp(app_label, shared_label) == 0) {
1636 C_LOGE("app_label equals shared_label");
1637 return PC_ERR_INVALID_PARAM;
1640 //setting label on everything in given directory and below
1641 ret = dir_set_smack_r(path, shared_label, SMACK_LABEL_ACCESS, label_all);
1642 if(ret != PC_OPERATION_SUCCESS){
1643 C_LOGE("dir_set_smack_r failed");
1647 //setting transmute on dir
1648 ret = dir_set_smack_r(path, "1", SMACK_LABEL_TRANSMUTE, label_dirs);
1649 if (ret != PC_OPERATION_SUCCESS) {
1650 C_LOGE("dir_set_smack_r failed");
1654 ret = app_add_rule(app_label, shared_label, "rwxat");
1655 if (ret != PC_OPERATION_SUCCESS) {
1656 C_LOGE("app_add_rule failed");
1660 return PC_OPERATION_SUCCESS;
1663 API int add_shared_dir_readers(const char* shared_label, const char** app_list)//deprecated
1665 C_LOGD("Enter function: %s", __func__);
1669 if(app_list == NULL) {
1670 C_LOGE("Invalid param app_list.");
1671 return PC_ERR_INVALID_PARAM;
1674 if (!smack_label_is_valid(shared_label))
1675 return PC_ERR_INVALID_PARAM;
1677 for (i = 0; app_list[i] != NULL; i++) {
1679 if (!smack_label_is_valid(app_list[i]))
1680 return PC_ERR_INVALID_PARAM;
1682 ret = app_add_rule(app_list[i], shared_label, "rx");
1683 if (ret != PC_OPERATION_SUCCESS) {
1684 C_LOGE("app_add_rule failed");
1689 return PC_OPERATION_SUCCESS;
1692 static char* smack_label_for_path(const char *app_id, const char *path)
1694 C_LOGD("Enter function: %s", __func__);
1695 char *salt AUTO_FREE;
1699 /* Prefix $1$ causes crypt() to use MD5 function */
1700 if (-1 == asprintf(&salt, "$1$%s", app_id)) {
1701 C_LOGE("asprintf failed");
1705 label = crypt(path, salt);
1706 if (label == NULL) {
1707 C_LOGE("crypt failed");
1711 /* crypt() output may contain slash character,
1712 * which is not legal in Smack labels */
1713 for (x = label; *x; ++x) {
1721 * This function should be called in perm_app_setup_path_internal().
1722 * After installation of new application (pkg_id) and labeling its shared directory (RW or RO),
1723 * all others apps installed in system should get rules to this shared directory.
1724 * This function will add and store those rules in rule-file of new installed app (pkg_id)
1726 static int add_other_apps_rules_for_shared_dir(const char *pkg_id, const char *type_of_shared_dir, const char *shared_dir_label)
1728 C_LOGD("Enter function: %s", __func__);
1732 char *smack_path AUTO_FREE;
1733 char *smack_rules_file_path AUTO_FREE;
1734 struct smack_accesses* smack AUTO_SMACK_FREE;
1736 ret = load_smack_from_file(pkg_id, &smack, &fd, &smack_path);
1737 if (ret != PC_OPERATION_SUCCESS ) {
1738 C_LOGE("load_smack_from_file failed: %d", ret);
1742 ret = asprintf(&smack_rules_file_path, TOSTRING(SHAREDIR)"/%s", type_of_shared_dir);
1744 C_LOGE("asprintf failed");
1745 return PC_ERR_MEM_OPERATION;
1748 ret = perm_to_smack_from_file(smack, shared_dir_label, SMACK_SHARED_DIR_LABEL_TEMPLATE, smack_rules_file_path);
1749 if (ret != PC_OPERATION_SUCCESS ) {
1750 C_LOGE("perm_to_smack_from_file failed: %d", ret);
1753 if (have_smack() && smack_accesses_apply(smack)) {
1754 C_LOGE("smack_accesses_apply failed");
1755 return PC_ERR_INVALID_OPERATION;
1758 if (smack_accesses_save(smack, fd)) {
1759 C_LOGE("smack_accesses_save failed");
1760 return PC_ERR_INVALID_OPERATION;
1763 return PC_OPERATION_SUCCESS;
1766 /* FIXME: remove this pragma once deprecated API is deleted */
1767 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1768 static int perm_app_setup_path_internal(const char* pkg_id, const char* path, app_path_type_t app_path_type, va_list ap)
1770 C_LOGD("Enter function: %s", __func__);
1773 C_LOGE("Invalid argument path.");
1774 return PC_ERR_INVALID_PARAM;
1777 if (!smack_label_is_valid(pkg_id)) {
1778 SECURE_SLOGE("Invalid app_id %s", pkg_id);
1779 return PC_ERR_INVALID_PARAM;
1782 switch (app_path_type) {
1783 case APP_PATH_PRIVATE:
1784 return app_label_dir(pkg_id, path);
1786 case APP_PATH_GROUP_RW: {
1787 const char *shared_label;
1790 shared_label = va_arg(ap, const char *);
1792 if (!smack_label_is_valid(shared_label)) {
1793 C_LOGE("Invalid shared_label %s", shared_label);
1794 return PC_ERR_INVALID_PARAM;
1797 if (strcmp(pkg_id, shared_label) == 0) {
1798 C_LOGE("app_id equals shared_label");
1799 return PC_ERR_INVALID_PARAM;
1802 ret = app_label_shared_dir(pkg_id, shared_label, path);
1803 if (ret != PC_OPERATION_SUCCESS) {
1804 C_LOGE("app_label_shared_dir failed: %d", ret);
1808 return add_other_apps_rules_for_shared_dir(pkg_id, PATH_RULES_GROUP_RW, shared_label);
1811 case APP_PATH_PUBLIC_RO: {
1812 char **app_ids AUTO_FREE;
1813 int app_ids_cnt = 0;
1817 C_LOGD("New public RO path %s", path);
1818 label = smack_label_for_path(pkg_id, path);
1820 return PC_ERR_INVALID_OPERATION;
1822 C_LOGD("Generated label '%s' for public RO path %s", label, path);
1823 ret = app_label_shared_dir(pkg_id, label, path);
1824 if (ret != PC_OPERATION_SUCCESS)
1827 /* FIXME: This should be in some kind of transaction/lock */
1828 ret = db_add_public_dir(label);
1829 if (ret != PC_OPERATION_SUCCESS)
1832 ret = get_all_apps_ids(&app_ids, &app_ids_cnt);
1833 if (ret != PC_OPERATION_SUCCESS)
1836 for (i = 0; i < app_ids_cnt; ++i) {
1837 SECURE_SLOGD("Allowing app %s to access public path %s", app_ids[i], path);
1838 ret = app_add_rule(app_ids[i], label, "rx");
1839 if (ret != PC_OPERATION_SUCCESS) {
1840 C_LOGE("smack_accesses_new failed");
1841 while (i < app_ids_cnt)
1848 return add_other_apps_rules_for_shared_dir(pkg_id, PATH_RULES_PUBLIC_RO, label);
1851 case APP_PATH_SETTINGS_RW:
1853 char **app_ids AUTO_FREE;
1854 int app_ids_cnt = 0;
1860 label = smack_label_for_path(pkg_id, path);
1862 return PC_ERR_INVALID_OPERATION;
1864 /*set id for path and all subfolders*/
1865 C_LOGD("Appsetting: generated label '%s' for setting path %s", label, path);
1866 ret = app_label_shared_dir(pkg_id, label, path);
1867 if (ret != PC_OPERATION_SUCCESS) {
1868 C_LOGE("Appsetting: app_label_shared_dir failed (%d)", ret);
1872 /* add path to database */
1873 /* FIXME: This should be in some kind of transaction/lock */
1874 ret = add_setting_dir_id_to_databse(label);
1875 if (ret != PC_OPERATION_SUCCESS) {
1876 C_LOGE("Appsetting: add_setting_dir_id_to_databse failed");
1880 /*read all apps with appsetting privilege*/
1881 ret = get_all_appsetting_ids(&app_ids, &app_ids_cnt);
1882 if (ret != PC_OPERATION_SUCCESS) {
1883 C_LOGE("Appsetting: get_all_appsetting_ids failed");
1886 C_LOGD("Appsetting: %d appsetting privileged apps registered",
1889 /*give RWX rights to all apps that have appsetting privilege*/
1890 for (i = 0; i < app_ids_cnt; ++i) {
1891 C_LOGD("Appsetting: allowing app %s to access setting path %s",
1893 ret = app_add_rule(app_ids[i], label, "rwx");
1894 if (ret != PC_OPERATION_SUCCESS) {
1895 C_LOGE("app_add_rule failed");
1896 while (i < app_ids_cnt)
1903 return PC_OPERATION_SUCCESS;
1906 case APP_PATH_ANY_LABEL: {
1907 const char *label = NULL;
1908 label = va_arg(ap, const char *);
1909 return app_label_dir(label, path);
1913 return PC_ERR_INVALID_PARAM;
1916 return PC_OPERATION_SUCCESS;
1918 /* FIXME: remove this pragma once deprecated API is deleted */
1919 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
1921 API int app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)//deprecated
1925 va_start( ap, app_path_type );
1926 ret = perm_app_setup_path_internal( pkg_id, path, app_path_type, ap );
1932 API int perm_app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)
1936 va_start( ap, app_path_type );
1937 ret = perm_app_setup_path_internal( pkg_id, path, app_path_type, ap );
1944 API int app_add_friend(const char* pkg_id1, const char* pkg_id2)//deprecated
1946 return perm_app_add_friend(pkg_id1, pkg_id2);
1949 API int perm_app_add_friend(const char* pkg_id1, const char* pkg_id2)
1951 C_LOGD("Enter function: %s", __func__);
1954 if (!smack_label_is_valid(pkg_id1) || !smack_label_is_valid(pkg_id2))
1955 return PC_ERR_INVALID_PARAM;
1957 ret = app_add_rule(pkg_id1, pkg_id2, "rwxat");
1958 if (ret != PC_OPERATION_SUCCESS) {
1959 C_LOGE("app_add_rule failed");
1963 ret = app_add_rule(pkg_id2, pkg_id1, "rwxat");
1964 if (ret != PC_OPERATION_SUCCESS) {
1965 C_LOGE("app_add_rule failed");
1969 return PC_OPERATION_SUCCESS;
1972 API int app_install(const char* pkg_id)//deprecated
1974 return perm_app_install(pkg_id);
1977 API int perm_app_install(const char* pkg_id)
1979 C_LOGD("Enter function: %s", __func__);
1982 char* smack_path AUTO_FREE;
1983 struct smack_accesses *smack AUTO_SMACK_FREE;
1985 if (!smack_label_is_valid(pkg_id))
1986 return PC_ERR_INVALID_PARAM;
1988 ret = smack_file_name(pkg_id, &smack_path);
1989 if (ret != PC_OPERATION_SUCCESS)
1992 ret = load_smack_from_file(pkg_id, &smack, &fd, &smack_path);
1993 if (ret != PC_OPERATION_SUCCESS) {
1994 C_LOGE("load_smack_from_file failed");
1998 ret = add_app_id_to_databse(pkg_id);
1999 if (ret != PC_OPERATION_SUCCESS ) {
2000 SECURE_SLOGE("Error while adding app %s to database: %s ", pkg_id, strerror(errno));
2004 ret = register_app_for_av(pkg_id);
2005 if (ret != PC_OPERATION_SUCCESS) {
2006 SECURE_SLOGE("Error while adding rules for anti viruses to app %s: %s ", pkg_id, strerror(errno));
2010 ret = register_app_for_appsetting(pkg_id);
2011 if (ret != PC_OPERATION_SUCCESS) {
2012 SECURE_SLOGE("Error while adding rules for setting managers to app %s: %s ", pkg_id, strerror(errno));
2016 ret = register_app_for_public_dirs(pkg_id, smack);
2017 if (ret != PC_OPERATION_SUCCESS) {
2018 SECURE_SLOGE("Error while adding rules for access to public dirs for app %s: %s ", pkg_id, strerror(errno));
2022 if (have_smack() && smack_accesses_apply(smack)) {
2023 C_LOGE("smack_accesses_apply failed");
2024 return PC_ERR_INVALID_OPERATION;
2027 if (smack_accesses_save(smack, fd)) {
2028 C_LOGE("smack_accesses_save failed");
2029 return PC_ERR_INVALID_OPERATION;
2032 return PC_OPERATION_SUCCESS;
2035 API int app_uninstall(const char* pkg_id)//deprecated
2037 return perm_app_uninstall(pkg_id);
2040 API int perm_app_uninstall(const char* pkg_id)
2042 // TODO: When real database will be used, then this function should remove app_id
2044 // It also should remove rules like: "anti_virus_label app_id rwx".
2045 C_LOGD("Enter function: %s", __func__);
2046 char* smack_path AUTO_FREE;
2049 if (!smack_label_is_valid(pkg_id))
2050 return PC_ERR_INVALID_PARAM;
2052 ret = smack_file_name(pkg_id, &smack_path);
2053 if (ret != PC_OPERATION_SUCCESS)
2056 if (unlink(smack_path)) {
2057 C_LOGE("unlink failed: ", strerror(errno));
2058 return PC_OPERATION_SUCCESS;
2061 ret = app_uninstall_remove_early_rules(pkg_id);
2062 if (ret != PC_OPERATION_SUCCESS)
2066 return PC_OPERATION_SUCCESS;
2069 static int save_rules(int fd, struct smack_accesses* accesses) {
2070 if (flock(fd, LOCK_EX)) {
2071 C_LOGE("flock failed, error %s", strerror(errno));
2072 return PC_ERR_FILE_OPERATION;
2075 if (smack_accesses_save(accesses, fd)) {
2076 C_LOGE("smack_accesses_save failed");
2077 return PC_ERR_FILE_OPERATION;
2079 return PC_OPERATION_SUCCESS ;
2082 static int validate_and_add_rule(char* rule, struct smack_accesses* accesses) {
2083 const char* subject = NULL;
2084 const char* object = NULL;
2085 const char* access = NULL;
2086 char* saveptr = NULL;
2088 subject = strtok_r(rule, " \t\n", &saveptr);
2089 object = strtok_r(NULL, " \t\n", &saveptr);
2090 access = strtok_r(NULL, " \t\n", &saveptr);
2092 // check rule validity
2093 if (subject == NULL ||
2096 strtok_r(NULL, " \t\n", &saveptr) != NULL ||
2097 !smack_label_is_valid(subject) ||
2098 !smack_label_is_valid(object))
2100 C_LOGE("Incorrect rule format: %s", rule);
2101 return PC_ERR_INVALID_PARAM;
2104 if (smack_accesses_add_modify(accesses, subject, object, access, "")) {
2105 C_LOGE("smack_accesses_add_modify failed");
2106 return PC_ERR_INVALID_OPERATION;
2108 return PC_OPERATION_SUCCESS ;
2111 static int parse_and_save_rules(const char** smack_rules,
2112 struct smack_accesses* accesses, const char* feature_file) {
2115 int ret = PC_OPERATION_SUCCESS;
2118 for (i = 0; smack_rules[i] != NULL ; i++) {
2119 // ignore empty lines
2120 if (strspn(smack_rules[i], " \t\n") == strlen(smack_rules[i]))
2123 tmp = strdup(smack_rules[i]);
2124 ret = validate_and_add_rule(tmp, accesses);
2126 if (ret != PC_OPERATION_SUCCESS )
2131 fd = open(feature_file, O_CREAT | O_WRONLY, 0644);
2133 C_LOGE("Unable to create file %s. Error: %s", feature_file, strerror(errno));
2134 return PC_ERR_FILE_OPERATION;
2137 ret = save_rules(fd, accesses);
2142 static int save_gids(FILE* file, const gid_t* list_of_db_gids, size_t list_size) {
2143 int ret = PC_OPERATION_SUCCESS;
2148 C_LOGE("Unable to create file. Error: %s", strerror(errno));
2149 return PC_ERR_FILE_OPERATION; // TODO remove smack accesses?
2152 if(-1 == fchmod(fileno(file), 0644)) {
2153 C_LOGE("Unable to chmod file. Error: %s", strerror(errno));
2154 return PC_ERR_FILE_OPERATION;
2157 for (i = 0; i < list_size ; ++i) {
2158 written = fprintf(file, "%u\n", list_of_db_gids[i]);
2160 C_LOGE("fprintf failed for file. Error: %s", strerror(errno));
2161 ret = PC_ERR_FILE_OPERATION;
2168 API int add_api_feature(app_type_t app_type,
2169 const char* api_feature_name,
2170 const char** smack_rules,
2171 const gid_t* list_of_db_gids,
2172 size_t list_size)//deprecated
2174 return perm_add_api_feature(app_type, api_feature_name, smack_rules, list_of_db_gids, list_size);
2177 API int perm_add_api_feature(app_type_t app_type,
2178 const char* api_feature_name,
2179 const char** smack_rules,
2180 const gid_t* list_of_db_gids,
2182 C_LOGD("Enter function: %s", __func__);
2184 int ret = PC_OPERATION_SUCCESS;
2185 char* smack_file AUTO_FREE;
2186 char* dac_file AUTO_FREE;
2187 struct smack_accesses* accesses = NULL;
2190 // TODO check process capabilities
2192 // get feature SMACK file name
2193 ret = perm_file_path(&smack_file, app_type, api_feature_name, ".smack", 0);
2194 if (ret != PC_OPERATION_SUCCESS || !smack_file ) {
2198 // check if feature exists
2199 if (file_exists(smack_file)) {
2200 C_LOGE("Feature file %s already exists", smack_file);
2201 return PC_ERR_INVALID_PARAM;
2204 // check .dac existence only if gids are supported
2205 if (list_of_db_gids && list_size > 0) {
2206 // get feature DAC file name
2207 ret = perm_file_path(&dac_file, app_type, api_feature_name, ".dac", 0);
2208 if (ret != PC_OPERATION_SUCCESS || !dac_file ) {
2212 // check if feature exists
2213 if (file_exists(dac_file)) {
2214 C_LOGE("Feature file %s already exists", dac_file);
2215 return PC_ERR_INVALID_PARAM;
2219 // parse & save rules
2221 if (smack_accesses_new(&accesses)) {
2222 C_LOGE("smack_acceses_new failed");
2223 return PC_ERR_MEM_OPERATION;
2226 ret = parse_and_save_rules(smack_rules, accesses, smack_file);
2227 smack_accesses_free(accesses);
2230 // go through gid list
2231 if (ret == PC_OPERATION_SUCCESS && list_of_db_gids && list_size > 0) {
2233 file = fopen(dac_file, "w+");
2234 ret = save_gids(file, list_of_db_gids, list_size);
2238 // remove both files in case of failure
2239 if (ret != PC_OPERATION_SUCCESS) {
2250 * This function is marked as deprecated and will be removed
2252 API int app_register_av(const char* app_av_id)//deprecated
2256 char* smack_path AUTO_FREE;
2257 struct smack_accesses* smack AUTO_SMACK_FREE;
2259 if(app_av_id == NULL) {
2260 C_LOGE("Invalid param app_av_id.");
2261 return PC_ERR_INVALID_PARAM;
2264 ret = load_smack_from_file(app_av_id, &smack, &fd, &smack_path);
2265 if (ret != PC_OPERATION_SUCCESS ) {
2266 C_LOGE("load_smack_from_file failed");
2270 ret = app_register_av_internal(app_av_id, smack);
2271 if (PC_OPERATION_SUCCESS != ret) {
2272 C_LOGE("app_register_av_internal failed");
2276 // Add permisions from OSP_antivirus.smack file
2277 ret = perm_to_smack(smack, app_av_id, APP_TYPE_OSP, TIZEN_PRIVILEGE_ANTIVIRUS);
2278 if (PC_OPERATION_SUCCESS != ret) {
2279 C_LOGE("perm_to_smack failed");
2283 // Add permisions from OSP_antivirus.dac file
2284 ret = perm_to_dac(app_av_id, APP_TYPE_OSP, TIZEN_PRIVILEGE_ANTIVIRUS);
2285 if (ret != PC_OPERATION_SUCCESS) {
2286 C_LOGE("perm_to_dac failed");
2290 if (have_smack() && smack_accesses_apply(smack)) {
2291 C_LOGE("smack_accesses_apply failed");
2292 ret = PC_ERR_INVALID_OPERATION;
2296 if (smack_accesses_save(smack, fd)) {
2297 C_LOGE("smack_accesses_save failed");
2298 ret = PC_ERR_INVALID_OPERATION;