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>
46 #include "privilege-control.h"
47 #include "access-db.h"
52 #define DEVELOPER_GID 5100
53 #define DEVELOPER_UID 5100
55 #define APP_USER_NAME "app"
56 #define DEV_USER_NAME "developer"
58 #define APP_HOME_DIR TOSTRING(HOMEDIR) "/app"
59 #define DEV_HOME_DIR TOSTRING(HOMEDIR) "/developer"
61 #define APP_GROUP_PATH TOSTRING(SHAREDIR) "/app_group_list"
62 #define DEV_GROUP_PATH TOSTRING(SHAREDIR) "/dev_group_list"
64 #define SMACK_APP_LABEL_TEMPLATE "~APP~"
65 #define SMACK_SHARED_DIR_LABEL_TEMPLATE "~APP_SHARED_DIR~"
67 #define SMACK_SRC_FILE_SUFFIX "_src_file"
68 #define SMACK_SRC_DIR_SUFFIX "_src_dir"
69 #define SMACK_DATA_SUFFIX "_data"
70 #define WRT_BASE_DEVCAP "WRT"
71 #define WRT_CLIENT_PATH "/usr/bin/wrt-client"
73 #define TIZEN_PRIVILEGE_ANTIVIRUS "http://tizen.org/privilege/antivirus"
74 #define TIZEN_PRIVILEGE_APPSETTING "http://tizen.org/privilege/appsetting"
75 #define PATH_RULES_PUBLIC_RO "PATH_RULES_PUBLIC_RO.smack"
76 #define PATH_RULES_GROUP_RW "PATH_RULES_GROUP_RW.smack"
92 typedef int (*label_decision_fn)(const FTSENT*);
98 API int control_privilege(void)//deprecated
100 C_LOGD("Enter function: %s", __func__);
101 if(getuid() == APP_UID) // current user is 'app'
102 return PC_OPERATION_SUCCESS;
104 if(perm_app_set_privilege("org.tizen.", NULL, NULL) == PC_OPERATION_SUCCESS)
105 return PC_OPERATION_SUCCESS;
107 return PC_ERR_NOT_PERMITTED;
111 * TODO: this function should be moved to libsmack in open-source.
113 API int get_smack_label_from_process(pid_t pid, char smack_label[SMACK_LABEL_LEN + 1])
115 C_LOGD("Enter function: %s", __func__);
118 int PATH_MAX_LEN = 64;
119 char path[PATH_MAX_LEN + 1];
122 ret = PC_ERR_INVALID_PARAM;
126 if(smack_label == NULL) {
127 C_LOGE("Invalid param smack_label (NULL).");
128 ret = PC_ERR_INVALID_PARAM;
132 bzero(smack_label, SMACK_LABEL_LEN + 1);
133 if (!have_smack()) { // If no smack found just return success and empty label
134 C_LOGD("No SMACK. Return empty label");
135 ret = PC_OPERATION_SUCCESS;
139 bzero(path, PATH_MAX_LEN + 1);
140 snprintf(path, PATH_MAX_LEN, "/proc/%d/attr/current", pid);
141 fd = open(path, O_RDONLY);
143 C_LOGE("cannot open file %s (errno: %s)", path, strerror(errno));
144 ret = PC_ERR_FILE_OPERATION;
148 ret = read(fd, smack_label, SMACK_LABEL_LEN);
150 C_LOGE("cannot read from file %s", path);
151 ret = PC_ERR_FILE_OPERATION;
155 ret = PC_OPERATION_SUCCESS;
161 API int smack_pid_have_access(pid_t pid,
163 const char *access_type)
165 C_LOGD("Enter function: %s", __func__);
167 char pid_subject_label[SMACK_LABEL_LEN + 1];
169 cap_flag_value_t cap_v;
172 C_LOGD("No SMACK. Return access granted");
177 C_LOGE("Invalid pid.");
182 C_LOGE("Invalid object param.");
186 if(access_type == NULL) {
187 C_LOGE("Invalid access_type param");
191 //get SMACK label of process
192 ret = get_smack_label_from_process(pid, pid_subject_label);
193 if (PC_OPERATION_SUCCESS != ret) {
194 C_LOGE("get_smack_label_from_process %d failed: %d", pid, ret);
197 C_LOGD("pid %d have label: %s", pid, pid_subject_label);
199 // do not call smack_have_access() if label is empty
200 if (pid_subject_label[0] != '\0') {
201 ret = smack_have_access(pid_subject_label, object, access_type);
203 C_LOGE("smack_have_access failed");
206 if ( 1 == ret ) { // smack_have_access return 1 (access granted)
207 C_LOGD("smack_have_access returned 1 (access granted)");
212 // smack_have_access returned 0 (access denied). Now CAP_MAC_OVERRIDE should be checked
213 C_LOGD("smack_have_access returned 0 (access denied)");
214 cap = cap_get_pid(pid);
216 C_LOGE("cap_get_pid failed");
219 ret = cap_get_flag(cap, CAP_MAC_OVERRIDE, CAP_EFFECTIVE, &cap_v);
221 C_LOGE("cap_get_flag failed");
225 if (cap_v == CAP_SET) {
226 C_LOGD("pid %d has CAP_MAC_OVERRIDE", pid);
230 C_LOGD("pid %d doesn't have CAP_MAC_OVERRIDE", pid);
235 static int set_dac(const char *smack_label, const char *pkg_name)
237 C_LOGD("Enter function: %s", __func__);
238 FILE* fp_group = NULL; // /etc/group
239 uid_t t_uid = -1; // uid of current process
240 gid_t *glist = NULL; // group list
241 gid_t temp_gid = -1; // for group list
242 char buf[10] = {0, }; // contents in group_list file
243 int glist_cnt = 0; // for group list
247 unsigned *additional_gids = NULL;
250 * initialize user structure
252 C_LOGD("initialize user structure");
253 memset(usr.user_name, 0x00, 10);
254 memset(usr.home_dir, 0x00, 64);
255 memset(usr.group_list, 0x00, 64);
260 C_LOGD("Current uid is %d", t_uid);
262 if(t_uid == 0) // current user is 'root'
264 if(!strncmp(pkg_name, "developer", 9))
266 strncpy(usr.user_name, DEV_USER_NAME, sizeof(usr.user_name));
267 usr.uid = DEVELOPER_UID;
268 usr.gid = DEVELOPER_GID;
269 strncpy(usr.home_dir, DEV_HOME_DIR, sizeof(usr.home_dir));
270 strncpy(usr.group_list, DEV_GROUP_PATH, sizeof(usr.group_list));
274 strncpy(usr.user_name, APP_USER_NAME, sizeof(usr.user_name));
277 strncpy(usr.home_dir, APP_HOME_DIR, sizeof(usr.home_dir));
278 strncpy(usr.group_list, APP_GROUP_PATH, sizeof(usr.group_list));
282 * get group information
284 C_LOGD("get group information");
285 if(!(fp_group = fopen(usr.group_list, "r")))
287 C_LOGE("File open error: %s", usr.group_list);
288 result = PC_ERR_FILE_OPERATION; // return -1
292 while(fgets(buf, 10, fp_group) != NULL)
295 temp_gid = strtoul(buf, 0, 10);
296 if(errno != 0) // error occured during strtoul()
298 C_LOGE("Cannot change string to integer: %s", buf);
299 result = PC_ERR_INVALID_OPERATION;
303 glist = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + 1));
306 result = PC_ERR_MEM_OPERATION; // return -2
307 C_LOGE("Cannot allocate memory");
310 glist[glist_cnt] = temp_gid;
316 if(NULL != smack_label)
321 result = get_app_gids(smack_label, &additional_gids, &cnt);
322 if (result != PC_OPERATION_SUCCESS)
326 glist_new = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + cnt));
327 if (glist_new == NULL) {
328 result = PC_ERR_MEM_OPERATION; // return -2
329 C_LOGE("Memory allocation failed");
333 for (i = 0; i < cnt; ++i) {
334 C_LOGD("Additional GID based on enabled permissions: %u", additional_gids[i]);
335 glist[glist_cnt++] = additional_gids[i];
343 C_LOGD("Adding process to the following groups:");
344 for(i=0; i<glist_cnt; ++i) {
345 C_LOGD("glist [ %d ] = %d", i, glist[i]);
347 C_LOGD("setgroups()");
348 if(setgroups(glist_cnt, glist) != 0)
350 C_LOGE("setgroups failed");
351 result = PC_ERR_NOT_PERMITTED; // return -3
361 * setuid() & setgid()
363 C_LOGD("setgid( %d ) & setuid( %d )", usr.gid, usr.uid);
364 if(setgid(usr.gid) != 0) // fail
366 C_LOGE("Failed to execute setgid().");
367 result = PC_ERR_INVALID_OPERATION;
370 if(setuid(usr.uid) != 0) // fail
372 C_LOGE("Failed to execute setuid().");
373 result = PC_ERR_INVALID_OPERATION;
377 SECURE_SLOGD("setenv(): USER = %s, HOME = %s", usr.user_name, usr.home_dir);
378 if(setenv("USER", usr.user_name, 1) != 0) //fail
380 C_LOGE("Failed to execute setenv() [USER].");
381 result = PC_ERR_INVALID_OPERATION;
384 if(setenv("HOME", usr.home_dir, 1) != 0) // fail
386 C_LOGE("Failed to execute setenv() [HOME].");
387 result = PC_ERR_INVALID_OPERATION;
391 else // current user is not only 'root' but 'app'
393 C_LOGE("Current user is NOT root");
394 result = PC_ERR_NOT_PERMITTED; // return -3
398 result = PC_OPERATION_SUCCESS;
405 free(additional_gids);
411 * Get SMACK label from EXEC label of a file.
412 * SMACK label should be freed by caller
414 * @param path file path to take label from
415 * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
417 static int get_smack_from_binary(char **smack_label, const char* path, app_type_t type)
419 C_LOGD("Enter function: %s", __func__);
422 C_LOGD("Path: %s", path);
425 if (type == APP_TYPE_WGT
426 || type == APP_TYPE_WGT_PARTNER
427 || type == APP_TYPE_WGT_PLATFORM) {
428 ret = smack_lgetlabel(path, smack_label, SMACK_LABEL_EXEC);
430 ret = smack_getlabel(path, smack_label, SMACK_LABEL_EXEC);
433 C_LOGE("Getting exec label from file %s failed", path);
434 return PC_ERR_INVALID_OPERATION;
437 return PC_OPERATION_SUCCESS;
441 * Set process SMACK label.
442 * This function is emulating EXEC label behavior of SMACK for programs
443 * run by dlopen/dlsym instead of execv.
446 * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
448 static int set_smack_for_self (char *smack_label)
450 C_LOGD("Enter function: %s", __func__);
453 if (smack_label == NULL) {
454 /* No label to set, just return with success */
455 C_LOGD("No label to set, just return with success");
456 ret = PC_OPERATION_SUCCESS;
459 C_LOGD("label = %s", smack_label);
461 ret = smack_set_label_for_self(smack_label);
462 C_LOGD("smack_set_label_for_self returned %d", ret);
464 ret = PC_OPERATION_SUCCESS;
470 static int is_widget(const char* path)
472 C_LOGD("Enter function: %s", __func__);
473 char buf[sizeof(WRT_CLIENT_PATH)];
476 ret = readlink(path, buf, sizeof(WRT_CLIENT_PATH));
478 C_LOGD("readlink(%s) returned error: %s. Assuming that app is not a widget", path, strerror(errno));
479 else if (ret == sizeof(WRT_CLIENT_PATH))
480 C_LOGD("%s is not a widget", path);
481 if (ret == -1 || ret == sizeof(WRT_CLIENT_PATH))
484 C_LOGD("buf = %s", buf);
486 ret = !strcmp(WRT_CLIENT_PATH, buf);
487 C_LOGD("%s is %s widget", path, ret ? "a" : "not a");
492 * Partially verify, that the type given for app is correct.
493 * This function will use some heuristics to check whether the app type is right.
494 * It is intended for security hardening to catch privilege setting for the
495 * app type not corresponding to the actual binary.
496 * Beware - when it detects an anomaly, the whole process will be terminated.
498 * @param type claimed application type
499 * @param path file path to executable
500 * @return return void on success, terminate the process on error
502 static app_type_t verify_app_type(const char* type, const char* path)
504 C_LOGD("Enter function: %s", __func__);
505 /* TODO: this should actually be treated as error, but until the old
506 * set_privilege API is removed, it must be ignored */
508 C_LOGD("PKG_TYPE_OTHER");
509 return APP_TYPE_OTHER; /* good */
512 if (is_widget(path)) {
513 if (!strcmp(type, "wgt")) {
514 C_LOGD("PKG_TYPE_WGT");
515 return APP_TYPE_WGT; /* good */
516 } else if (!strcmp(type, "wgt_partner")) {
517 C_LOGD("PKG_TYPE_WGT_PARTNER");
518 return APP_TYPE_WGT_PARTNER; /* good */
519 } else if (!strcmp(type, "wgt_platform")) {
520 C_LOGD("PKG_TYPE_WGT_PLATFORM");
521 return APP_TYPE_WGT_PLATFORM; /* good */
525 if (type == NULL || (strcmp(type, "wgt")
526 && strcmp(type, "wgt_partner")
527 && strcmp(type, "wgt_platform"))){
528 C_LOGD("PKG_TYPE_OTHER");
529 return APP_TYPE_OTHER; /* good */
534 C_LOGE("EXIT_FAILURE");
538 API int set_app_privilege(const char* name, const char* type, const char* path)//deprecated
540 return perm_app_set_privilege(name, type, path);
543 API int perm_app_set_privilege(const char* name, const char* type, const char* path)
545 C_LOGD("Enter function: %s", __func__);
546 SECURE_SLOGD("Function params: name = %s, type = %s, path = %s", name, type, path);
547 int ret = PC_OPERATION_SUCCESS;
548 int were_rules_loaded = 0;
549 char *smack_label AUTO_FREE;
552 C_LOGE("Error invalid parameter");
553 return PC_ERR_INVALID_PARAM;
556 if (path != NULL && have_smack()) {
557 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
558 if (ret != PC_OPERATION_SUCCESS)
561 were_rules_loaded = check_if_rules_were_loaded(smack_label);
562 if (were_rules_loaded < 0) {
563 C_LOGE("Error while check_if_rules_was_loaded");
564 return PC_ERR_INVALID_OPERATION;
566 if (!were_rules_loaded) { // first run of application
567 C_LOGD("This is first run of this application. Adding SMACK rules");
568 ret = add_app_first_run_rules(smack_label);
569 if (ret != PC_OPERATION_SUCCESS ) {
570 C_LOGW("Warning: add_app_first_run_rules failed");
571 // should we return here with error code?
573 mark_rules_as_loaded(smack_label);
576 ret = set_smack_for_self(smack_label);
577 if (ret != PC_OPERATION_SUCCESS)
581 if (path != NULL && !have_smack()) {
582 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
583 if (ret != PC_OPERATION_SUCCESS)
587 return set_dac(smack_label, name);
590 API int set_privilege(const char* pkg_name)//deprecated
592 C_LOGD("Enter function: %s", __func__);
593 return perm_app_set_privilege(pkg_name, NULL, NULL);
596 static inline const char* app_type_name(app_type_t app_type)
603 case APP_TYPE_WGT_PARTNER:
604 return "WRT_partner";
605 case APP_TYPE_WGT_PLATFORM:
606 return "WRT_platform";
607 case APP_TYPE_OSP_PARTNER:
608 return "OSP_partner";
609 case APP_TYPE_OSP_PLATFORM:
610 return "OSP_platform";
618 static inline const char* app_type_group_name(app_type_t app_type)
622 case APP_TYPE_WGT_PARTNER:
623 case APP_TYPE_WGT_PLATFORM:
626 case APP_TYPE_OSP_PARTNER:
627 case APP_TYPE_OSP_PLATFORM:
637 * This function changes permission URI to basename for file name.
638 * For e.g. from http://tizen.org/privilege/contact.read will be
639 * created basename : org.tizen.privilege.contact.read
642 static int base_name_from_perm(const char *perm, char **name) {
644 char *host_dot = NULL;
645 char *rest_slash = NULL;
648 ip = iri_parse(perm);
649 if (ip == NULL || ip->host == NULL) {
650 C_LOGE("Bad permission format : %s", perm);
652 return PC_ERR_INVALID_PARAM;
655 if (ip->path == NULL) {
661 host_dot = strrchr(ip->host, '.');
668 while ((rest_slash = strchr(ip->path, '/'))) {
672 ret = asprintf(name, "%s%s%s%s",
673 host_dot ? host_dot : "", host_dot ? "." : "",
674 ip->host ? ip->host : "", ip->path);
676 C_LOGE("asprintf failed");
678 return PC_ERR_MEM_OPERATION;
682 return PC_OPERATION_SUCCESS;
685 static int perm_file_path(char** path, app_type_t app_type, const char* perm, const char *suffix, bool is_early)
687 const char* app_type_prefix = NULL;
688 char* perm_basename = NULL;
691 if (perm == NULL || strlen(perm) == 0) {
692 C_LOGE("empty permission name");
693 return PC_ERR_INVALID_PARAM;
696 app_type_prefix = app_type_group_name(app_type);
698 ret = base_name_from_perm(perm, &perm_basename);
699 if (ret != PC_OPERATION_SUCCESS) {
700 C_LOGE("Couldn't get permission basename");
705 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s%s",
706 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
707 perm_basename, "_early", suffix);
710 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s",
711 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
712 perm_basename, suffix);
715 C_LOGE("asprintf failed");
716 return PC_ERR_MEM_OPERATION;
719 C_LOGD("Path : %s", *path);
721 return PC_OPERATION_SUCCESS;
724 static int perm_to_smack_from_file(struct smack_accesses* smack,
725 const char* app_label,
726 const char* app_label_template,
727 const char* rules_file_path)
729 C_LOGD("Enter function: %s", __func__);
731 char smack_subject[SMACK_LABEL_LEN + 1];
732 char smack_object[SMACK_LABEL_LEN + 1];
733 char smack_accesses[ACC_LEN + 1];
734 FILE* file AUTO_FCLOSE;
736 file = fopen(rules_file_path, "r");
737 C_LOGD("path = %s", rules_file_path);
739 C_LOGW("fopen failed [%s] %s", rules_file_path, strerror(errno));
740 return PC_OPERATION_SUCCESS;
744 "%" TOSTRING(SMACK_LABEL_LEN) "s "
745 "%" TOSTRING(SMACK_LABEL_LEN) "s "
746 "%" TOSTRING(ACC_LEN) "s\n",
747 smack_subject, smack_object, smack_accesses) == 3) {
748 if (!strcmp(smack_subject, app_label_template))
749 strcpy(smack_subject, app_label);
751 if (!strcmp(smack_object, app_label_template))
752 strcpy(smack_object, app_label);
754 C_LOGD("smack_accesses_add_modify (subject: %s, object: %s, access: %s)", smack_subject, smack_object, smack_accesses);
755 if (smack_accesses_add_modify(smack, smack_subject, smack_object, smack_accesses, "") != 0) {
756 C_LOGE("smack_accesses_add_modify failed");
757 return PC_ERR_INVALID_OPERATION;
761 return PC_OPERATION_SUCCESS;
764 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)
766 C_LOGD("Enter function: %s", __func__);
769 char* path AUTO_FREE;
771 // get file name for permission (devcap)
772 ret = perm_file_path(&path, app_type, perm, ".smack", is_early);
773 if (ret != PC_OPERATION_SUCCESS) {
774 C_LOGD("No smack config file for permission %s", perm);
778 ret = perm_to_smack_from_file(smack, app_label, SMACK_APP_LABEL_TEMPLATE, path);
779 if (ret != PC_OPERATION_SUCCESS) {
783 return PC_OPERATION_SUCCESS;
786 static int perm_to_smack_early(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
788 C_LOGD("Enter function: %s", __func__);
790 return perm_to_smack_generic(smack, app_label, app_type, perm, 1);
793 static int perm_to_smack(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
795 C_LOGD("Enter function: %s", __func__);
797 return perm_to_smack_generic(smack, app_label, app_type, perm, 0);
800 static int perm_to_dac(const char* app_label, app_type_t app_type, const char* perm)
802 C_LOGD("Enter function: %s", __func__);
804 char* path AUTO_FREE;
805 FILE* file AUTO_FCLOSE;
808 ret = perm_file_path(&path, app_type, perm, ".dac", 0);
809 if (ret != PC_OPERATION_SUCCESS) {
810 C_LOGD("No dac config file for permission %s", perm);
814 file = fopen(path, "r");
815 C_LOGD("path = %s", path);
817 C_LOGW("fopen failed");
818 return PC_OPERATION_SUCCESS;
821 while (fscanf(file, "%d\n", &gid) == 1) {
822 SECURE_SLOGD("Adding app_id %s to group %d", app_label, gid);
823 ret = add_app_gid(app_label, gid);
824 if (ret != PC_OPERATION_SUCCESS) {
825 C_LOGE("sadd_app_gid failed");
830 return PC_OPERATION_SUCCESS;
833 static int label_all(const FTSENT* ftsent)
835 return DECISION_LABEL;
838 static int label_execs(const FTSENT* ftsent)
840 C_LOGD("Mode: %d", ftsent->fts_statp->st_mode);
841 // label only regular executable files
842 if (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR))
843 return DECISION_LABEL;
844 return DECISION_SKIP;
847 static int label_dirs(const FTSENT* ftsent)
849 // label only directories
850 if (S_ISDIR(ftsent->fts_statp->st_mode))
851 return DECISION_LABEL;
852 return DECISION_SKIP;
855 static int label_links_to_execs(const FTSENT* ftsent)
858 char* target AUTO_FREE;
860 // check if it's a link
861 if ( !S_ISLNK(ftsent->fts_statp->st_mode))
862 return DECISION_SKIP;
864 target = realpath(ftsent->fts_path, NULL);
866 C_LOGE("Getting link target for %s failed. Error %s", ftsent->fts_path, strerror(errno));
867 return PC_ERR_FILE_OPERATION;
869 if (-1 == stat(target, &buf)) {
870 C_LOGE("stat failed for %s, error: %s",target, strerror(errno));
871 return PC_ERR_FILE_OPERATION;
873 // skip if link target is not a regular executable file
874 if (buf.st_mode != (buf.st_mode | S_IXUSR | S_IFREG)) {
875 C_LOGD("%s is not a regular executable file. Skipping.", target);
876 return DECISION_SKIP;
879 return DECISION_LABEL;
882 static int dir_set_smack_r(const char *path, const char* label,
883 enum smack_label_type type, label_decision_fn fn)
885 C_LOGD("Enter function: %s", __func__);
886 const char* path_argv[] = {path, NULL};
887 FTS *fts AUTO_FTS_CLOSE;
891 fts = fts_open((char * const *) path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
893 C_LOGE("fts_open failed");
894 return PC_ERR_FILE_OPERATION;
897 while ((ftsent = fts_read(fts)) != NULL) {
898 /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
899 if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
900 C_LOGE("FTS_ERR error or failed stat(2) (FTS_NS)");
901 return PC_ERR_FILE_OPERATION;
909 if (ret == DECISION_LABEL) {
910 C_LOGD("smack_lsetlabel (label: %s (type: %d), path: %s)", label, type, ftsent->fts_path);
911 if (smack_lsetlabel(ftsent->fts_path, label, type) != 0) {
912 C_LOGE("smack_lsetlabel failed");
913 return PC_ERR_FILE_OPERATION;
918 /* If last call to fts_read() set errno, we need to return error. */
920 C_LOGE("Last errno: %s", strerror(errno));
921 return PC_ERR_FILE_OPERATION;
923 return PC_OPERATION_SUCCESS;
926 API char* app_id_from_socket(int sockfd)//deprecated
928 return perm_app_id_from_socket(sockfd);
931 API char* perm_app_id_from_socket(int sockfd)
933 C_LOGD("Enter function: %s", __func__);
940 ret = smack_new_label_from_socket(sockfd, &app_id);
942 C_LOGE("smack_new_label_from_socket failed");
946 SECURE_SLOGD("app_id: %s", app_id);
951 static int app_add_rule(const char *app_id, const char *object, const char *perm)
953 C_LOGD("Enter function: %s", __func__);
956 char *smack_path AUTO_FREE;
957 struct smack_accesses* smack AUTO_SMACK_FREE;
959 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
960 if (ret != PC_OPERATION_SUCCESS) {
961 C_LOGE("load_smack_from_file failed");
965 ret = smack_accesses_add_modify(smack, app_id, object, perm, "");
967 C_LOGE("smack_accesses_add_modify failed");
968 return PC_ERR_INVALID_OPERATION;
971 if (have_smack() && smack_accesses_apply(smack)) {
972 C_LOGE("smack_accesses_apply failed");
973 return PC_ERR_INVALID_OPERATION;
976 if (smack_accesses_save(smack, fd)) {
977 C_LOGE("smack_accesses_save failed");
978 return PC_ERR_INVALID_OPERATION;
981 return PC_OPERATION_SUCCESS;
986 app_register_appsetting(const char *app_id, struct smack_accesses *smack)
988 C_LOGD("Enter function: %s", __func__);
992 char **label_app_list AUTO_FREE;
993 char **label_dir_list AUTO_FREE;
994 int app_list_len = 0;
995 int dir_list_len = 0;
997 if (!smack_label_is_valid(app_id))
998 return PC_ERR_INVALID_PARAM;
1001 /* writing appsetting_id (app_id) to "database"*/
1002 ret = add_appsetting_id_to_databse(app_id);
1003 if (ret != PC_OPERATION_SUCCESS)
1007 /* Reading labels of all installed apps from "database"*/
1008 ret = get_all_apps_ids(&label_app_list, &app_list_len);
1009 if (ret != PC_OPERATION_SUCCESS) {
1010 C_LOGE("Error while getting data from database");
1014 /*Add smack rules with rx access to each app*/
1015 for (i = 0; i < app_list_len; ++i) {
1016 C_LOGD("Appsetting: applying rx rule for %s", label_app_list[i]);
1017 if (smack_accesses_add_modify(smack, app_id,
1018 label_app_list[i], "rx", "") == -1) {
1019 C_LOGE("smack_accesses_add_modify failed");
1020 ret = PC_ERR_INVALID_OPERATION;
1025 /* Reading labels of all registered settings dirs from "database"*/
1026 ret = get_all_settings_dir_ids(
1027 &label_dir_list, &dir_list_len);
1028 if (ret != PC_OPERATION_SUCCESS) {
1029 C_LOGE("Error while getting data from database");
1032 /*Add smack rules with rwx access to each app*/
1033 for (i = 0; i < dir_list_len; ++i) {
1034 C_LOGD("Appsetting: applying rwx rule for %s", label_dir_list[i]);
1035 if (smack_accesses_add_modify(smack, app_id,
1036 label_dir_list[i], "rwx", "") == -1) {
1037 C_LOGE("smack_accesses_add_modify failed");
1038 ret = PC_ERR_INVALID_OPERATION;
1040 /* Should we abort adding rules if
1041 * smack_accesses_add_modify fails once?*/
1046 for (i = 0; i < app_list_len; ++i) {
1047 free(label_app_list[i]);
1049 for (i = 0; i < dir_list_len; ++i) {
1050 free(label_dir_list[i]);
1056 static int app_register_av_internal(const char *app_av_id, struct smack_accesses* smack)
1058 C_LOGD("Enter function: %s", __func__);
1062 char** smack_label_app_list AUTO_FREE;
1063 int smack_label_app_list_len = 0;
1065 if (!smack_label_is_valid(app_av_id) || NULL == smack)
1066 return PC_ERR_INVALID_PARAM;
1068 // writing anti_virus_id (app_av_id) to "database"
1069 ret = add_av_id_to_databse(app_av_id);
1070 if (ret != PC_OPERATION_SUCCESS )
1073 // Reading labels of all installed apps from "database"
1074 ret = get_all_apps_ids(&smack_label_app_list, &smack_label_app_list_len);
1075 if (ret != PC_OPERATION_SUCCESS ) {
1076 C_LOGE("Error while geting data from database");
1079 for (i = 0; i < smack_label_app_list_len; ++i) {
1080 C_LOGD("Applying rwx rule for %s", smack_label_app_list[i]);
1081 if (smack_accesses_add_modify(smack, app_av_id, smack_label_app_list[i], "wrx", "") == -1) {
1082 C_LOGE("smack_accesses_add_modify failed");
1083 ret = PC_ERR_INVALID_OPERATION;
1085 // Should we abort adding rules once smack_accesses_add_modify will fail?
1090 for (i = 0; i < smack_label_app_list_len; ++i) {
1091 free(smack_label_app_list[i]);
1098 * This function will find labels of all anti viruses in database
1099 * and for all of them will add a rule "anti_virus_label app_id rwx".
1100 * This should be called in app_install function.
1102 static int register_app_for_av(const char * app_id)
1105 char** smack_label_av_list AUTO_FREE;
1106 int smack_label_av_list_len = 0;
1108 // Reading labels of all installed anti viruses from "database"
1109 ret = get_all_avs_ids(&smack_label_av_list, &smack_label_av_list_len);
1110 if (ret != PC_OPERATION_SUCCESS) {
1111 C_LOGE("Error while geting data from database");
1115 // for each anti-virus label put rule: "anti_virus_label app_id rwx"
1116 for (i = 0; i < smack_label_av_list_len; ++i) {
1117 SECURE_SLOGD("Antivirus: app_add_rule (%s, %s rx)", smack_label_av_list[i], app_id);
1118 if (strcmp(app_id, smack_label_av_list[i])==0) {
1119 SECURE_SLOGW("Trying to add antivirus rule for self. Skipping");
1122 ret = app_add_rule(smack_label_av_list[i], app_id, "wrx");
1123 if (ret != PC_OPERATION_SUCCESS) {
1124 C_LOGE("app_add_rule failed");
1128 free(smack_label_av_list[i]);
1131 ret = PC_OPERATION_SUCCESS;
1134 // If something failed, then no entry of smack_label_av_list[i]
1135 // was deallocated. They all must be freed.
1136 for(; i<smack_label_av_list_len; ++i) {
1137 free(smack_label_av_list[i]);
1144 * This function will find labels of all setting applications in database
1145 * and for all of them will add a rule "appsetting_id app_id rwx".
1146 * This should be called in app_install function.
1148 static int register_app_for_appsetting(const char *app_id)
1150 C_LOGD("Enter function: %s",__func__);
1152 char **smack_label_list AUTO_FREE;
1153 int smack_label_list_len = 0;
1155 /* Reading labels of all installed setting managers from "database"*/
1156 ret = get_all_appsetting_ids(&smack_label_list, &smack_label_list_len);
1157 if (ret != PC_OPERATION_SUCCESS) {
1158 C_LOGE("Error while geting data from database");
1162 /* for each appsetting put rule: "appsetting_id app_id rx"*/
1163 for (i = 0; i < smack_label_list_len; ++i) {
1165 SECURE_SLOGD("Appsetting: app_add_rule (%s, %s rx)", smack_label_list[i], app_id);
1166 if (strcmp(app_id, smack_label_list[i])==0) {
1167 SECURE_SLOGW("Trying to add setting rule for self. Skipping");
1170 ret = app_add_rule(smack_label_list[i], app_id, "rx");
1171 if (ret != PC_OPERATION_SUCCESS) {
1172 C_LOGE("app_add_rule failed");
1176 free(smack_label_list[i]);
1179 ret = PC_OPERATION_SUCCESS;
1182 /* If something failed, then no entry of smack_label_list[i]
1183 was deallocated. They all must be freed.*/
1184 for (; i < smack_label_list_len; ++i) {
1185 free(smack_label_list[i]);
1193 * This function will grant app_id rx access to all public directories and
1194 * files previously designated by app_setup_path(APP_PATH_PUBLIC_RO)
1195 * This should be called in app_install function.
1197 static int register_app_for_public_dirs(const char *app_id, struct smack_accesses *smack)
1199 C_LOGD("Enter function: %s", __func__);
1201 char **public_dirs AUTO_FREE;
1202 int public_dirs_cnt = 0;
1204 ret = db_get_public_dirs(&public_dirs, &public_dirs_cnt);
1205 if (ret != PC_OPERATION_SUCCESS) {
1206 C_LOGE("Error while getting data from database");
1210 for (i = 0; i < public_dirs_cnt; ++i) {
1211 SECURE_SLOGD("Allowing app %s to access public path %s", app_id, public_dirs[i]);
1212 if (smack_accesses_add_modify(smack, app_id, public_dirs[i], "rx", "")) {
1213 C_LOGE("app_add_rule_modify failed");
1214 while (i < public_dirs_cnt)
1215 free(public_dirs[i++]);
1216 return PC_ERR_INVALID_OPERATION;
1218 free(public_dirs[i]);
1221 return PC_OPERATION_SUCCESS;
1224 static int app_add_permissions_internal(const char* app_id, app_type_t app_type, const char** perm_list, int permanent)
1226 C_LOGD("Enter function: %s", __func__);
1228 char* smack_path AUTO_FREE;
1229 char* smack_path_early AUTO_FREE;
1231 int fd_early AUTO_CLOSE;
1232 struct smack_accesses *smack AUTO_SMACK_FREE;
1233 struct smack_accesses *smack_early AUTO_SMACK_FREE;
1234 const char* base_perm = NULL;
1236 if (!smack_label_is_valid(app_id))
1237 return PC_ERR_INVALID_PARAM;
1239 if(perm_list == NULL) {
1240 C_LOGE("Invalid perm_list (NULL).");
1241 return PC_ERR_INVALID_PARAM;
1244 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1245 if (ret != PC_OPERATION_SUCCESS) {
1246 C_LOGE("load_smack_from_file failed");
1250 ret = load_smack_from_file_early(app_id, &smack_early, &fd_early, &smack_path_early);
1251 if (ret != PC_OPERATION_SUCCESS) {
1252 C_LOGE("load_smack_from_file failed");
1256 /* Implicitly enable base permission for an app_type */
1257 base_perm = app_type_name(app_type);
1259 SECURE_SLOGD("perm_to_smack params: app_id: %s, %s", app_id, base_perm);
1260 ret = perm_to_smack(smack, app_id, APP_TYPE_OTHER, base_perm);
1261 if (ret != PC_OPERATION_SUCCESS){
1262 C_LOGE("perm_to_smack failed");
1266 // Add early permission - such permissions should be enabled right after system boot
1267 SECURE_SLOGD("perm_to_smack params: app_id: %s, %s", app_id, base_perm);
1268 ret = perm_to_smack_early(smack_early, app_id, APP_TYPE_OTHER, base_perm);
1269 if (ret != PC_OPERATION_SUCCESS){
1270 C_LOGE("perm_to_smack failed");
1275 for (i = 0; perm_list[i] != NULL; ++i) {
1276 SECURE_SLOGD("perm_to_smack params: app_id: %s, perm_list[%d]: %s", app_id, i, perm_list[i]);
1277 if (strcmp(perm_list[i], TIZEN_PRIVILEGE_ANTIVIRUS) == 0) {
1278 ret = app_register_av_internal(app_id, smack);
1279 if (ret != PC_OPERATION_SUCCESS) {
1280 C_LOGE("app_register_av_internal failed");
1284 if (strcmp(perm_list[i], TIZEN_PRIVILEGE_APPSETTING) == 0) {
1285 ret = app_register_appsetting(app_id, smack);
1286 if (ret != PC_OPERATION_SUCCESS) {
1287 C_LOGE("app_register_appsetting failed");
1292 ret = perm_to_smack(smack, app_id, app_type, perm_list[i]);
1293 if (ret != PC_OPERATION_SUCCESS){
1294 C_LOGE("perm_to_smack failed");
1298 ret = perm_to_smack_early(smack_early, app_id, app_type, perm_list[i]);
1299 if (ret != PC_OPERATION_SUCCESS){
1300 C_LOGE("perm_to_smack_early failed");
1304 ret = perm_to_dac(app_id, app_type, perm_list[i]);
1305 if (ret != PC_OPERATION_SUCCESS){
1306 C_LOGE("perm_to_dac failed");
1311 if (have_smack() && smack_accesses_apply(smack)) {
1312 C_LOGE("smack_accesses_apply failed");
1313 return PC_ERR_INVALID_OPERATION;
1316 if (have_smack() && smack_accesses_apply(smack_early)) {
1317 C_LOGE("smack_accesses_apply (early) failed");
1318 return PC_ERR_INVALID_OPERATION;
1321 if (permanent && smack_accesses_save(smack, fd)) {
1322 C_LOGE("smack_accesses_save failed");
1323 return PC_ERR_INVALID_OPERATION;
1326 if (permanent && smack_accesses_save(smack_early, fd_early)) {
1327 C_LOGE("smack_accesses_save (early) failed");
1328 return PC_ERR_INVALID_OPERATION;
1331 return PC_OPERATION_SUCCESS;
1334 API int app_add_permissions(const char* app_id, const char** perm_list)//deprecated
1336 C_LOGD("Enter function: %s", __func__);
1337 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 1);
1340 API int app_add_volatile_permissions(const char* app_id, const char** perm_list)//deprecated
1342 C_LOGD("Enter function: %s", __func__);
1343 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 0);
1346 API int app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)//deprecated
1348 C_LOGD("Enter function: %s", __func__);
1349 return app_add_permissions_internal(pkg_id, app_type, perm_list, persistent);
1352 API int perm_app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)
1354 C_LOGD("Enter function: %s", __func__);
1355 return app_add_permissions_internal(pkg_id, app_type, perm_list, persistent);
1358 API int app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)//deprecated
1360 return perm_app_disable_permissions(pkg_id, app_type, perm_list);
1363 /* FIXME: this function is only a stub */
1364 API int perm_app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)
1366 C_LOGD("Enter function: %s", __func__);
1367 return PC_OPERATION_SUCCESS;
1370 static int app_revoke_permissions_internal(const char* app_id, bool persistent)
1372 C_LOGD("Enter function: %s", __func__);
1373 char* smack_path AUTO_FREE;
1376 struct smack_accesses *smack AUTO_SMACK_FREE;
1378 if (!smack_label_is_valid(app_id))
1379 return PC_ERR_INVALID_PARAM;
1381 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1382 if (ret != PC_OPERATION_SUCCESS) {
1383 C_LOGE("load_smack_from_file failed");
1387 if (have_smack() && smack_accesses_clear(smack)) {
1388 ret = PC_ERR_INVALID_OPERATION;
1389 C_LOGE("smack_accesses_clear failed");
1393 if (have_smack() && smack_revoke_subject(app_id)) {
1394 ret = PC_ERR_INVALID_OPERATION;
1395 C_LOGE("smack_revoke_subject failed");
1399 if (persistent && ftruncate(fd, 0) == -1)
1400 C_LOGW("file truncation failed");
1402 return PC_OPERATION_SUCCESS;
1405 API int app_revoke_permissions(const char* pkg_id)//deprecated
1407 return perm_app_revoke_permissions(pkg_id);
1410 API int perm_app_revoke_permissions(const char* pkg_id)
1412 C_LOGD("Enter function: %s", __func__);
1415 if (!smack_label_is_valid(pkg_id))
1416 return PC_ERR_INVALID_PARAM;
1418 ret = app_revoke_permissions_internal(pkg_id, true);
1420 C_LOGE("Revoking permissions failed");
1424 return PC_OPERATION_SUCCESS;
1427 API int app_reset_permissions(const char* pkg_id)//deprecated
1429 return perm_app_reset_permissions(pkg_id);
1432 API int perm_app_reset_permissions(const char* pkg_id)
1434 C_LOGD("Enter function: %s", __func__);
1437 if (!smack_label_is_valid(pkg_id))
1438 return PC_ERR_INVALID_PARAM;
1440 ret = app_revoke_permissions_internal(pkg_id, false);
1442 C_LOGE("Revoking permissions failed");
1446 /* Add empty permissions set to trigger re-read of rules */
1447 return perm_app_enable_permissions(pkg_id, APP_TYPE_OTHER, (const char*[]){NULL}, 0);
1450 API int app_label_dir(const char* label, const char* path)//deprecated
1452 C_LOGD("Enter function: %s", __func__);
1454 int ret = PC_OPERATION_SUCCESS;
1457 C_LOGE("Invalid argument path (NULL).");
1458 return PC_ERR_INVALID_PARAM;
1461 if (!smack_label_is_valid(label))
1462 return PC_ERR_INVALID_PARAM;
1464 //setting access label on everything in given directory and below
1465 ret = dir_set_smack_r(path, label, SMACK_LABEL_ACCESS, &label_all);
1466 if (PC_OPERATION_SUCCESS != ret)
1469 //setting execute label for everything with permission to execute
1470 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_execs);
1471 if (PC_OPERATION_SUCCESS != ret)
1474 //setting execute label for everything with permission to execute
1475 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_links_to_execs);
1479 int smack_get_access_new(const char* subject, const char* object, char** label)
1481 char buff[ACC_LEN] = {'r', 'w', 'x', 'a', 't'};
1482 char perm[2] = {'-'};
1485 if(!smack_label_is_valid(subject) || !smack_label_is_valid(object) || !label)
1486 return PC_ERR_INVALID_PARAM;
1488 for (i=0; i<ACC_LEN; ++i) {
1490 int ret = smack_have_access(subject, object, perm);
1492 return PC_ERR_INVALID_OPERATION;
1497 *label = malloc(ACC_LEN+1);
1499 return PC_ERR_MEM_OPERATION;
1501 memcpy(*label, buff, ACC_LEN);
1502 (*label)[ACC_LEN] = 0;
1503 return PC_OPERATION_SUCCESS;
1506 static int app_uninstall_remove_early_rules(const char *app_id)
1508 C_LOGD("Enter function: %s(%s)", __func__, app_id);
1514 char *data, *data_end;
1515 char *line_begin, *line_end, *write_pos;
1516 char subject[SMACK_LABEL_LEN + 1];
1517 char object[SMACK_LABEL_LEN + 1];
1519 fd = open(SMACK_STARTUP_RULES_FILE, O_RDWR);
1521 C_LOGE("Unable to open file %s: %s", SMACK_STARTUP_RULES_FILE, strerror(errno));
1522 return PC_ERR_FILE_OPERATION;
1525 if (flock(fd, LOCK_EX)) {
1526 C_LOGE("flock failed, error %s", strerror(errno));
1527 return PC_ERR_FILE_OPERATION;
1530 size = lseek(fd, 0, SEEK_END);
1532 C_LOGE("Unable to read file %s: %s", SMACK_STARTUP_RULES_FILE, strerror(errno));
1533 return PC_ERR_FILE_OPERATION;
1537 return PC_OPERATION_SUCCESS;
1539 data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1540 if (data == MAP_FAILED) {
1541 C_LOGE("Unable to read file %s: %s", SMACK_STARTUP_RULES_FILE, strerror(errno));
1542 return PC_ERR_FILE_OPERATION;
1544 data_end = data + size;
1546 line_begin = write_pos = data;
1547 while (line_begin < data_end) {
1548 line_end = memchr(line_begin, '\n', data_end - line_begin);
1549 if (line_end == NULL)
1550 line_end = data_end - 1;
1554 C_LOGD("Considering early rule: %s", line_begin);
1556 ret = sscanf(line_begin, "%" TOSTRING(SMACK_LABEL_LEN) "s %" TOSTRING(SMACK_LABEL_LEN) "s", subject, object);
1558 C_LOGD("Rule format is invalid, skipping it.");
1562 if (!strcmp(subject, app_id) || !strcmp(object, app_id)) {
1563 C_LOGD("Rule belongs to an app being removed, skipping it.");
1567 C_LOGD("Rule still needed, keeping it.");
1569 if (write_pos != line_begin)
1570 memcpy(write_pos, line_begin, line_end - line_begin + 1);
1571 write_pos += (line_end - line_begin + 1);
1575 line_begin = line_end + 1;
1579 ret = ftruncate(fd, write_pos - data);
1581 C_LOGE("Unable to truncate file %s to %d bytes: %s", SMACK_STARTUP_RULES_FILE, write_pos, strerror(errno));
1583 return PC_ERR_FILE_OPERATION;
1586 return PC_OPERATION_SUCCESS;
1589 API int app_label_shared_dir(const char* app_label, const char* shared_label, const char* path)//deprecated
1591 C_LOGD("Enter function: %s", __func__);
1596 C_LOGE("Invalid param path.");
1597 return PC_ERR_INVALID_PARAM;
1600 if (!smack_label_is_valid(app_label) || !smack_label_is_valid(shared_label))
1601 return PC_ERR_INVALID_PARAM;
1603 if (strcmp(app_label, shared_label) == 0) {
1604 C_LOGE("app_label equals shared_label");
1605 return PC_ERR_INVALID_PARAM;
1608 //setting label on everything in given directory and below
1609 ret = dir_set_smack_r(path, shared_label, SMACK_LABEL_ACCESS, label_all);
1610 if(ret != PC_OPERATION_SUCCESS){
1611 C_LOGE("dir_set_smack_r failed");
1615 //setting transmute on dir
1616 ret = dir_set_smack_r(path, "1", SMACK_LABEL_TRANSMUTE, label_dirs);
1617 if (ret != PC_OPERATION_SUCCESS) {
1618 C_LOGE("dir_set_smack_r failed");
1622 ret = app_add_rule(app_label, shared_label, "rwxat");
1623 if (ret != PC_OPERATION_SUCCESS) {
1624 C_LOGE("app_add_rule failed");
1628 return PC_OPERATION_SUCCESS;
1631 API int add_shared_dir_readers(const char* shared_label, const char** app_list)//deprecated
1633 C_LOGD("Enter function: %s", __func__);
1637 if(app_list == NULL) {
1638 C_LOGE("Invalid param app_list.");
1639 return PC_ERR_INVALID_PARAM;
1642 if (!smack_label_is_valid(shared_label))
1643 return PC_ERR_INVALID_PARAM;
1645 for (i = 0; app_list[i] != NULL; i++) {
1647 if (!smack_label_is_valid(app_list[i]))
1648 return PC_ERR_INVALID_PARAM;
1650 ret = app_add_rule(app_list[i], shared_label, "rx");
1651 if (ret != PC_OPERATION_SUCCESS) {
1652 C_LOGE("app_add_rule failed");
1657 return PC_OPERATION_SUCCESS;
1660 static char* smack_label_for_path(const char *app_id, const char *path)
1662 C_LOGD("Enter function: %s", __func__);
1663 char *salt AUTO_FREE;
1667 /* Prefix $1$ causes crypt() to use MD5 function */
1668 if (-1 == asprintf(&salt, "$1$%s", app_id)) {
1669 C_LOGE("asprintf failed");
1673 label = crypt(path, salt);
1674 if (label == NULL) {
1675 C_LOGE("crypt failed");
1679 /* crypt() output may contain slash character,
1680 * which is not legal in Smack labels */
1681 for (x = label; *x; ++x) {
1689 * This function should be called in perm_app_setup_path_internal().
1690 * After installation of new application (pkg_id) and labeling its shared directory (RW or RO),
1691 * all others apps installed in system should get rules to this shared directory.
1692 * This function will add and store those rules in rule-file of new installed app (pkg_id)
1694 static int add_other_apps_rules_for_shared_dir(const char *pkg_id, const char *type_of_shared_dir, const char *shared_dir_label)
1696 C_LOGD("Enter function: %s", __func__);
1700 char *smack_path AUTO_FREE;
1701 char *smack_rules_file_path AUTO_FREE;
1702 struct smack_accesses* smack AUTO_SMACK_FREE;
1704 ret = load_smack_from_file(pkg_id, &smack, &fd, &smack_path);
1705 if (ret != PC_OPERATION_SUCCESS ) {
1706 C_LOGE("load_smack_from_file failed: %d", ret);
1710 ret = asprintf(&smack_rules_file_path, TOSTRING(SHAREDIR)"/%s", type_of_shared_dir);
1712 C_LOGE("asprintf failed");
1713 return PC_ERR_MEM_OPERATION;
1716 ret = perm_to_smack_from_file(smack, shared_dir_label, SMACK_SHARED_DIR_LABEL_TEMPLATE, smack_rules_file_path);
1717 if (ret != PC_OPERATION_SUCCESS ) {
1718 C_LOGE("perm_to_smack_from_file failed: %d", ret);
1721 if (have_smack() && smack_accesses_apply(smack)) {
1722 C_LOGE("smack_accesses_apply failed");
1723 return PC_ERR_INVALID_OPERATION;
1726 if (smack_accesses_save(smack, fd)) {
1727 C_LOGE("smack_accesses_save failed");
1728 return PC_ERR_INVALID_OPERATION;
1731 return PC_OPERATION_SUCCESS;
1734 /* FIXME: remove this pragma once deprecated API is deleted */
1735 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1736 static int perm_app_setup_path_internal(const char* pkg_id, const char* path, app_path_type_t app_path_type, va_list ap)
1738 C_LOGD("Enter function: %s", __func__);
1741 C_LOGE("Invalid argument path.");
1742 return PC_ERR_INVALID_PARAM;
1745 if (!smack_label_is_valid(pkg_id)) {
1746 SECURE_SLOGE("Invalid app_id %s", pkg_id);
1747 return PC_ERR_INVALID_PARAM;
1750 switch (app_path_type) {
1751 case APP_PATH_PRIVATE:
1752 return app_label_dir(pkg_id, path);
1754 case APP_PATH_GROUP_RW: {
1755 const char *shared_label;
1758 shared_label = va_arg(ap, const char *);
1760 if (!smack_label_is_valid(shared_label)) {
1761 C_LOGE("Invalid shared_label %s", shared_label);
1762 return PC_ERR_INVALID_PARAM;
1765 if (strcmp(pkg_id, shared_label) == 0) {
1766 C_LOGE("app_id equals shared_label");
1767 return PC_ERR_INVALID_PARAM;
1770 ret = app_label_shared_dir(pkg_id, shared_label, path);
1771 if (ret != PC_OPERATION_SUCCESS) {
1772 C_LOGE("app_label_shared_dir failed: %d", ret);
1776 return add_other_apps_rules_for_shared_dir(pkg_id, PATH_RULES_GROUP_RW, shared_label);
1779 case APP_PATH_PUBLIC_RO: {
1780 char **app_ids AUTO_FREE;
1781 int app_ids_cnt = 0;
1785 C_LOGD("New public RO path %s", path);
1786 label = smack_label_for_path(pkg_id, path);
1788 return PC_ERR_INVALID_OPERATION;
1790 C_LOGD("Generated label '%s' for public RO path %s", label, path);
1791 ret = app_label_shared_dir(pkg_id, label, path);
1792 if (ret != PC_OPERATION_SUCCESS)
1795 /* FIXME: This should be in some kind of transaction/lock */
1796 ret = db_add_public_dir(label);
1797 if (ret != PC_OPERATION_SUCCESS)
1800 ret = get_all_apps_ids(&app_ids, &app_ids_cnt);
1801 if (ret != PC_OPERATION_SUCCESS)
1804 for (i = 0; i < app_ids_cnt; ++i) {
1805 SECURE_SLOGD("Allowing app %s to access public path %s", app_ids[i], path);
1806 ret = app_add_rule(app_ids[i], label, "rx");
1807 if (ret != PC_OPERATION_SUCCESS) {
1808 C_LOGE("smack_accesses_new failed");
1809 while (i < app_ids_cnt)
1816 return add_other_apps_rules_for_shared_dir(pkg_id, PATH_RULES_PUBLIC_RO, label);
1819 case APP_PATH_SETTINGS_RW:
1821 char **app_ids AUTO_FREE;
1822 int app_ids_cnt = 0;
1828 label = smack_label_for_path(pkg_id, path);
1830 return PC_ERR_INVALID_OPERATION;
1832 /*set id for path and all subfolders*/
1833 C_LOGD("Appsetting: generated label '%s' for setting path %s", label, path);
1834 ret = app_label_shared_dir(pkg_id, label, path);
1835 if (ret != PC_OPERATION_SUCCESS) {
1836 C_LOGE("Appsetting: app_label_shared_dir failed (%d)", ret);
1840 /* add path to database */
1841 /* FIXME: This should be in some kind of transaction/lock */
1842 ret = add_setting_dir_id_to_databse(label);
1843 if (ret != PC_OPERATION_SUCCESS) {
1844 C_LOGE("Appsetting: add_setting_dir_id_to_databse failed");
1848 /*read all apps with appsetting privilege*/
1849 ret = get_all_appsetting_ids(&app_ids, &app_ids_cnt);
1850 if (ret != PC_OPERATION_SUCCESS) {
1851 C_LOGE("Appsetting: get_all_appsetting_ids failed");
1854 C_LOGD("Appsetting: %d appsetting privileged apps registered",
1857 /*give RWX rights to all apps that have appsetting privilege*/
1858 for (i = 0; i < app_ids_cnt; ++i) {
1859 C_LOGD("Appsetting: allowing app %s to access setting path %s",
1861 ret = app_add_rule(app_ids[i], label, "rwx");
1862 if (ret != PC_OPERATION_SUCCESS) {
1863 C_LOGE("app_add_rule failed");
1864 while (i < app_ids_cnt)
1871 return PC_OPERATION_SUCCESS;
1874 case APP_PATH_ANY_LABEL: {
1875 const char *label = NULL;
1876 label = va_arg(ap, const char *);
1877 return app_label_dir(label, path);
1881 return PC_ERR_INVALID_PARAM;
1884 return PC_OPERATION_SUCCESS;
1886 /* FIXME: remove this pragma once deprecated API is deleted */
1887 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
1889 API int app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)//deprecated
1893 va_start( ap, app_path_type );
1894 ret = perm_app_setup_path_internal( pkg_id, path, app_path_type, ap );
1900 API int perm_app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)
1904 va_start( ap, app_path_type );
1905 ret = perm_app_setup_path_internal( pkg_id, path, app_path_type, ap );
1912 API int app_add_friend(const char* pkg_id1, const char* pkg_id2)//deprecated
1914 return perm_app_add_friend(pkg_id1, pkg_id2);
1917 API int perm_app_add_friend(const char* pkg_id1, const char* pkg_id2)
1919 C_LOGD("Enter function: %s", __func__);
1922 if (!smack_label_is_valid(pkg_id1) || !smack_label_is_valid(pkg_id2))
1923 return PC_ERR_INVALID_PARAM;
1925 ret = app_add_rule(pkg_id1, pkg_id2, "rwxat");
1926 if (ret != PC_OPERATION_SUCCESS) {
1927 C_LOGE("app_add_rule failed");
1931 ret = app_add_rule(pkg_id2, pkg_id1, "rwxat");
1932 if (ret != PC_OPERATION_SUCCESS) {
1933 C_LOGE("app_add_rule failed");
1937 return PC_OPERATION_SUCCESS;
1940 API int app_install(const char* pkg_id)//deprecated
1942 return perm_app_install(pkg_id);
1945 API int perm_app_install(const char* pkg_id)
1947 C_LOGD("Enter function: %s", __func__);
1950 char* smack_path AUTO_FREE;
1951 struct smack_accesses *smack AUTO_SMACK_FREE;
1953 if (!smack_label_is_valid(pkg_id))
1954 return PC_ERR_INVALID_PARAM;
1956 ret = smack_file_name(pkg_id, &smack_path);
1957 if (ret != PC_OPERATION_SUCCESS)
1960 ret = load_smack_from_file(pkg_id, &smack, &fd, &smack_path);
1961 if (ret != PC_OPERATION_SUCCESS) {
1962 C_LOGE("load_smack_from_file failed");
1966 ret = add_app_id_to_databse(pkg_id);
1967 if (ret != PC_OPERATION_SUCCESS ) {
1968 SECURE_SLOGE("Error while adding app %s to database: %s ", pkg_id, strerror(errno));
1972 ret = register_app_for_av(pkg_id);
1973 if (ret != PC_OPERATION_SUCCESS) {
1974 SECURE_SLOGE("Error while adding rules for anti viruses to app %s: %s ", pkg_id, strerror(errno));
1978 ret = register_app_for_appsetting(pkg_id);
1979 if (ret != PC_OPERATION_SUCCESS) {
1980 SECURE_SLOGE("Error while adding rules for setting managers to app %s: %s ", pkg_id, strerror(errno));
1984 ret = register_app_for_public_dirs(pkg_id, smack);
1985 if (ret != PC_OPERATION_SUCCESS) {
1986 SECURE_SLOGE("Error while adding rules for access to public dirs for app %s: %s ", pkg_id, strerror(errno));
1990 if (have_smack() && smack_accesses_apply(smack)) {
1991 C_LOGE("smack_accesses_apply failed");
1992 return PC_ERR_INVALID_OPERATION;
1995 if (smack_accesses_save(smack, fd)) {
1996 C_LOGE("smack_accesses_save failed");
1997 return PC_ERR_INVALID_OPERATION;
2000 return PC_OPERATION_SUCCESS;
2003 API int app_uninstall(const char* pkg_id)//deprecated
2005 return perm_app_uninstall(pkg_id);
2008 API int perm_app_uninstall(const char* pkg_id)
2010 // TODO: When real database will be used, then this function should remove app_id
2012 // It also should remove rules like: "anti_virus_label app_id rwx".
2013 C_LOGD("Enter function: %s", __func__);
2014 char* smack_path AUTO_FREE;
2017 if (!smack_label_is_valid(pkg_id))
2018 return PC_ERR_INVALID_PARAM;
2020 ret = smack_file_name(pkg_id, &smack_path);
2021 if (ret != PC_OPERATION_SUCCESS)
2024 if (unlink(smack_path)) {
2025 C_LOGE("unlink failed: ", strerror(errno));
2026 return PC_OPERATION_SUCCESS;
2029 ret = app_uninstall_remove_early_rules(pkg_id);
2030 if (ret != PC_OPERATION_SUCCESS)
2034 return PC_OPERATION_SUCCESS;
2037 static int save_rules(int fd, struct smack_accesses* accesses) {
2038 if (flock(fd, LOCK_EX)) {
2039 C_LOGE("flock failed, error %s", strerror(errno));
2040 return PC_ERR_FILE_OPERATION;
2043 if (smack_accesses_save(accesses, fd)) {
2044 C_LOGE("smack_accesses_save failed");
2045 return PC_ERR_FILE_OPERATION;
2047 return PC_OPERATION_SUCCESS ;
2050 static int validate_and_add_rule(char* rule, struct smack_accesses* accesses) {
2051 const char* subject = NULL;
2052 const char* object = NULL;
2053 const char* access = NULL;
2054 char* saveptr = NULL;
2056 subject = strtok_r(rule, " \t\n", &saveptr);
2057 object = strtok_r(NULL, " \t\n", &saveptr);
2058 access = strtok_r(NULL, " \t\n", &saveptr);
2060 // check rule validity
2061 if (subject == NULL ||
2064 strtok_r(NULL, " \t\n", &saveptr) != NULL ||
2065 !smack_label_is_valid(subject) ||
2066 !smack_label_is_valid(object))
2068 C_LOGE("Incorrect rule format: %s", rule);
2069 return PC_ERR_INVALID_PARAM;
2072 if (smack_accesses_add_modify(accesses, subject, object, access, "")) {
2073 C_LOGE("smack_accesses_add_modify failed");
2074 return PC_ERR_INVALID_OPERATION;
2076 return PC_OPERATION_SUCCESS ;
2079 static int parse_and_save_rules(const char** smack_rules,
2080 struct smack_accesses* accesses, const char* feature_file) {
2083 int ret = PC_OPERATION_SUCCESS;
2086 for (i = 0; smack_rules[i] != NULL ; i++) {
2087 // ignore empty lines
2088 if (strspn(smack_rules[i], " \t\n") == strlen(smack_rules[i]))
2091 tmp = strdup(smack_rules[i]);
2092 ret = validate_and_add_rule(tmp, accesses);
2094 if (ret != PC_OPERATION_SUCCESS )
2099 fd = open(feature_file, O_CREAT | O_WRONLY, 0644);
2101 C_LOGE("Unable to create file %s. Error: %s", feature_file, strerror(errno));
2102 return PC_ERR_FILE_OPERATION;
2105 ret = save_rules(fd, accesses);
2110 static int save_gids(FILE* file, const gid_t* list_of_db_gids, size_t list_size) {
2111 int ret = PC_OPERATION_SUCCESS;
2116 C_LOGE("Unable to create file. Error: %s", strerror(errno));
2117 return PC_ERR_FILE_OPERATION; // TODO remove smack accesses?
2120 if(-1 == fchmod(fileno(file), 0644)) {
2121 C_LOGE("Unable to chmod file. Error: %s", strerror(errno));
2122 return PC_ERR_FILE_OPERATION;
2125 for (i = 0; i < list_size ; ++i) {
2126 written = fprintf(file, "%u\n", list_of_db_gids[i]);
2128 C_LOGE("fprintf failed for file. Error: %s", strerror(errno));
2129 ret = PC_ERR_FILE_OPERATION;
2136 API int add_api_feature(app_type_t app_type,
2137 const char* api_feature_name,
2138 const char** smack_rules,
2139 const gid_t* list_of_db_gids,
2140 size_t list_size)//deprecated
2142 return perm_add_api_feature(app_type, api_feature_name, smack_rules, list_of_db_gids, list_size);
2145 API int perm_add_api_feature(app_type_t app_type,
2146 const char* api_feature_name,
2147 const char** smack_rules,
2148 const gid_t* list_of_db_gids,
2150 C_LOGD("Enter function: %s", __func__);
2152 int ret = PC_OPERATION_SUCCESS;
2153 char* smack_file AUTO_FREE;
2154 char* dac_file AUTO_FREE;
2155 struct smack_accesses* accesses = NULL;
2158 // TODO check process capabilities
2160 // get feature SMACK file name
2161 ret = perm_file_path(&smack_file, app_type, api_feature_name, ".smack", 0);
2162 if (ret != PC_OPERATION_SUCCESS || !smack_file ) {
2166 // check if feature exists
2167 if (file_exists(smack_file)) {
2168 C_LOGE("Feature file %s already exists", smack_file);
2169 return PC_ERR_INVALID_PARAM;
2172 // check .dac existence only if gids are supported
2173 if (list_of_db_gids && list_size > 0) {
2174 // get feature DAC file name
2175 ret = perm_file_path(&dac_file, app_type, api_feature_name, ".dac", 0);
2176 if (ret != PC_OPERATION_SUCCESS || !dac_file ) {
2180 // check if feature exists
2181 if (file_exists(dac_file)) {
2182 C_LOGE("Feature file %s already exists", dac_file);
2183 return PC_ERR_INVALID_PARAM;
2187 // parse & save rules
2189 if (smack_accesses_new(&accesses)) {
2190 C_LOGE("smack_acceses_new failed");
2191 return PC_ERR_MEM_OPERATION;
2194 ret = parse_and_save_rules(smack_rules, accesses, smack_file);
2195 smack_accesses_free(accesses);
2198 // go through gid list
2199 if (ret == PC_OPERATION_SUCCESS && list_of_db_gids && list_size > 0) {
2201 file = fopen(dac_file, "w+");
2202 ret = save_gids(file, list_of_db_gids, list_size);
2206 // remove both files in case of failure
2207 if (ret != PC_OPERATION_SUCCESS) {
2218 * This function is marked as deprecated and will be removed
2220 API int app_register_av(const char* app_av_id)//deprecated
2224 char* smack_path AUTO_FREE;
2225 struct smack_accesses* smack AUTO_SMACK_FREE;
2227 if(app_av_id == NULL) {
2228 C_LOGE("Invalid param app_av_id.");
2229 return PC_ERR_INVALID_PARAM;
2232 ret = load_smack_from_file(app_av_id, &smack, &fd, &smack_path);
2233 if (ret != PC_OPERATION_SUCCESS ) {
2234 C_LOGE("load_smack_from_file failed");
2238 ret = app_register_av_internal(app_av_id, smack);
2239 if (PC_OPERATION_SUCCESS != ret) {
2240 C_LOGE("app_register_av_internal failed");
2244 // Add permisions from OSP_antivirus.smack file
2245 ret = perm_to_smack(smack, app_av_id, APP_TYPE_OSP, TIZEN_PRIVILEGE_ANTIVIRUS);
2246 if (PC_OPERATION_SUCCESS != ret) {
2247 C_LOGE("perm_to_smack failed");
2251 // Add permisions from OSP_antivirus.dac file
2252 ret = perm_to_dac(app_av_id, APP_TYPE_OSP, TIZEN_PRIVILEGE_ANTIVIRUS);
2253 if (ret != PC_OPERATION_SUCCESS) {
2254 C_LOGE("perm_to_dac failed");
2258 if (have_smack() && smack_accesses_apply(smack)) {
2259 C_LOGE("smack_accesses_apply failed");
2260 ret = PC_ERR_INVALID_OPERATION;
2264 if (smack_accesses_save(smack, fd)) {
2265 C_LOGE("smack_accesses_save failed");
2266 ret = PC_ERR_INVALID_OPERATION;