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_RULES_DIR "/opt/etc/smack/accesses.d/"
64 #define SMACK_LOADED_APP_RULES "/var/run/smack-app/"
66 #define SMACK_APP_LABEL_TEMPLATE "~APP~"
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"
86 typedef struct state_node_t {
90 static void *state_tree = NULL;
98 typedef int (*label_decision_fn)(const FTSENT*);
104 static int load_smack_from_file(const char* app_id, struct smack_accesses** smack, int *fd, char** path);
105 static bool file_exists(const char* path);
107 int state_tree_cmp(const void *first, const void *second)
109 return strcmp(((state_node*)first)->key,
110 ((state_node*)second)->key);
113 int state_tree_push(const char* key_param, const char* value_param)
115 state_node *node = malloc(sizeof(state_node));
116 char *key = strdup(key_param);
117 char *value = strdup(value_param);
119 if (!node || !key || !value) {
123 return PC_ERR_MEM_OPERATION;
129 if (NULL != tfind(node, &state_tree, state_tree_cmp)){
133 return PC_OPERATION_SUCCESS; // 04.2013 Temporary fix. Allow for multiple call of app_give_access
136 tsearch(node, &state_tree, state_tree_cmp);
137 return PC_OPERATION_SUCCESS;
140 char* state_tree_pop_new(char *key)
142 state_node search, *node;
148 wtf = tfind(&search, &state_tree, state_tree_cmp);
152 node = *(state_node**)wtf;
156 tdelete(node, &state_tree, state_tree_cmp);
164 int state_save(const char *subject, const char *object, const char *perm)
167 if (-1 == asprintf(&key, "%s|%s", subject, object)) {
168 C_LOGE("Error in %s: asprintf failed.", __func__);
169 return PC_ERR_INVALID_OPERATION;
171 int ret = state_tree_push(key, perm);
176 int state_restore(const char* subject, const char* object)
179 char *perm AUTO_FREE;
180 struct smack_accesses *smack AUTO_SMACK_FREE;
182 if (-1 == asprintf(&key, "%s|%s", subject, object)) {
183 C_LOGE("Error in %s: asprintf failed.", __func__);
184 return PC_ERR_INVALID_OPERATION;
187 perm = state_tree_pop_new(key);
189 C_LOGE("Error in %s: state_tree_pop_new failed - no data for subject=%s object=%s.", __func__, subject, object);
190 return PC_ERR_INVALID_OPERATION;
193 if (smack_accesses_new(&smack)) {
194 C_LOGE("Error in %s: smack_accesses_new failed - memory error.", __func__);
195 return PC_ERR_MEM_OPERATION;
198 if (smack_accesses_add(smack, subject, object, perm)) {
199 C_LOGE("Error in %s: smack_accesses_add failed.", __func__);
200 return PC_ERR_MEM_OPERATION;
203 if (smack_accesses_apply(smack)) {
204 C_LOGE("Error in %s: smack_accesses_apply failed - operation not permitted.", __func__);
205 return PC_ERR_NOT_PERMITTED;
208 return PC_OPERATION_SUCCESS;
211 static inline int have_smack(void)
213 static int have_smack = -1;
215 if (-1 == have_smack) {
216 if (NULL == smack_smackfs_path()) {
217 C_LOGD("Libprivilage-control: no smack found on phone");
220 C_LOGD("Libprivilege-control: found smack on phone");
228 API int control_privilege(void)
230 C_LOGD("Enter function: %s", __func__);
231 if(getuid() == APP_UID) // current user is 'app'
232 return PC_OPERATION_SUCCESS;
234 if(set_app_privilege("org.tizen.", NULL, NULL) == PC_OPERATION_SUCCESS)
235 return PC_OPERATION_SUCCESS;
237 return PC_ERR_NOT_PERMITTED;
240 static int smack_mark_file_name(const char *app_id, char **path)
242 if (asprintf(path, SMACK_LOADED_APP_RULES "/%s", app_id) == -1) {
243 C_LOGE("asprintf failed");
245 return PC_ERR_MEM_OPERATION;
248 return PC_OPERATION_SUCCESS;
252 * TODO: this function should be moved to libsmack in open-source.
254 API int get_smack_label_from_process(pid_t pid, char smack_label[SMACK_LABEL_LEN + 1])
256 C_LOGD("Enter function: %s", __func__);
259 int PATH_MAX_LEN = 64;
260 char path[PATH_MAX_LEN + 1];
263 ret = PC_ERR_INVALID_PARAM;
267 bzero(smack_label, SMACK_LABEL_LEN + 1);
268 if (!have_smack()) { // If no smack just return success with empty label
269 C_LOGD("No SMACK. Return empty label");
270 ret = PC_OPERATION_SUCCESS;
274 bzero(path, PATH_MAX_LEN + 1);
275 snprintf(path, PATH_MAX_LEN, "/proc/%d/attr/current", pid);
276 fd = open(path, O_RDONLY);
278 C_LOGE("cannot open file %s (errno: %s)", path, strerror(errno));
279 ret = PC_ERR_FILE_OPERATION;
283 ret = read(fd, smack_label, SMACK_LABEL_LEN);
285 C_LOGE("cannot read from file %s", path);
286 ret = PC_ERR_FILE_OPERATION;
290 ret = PC_OPERATION_SUCCESS;
296 API int smack_pid_have_access(pid_t pid,
298 const char *access_type)
300 C_LOGD("Enter function: %s", __func__);
302 char pid_subject_label[SMACK_LABEL_LEN + 1];
304 cap_flag_value_t cap_v;
307 C_LOGD("No SMACK. Return access granted");
311 if (pid < 0 || object == NULL || strlen(object) == 0 ||
312 access_type == NULL || strlen(access_type) == 0) {
313 C_LOGE("Invalid param");
317 //get SMACK label of process
318 ret = get_smack_label_from_process(pid, pid_subject_label);
319 if (PC_OPERATION_SUCCESS != ret) {
320 C_LOGE("get_smack_label_from_process %d failed: %d", pid, ret);
323 C_LOGD("pid %d have label: %s", pid, pid_subject_label);
325 // if read empty label then do not call smack_have_access()
326 if (pid_subject_label[0] != '\0') {
327 ret = smack_have_access(pid_subject_label, object, access_type);
329 C_LOGE("smack_have_access failed");
332 if ( 1 == ret ) { // smack_have_access return 1 (access granted)
333 C_LOGD("smack_have_access return 1 (access granted)");
338 // smack_have_access return 0 (access denied). Now CAP_MAC_OVERRIDE should be checked
339 C_LOGD("smack_have_access return 0 (access denied)");
340 cap = cap_get_pid(pid);
342 C_LOGE("cap_get_pid failed");
345 ret = cap_get_flag(cap, CAP_MAC_OVERRIDE, CAP_EFFECTIVE, &cap_v);
347 C_LOGE("cap_get_flag failed");
351 if (cap_v == CAP_SET) {
352 C_LOGD("pid %d have CAP_MAC_OVERRIDE", pid);
356 C_LOGD("pid %d have no CAP_MAC_OVERRIDE", pid);
361 static int set_dac(const char *smack_label, const char *pkg_name)
363 C_LOGD("Enter function: %s", __func__);
364 FILE* fp_group = NULL; // /etc/group
365 uid_t t_uid = -1; // uid of current process
366 gid_t *glist = NULL; // group list
367 gid_t temp_gid = -1; // for group list
368 char buf[10] = {0, }; // contents in group_list file
369 int glist_cnt = 0; // for group list
373 unsigned *additional_gids = NULL;
376 * initialize user structure
378 C_LOGD("initialize user structure");
379 memset(usr.user_name, 0x00, 10);
380 memset(usr.home_dir, 0x00, 64);
381 memset(usr.group_list, 0x00, 64);
386 C_LOGD("Current uid is %d", t_uid);
388 if(t_uid == 0) // current user is 'root'
390 if(!strncmp(pkg_name, "developer", 9))
392 strncpy(usr.user_name, DEV_USER_NAME, sizeof(usr.user_name));
393 usr.uid = DEVELOPER_UID;
394 usr.gid = DEVELOPER_GID;
395 strncpy(usr.home_dir, DEV_HOME_DIR, sizeof(usr.home_dir));
396 strncpy(usr.group_list, DEV_GROUP_PATH, sizeof(usr.group_list));
400 strncpy(usr.user_name, APP_USER_NAME, sizeof(usr.user_name));
403 strncpy(usr.home_dir, APP_HOME_DIR, sizeof(usr.home_dir));
404 strncpy(usr.group_list, APP_GROUP_PATH, sizeof(usr.group_list));
408 * get group information
410 C_LOGD("get group information");
411 if(!(fp_group = fopen(usr.group_list, "r")))
413 C_LOGE("File open error: %s", usr.group_list);
414 result = PC_ERR_FILE_OPERATION; // return -1
418 while(fgets(buf, 10, fp_group) != NULL)
421 temp_gid = strtoul(buf, 0, 10);
422 if(errno != 0) // error occured during strtoul()
424 C_LOGE("Cannot change string to integer: %s", buf);
425 result = PC_ERR_INVALID_OPERATION;
429 glist = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + 1));
432 result = PC_ERR_MEM_OPERATION; // return -2
433 C_LOGE("Cannot allocate memory");
436 glist[glist_cnt] = temp_gid;
446 result = get_app_gids(smack_label, &additional_gids, &cnt);
447 if (result != PC_OPERATION_SUCCESS)
451 glist_new = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + cnt));
452 if (glist_new == NULL) {
453 result = PC_ERR_MEM_OPERATION; // return -2
454 C_LOGE("Cannot allocate memory");
458 for (i = 0; i < cnt; ++i) {
459 C_LOGD("Additional GID based on enabled permissions: %u", additional_gids[i]);
460 glist[glist_cnt++] = additional_gids[i];
468 C_LOGD("Adding process to the following groups:");
469 for(i=0; i<glist_cnt; ++i) {
470 C_LOGD("glist [ %d ] = %d", i, glist[i]);
472 C_LOGD("setgroups()");
473 if(setgroups(glist_cnt, glist) != 0)
475 C_LOGE("setgrouops fail");
476 result = PC_ERR_NOT_PERMITTED; // return -3
486 * setuid() & setgid()
488 C_LOGD("setgid( %d ) & setuid( %d )", usr.gid, usr.uid);
489 if(setgid(usr.gid) != 0) // fail
491 C_LOGE("Fail to execute setgid().");
492 result = PC_ERR_INVALID_OPERATION;
495 if(setuid(usr.uid) != 0) // fail
497 C_LOGE("Fail to execute setuid().");
498 result = PC_ERR_INVALID_OPERATION;
502 SECURE_LOGD("setenv(): USER = %s, HOME = %s", usr.user_name, usr.home_dir);
503 if(setenv("USER", usr.user_name, 1) != 0) //fail
505 C_LOGE("Fail to execute setenv() [USER].");
506 result = PC_ERR_INVALID_OPERATION;
509 if(setenv("HOME", usr.home_dir, 1) != 0) // fail
511 C_LOGE("Fail to execute setenv() [HOME].");
512 result = PC_ERR_INVALID_OPERATION;
516 else // current user is not only 'root' but 'app'
518 C_LOGE("Current user is NOT root");
519 result = PC_ERR_NOT_PERMITTED; // return -3
523 result = PC_OPERATION_SUCCESS;
530 free(additional_gids);
536 * Get SMACK label from EXEC label of a file.
537 * SMACK label should be free by caller
539 * @param path file path to take label from
540 * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
542 static int get_smack_from_binary(char **smack_label, const char* path, app_type_t type)
544 C_LOGD("Enter function: %s", __func__);
547 C_LOGD("Path: %s", path);
550 if (type == APP_TYPE_WGT
551 || type == APP_TYPE_WGT_PARTNER
552 || type == APP_TYPE_WGT_PLATFORM) {
553 ret = smack_lgetlabel(path, smack_label, SMACK_LABEL_EXEC);
555 ret = smack_getlabel(path, smack_label, SMACK_LABEL_EXEC);
558 C_LOGE("Getting exec label from file %s failed", path);
559 return PC_ERR_INVALID_OPERATION;
562 return PC_OPERATION_SUCCESS;
566 * Set process SMACK label.
567 * This function is emulating EXEC label behaviour of SMACK for programs
568 * run by dlopen/dlsym instead of execv.
571 * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
573 static int set_smack_for_self (char *smack_label)
575 C_LOGD("Enter function: %s", __func__);
578 if (smack_label == NULL) {
579 /* No label to set, just return with success */
580 C_LOGD("No label to set, just return with success");
581 ret = PC_OPERATION_SUCCESS;
584 C_LOGD("label = %s", smack_label);
586 ret = smack_set_label_for_self(smack_label);
587 C_LOGD("smack_set_label_for_self returned %d", ret);
589 ret = PC_OPERATION_SUCCESS;
595 static int is_widget(const char* path)
597 C_LOGD("Enter function: %s", __func__);
598 char buf[sizeof(WRT_CLIENT_PATH)];
601 ret = readlink(path, buf, sizeof(WRT_CLIENT_PATH));
603 C_LOGD("readlink(%s) returned error: %s. Assuming that app is not a widget", path, strerror(errno));
604 else if (ret == sizeof(WRT_CLIENT_PATH))
605 C_LOGD("%s is not a widget", path);
606 if (ret == -1 || ret == sizeof(WRT_CLIENT_PATH))
609 C_LOGD("buf = %s", buf);
611 ret = !strcmp(WRT_CLIENT_PATH, buf);
612 C_LOGD("%s is %s widget", path, ret ? "a" : "not a");
617 * Partially verify, that the type given for app is correct.
618 * This function will use some heuristics to check whether the app type is right.
619 * It is intended for security hardening to catch privilege setting for the
620 * app type not corresponding to the actual binary.
621 * Beware - when it detects an anomaly, the whole process will be terminated.
623 * @param type claimed application type
624 * @param path file path to executable
625 * @return return void on success, terminate the process on error
627 static app_type_t verify_app_type(const char* type, const char* path)
629 C_LOGD("Enter function: %s", __func__);
630 /* TODO: this should actually be treated as error, but until the old
631 * set_privilege API is removed, it must be ignored */
633 C_LOGD("PKG_TYPE_OTHER");
634 return APP_TYPE_OTHER; /* good */
637 if (is_widget(path)) {
638 if (!strcmp(type, "wgt")) {
639 C_LOGD("PKG_TYPE_WGT");
640 return APP_TYPE_WGT; /* good */
641 } else if (!strcmp(type, "wgt_partner")) {
642 C_LOGD("PKG_TYPE_WGT_PARTNER");
643 return APP_TYPE_WGT_PARTNER; /* good */
644 } else if (!strcmp(type, "wgt_platform")) {
645 C_LOGD("PKG_TYPE_WGT_PLATFORM");
646 return APP_TYPE_WGT_PLATFORM; /* good */
650 if (type == NULL || (strcmp(type, "wgt")
651 && strcmp(type, "wgt_partner")
652 && strcmp(type, "wgt_platform"))){
653 C_LOGD("PKG_TYPE_OTHER");
654 return APP_TYPE_OTHER; /* good */
659 C_LOGE("EXIT_FAILURE");
663 static int add_app_first_run_rules(const char *app_id)
665 C_LOGD("Enter function: %s", __func__);
668 char *smack_path AUTO_FREE;
669 struct smack_accesses* smack AUTO_SMACK_FREE;
671 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
672 if (ret != PC_OPERATION_SUCCESS) {
673 C_LOGE("Error while load_smack_from_file");
676 if (have_smack() && smack_accesses_apply(smack)) {
677 C_LOGE("smack_accesses_apply failed");
678 return PC_ERR_INVALID_OPERATION;
681 return PC_OPERATION_SUCCESS;
685 * This function check if application SMACK rules was already loaded
686 * by checking if specific file exist. This Function desn't create such file.
688 * 0 if rules weren't yet loaded,
689 * 1 if rules were loaded
690 * -1 if error occurs while checking
692 static int check_if_rules_were_loaded(const char *app_id)
694 C_LOGD("Enter function: %s", __func__);
696 char *path AUTO_FREE;
698 ret = smack_mark_file_name(app_id, &path);
699 if(PC_OPERATION_SUCCESS != ret) {
703 return file_exists(path);
707 * This function creates a (empty) file for app if rules for this app
710 static void mark_rules_as_loaded(const char *app_id)
713 char *path AUTO_FREE;
716 if(smack_mark_file_name(app_id, &path)) {
717 C_LOGW("Warning: smack_mark_file_name failed");
721 if (-1 == stat(SMACK_LOADED_APP_RULES, &s)) {
722 if (ENOENT == errno) {
723 C_LOGD("Creating dir %s", SMACK_LOADED_APP_RULES);
724 mkdir(SMACK_LOADED_APP_RULES, S_IRWXU | S_IRWXG | S_IRWXO);
728 file = fopen(path, "w");
732 API int set_app_privilege(const char* name, const char* type, const char* path)
734 C_LOGD("Enter function: %s", __func__);
735 SECURE_LOGD("Function params: name = %s, type = %s, path = %s", name, type, path);
736 int ret = PC_OPERATION_SUCCESS;
737 int were_rules_loaded = 0;
738 char *smack_label AUTO_FREE;
740 if (path != NULL && have_smack()) {
741 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
742 if (ret != PC_OPERATION_SUCCESS)
745 were_rules_loaded = check_if_rules_were_loaded(smack_label);
746 if (were_rules_loaded < 0) {
747 C_LOGE("Error while check_if_rules_was_loaded");
748 return PC_ERR_INVALID_OPERATION;
750 if (!were_rules_loaded) { // first run of application
751 C_LOGD("This is first run of this application. Adding SMACK rules");
752 ret = add_app_first_run_rules(smack_label);
753 if (ret != PC_OPERATION_SUCCESS ) {
754 C_LOGW("Warning: add_app_first_run_rules failed");
755 // should we return here with error code?
757 mark_rules_as_loaded(smack_label);
760 ret = set_smack_for_self(smack_label);
761 if (ret != PC_OPERATION_SUCCESS)
765 return set_dac(smack_label, name);
768 API int set_privilege(const char* pkg_name)
770 C_LOGD("Enter function: %s", __func__);
771 return set_app_privilege(pkg_name, NULL, NULL);
774 static inline const char* app_type_name(app_type_t app_type)
781 case APP_TYPE_WGT_PARTNER:
782 return "WRT_partner";
783 case APP_TYPE_WGT_PLATFORM:
784 return "WRT_platform";
785 case APP_TYPE_OSP_PARTNER:
786 return "OSP_partner";
787 case APP_TYPE_OSP_PLATFORM:
788 return "OSP_platform";
794 static inline const char* app_type_group_name(app_type_t app_type)
798 case APP_TYPE_WGT_PARTNER:
799 case APP_TYPE_WGT_PLATFORM:
802 case APP_TYPE_OSP_PARTNER:
803 case APP_TYPE_OSP_PLATFORM:
811 * This function changes permission URI to basename for file name.
812 * For e.g. from http://tizen.org/privilege/contact.read will be
813 * created basename : org.tizen.privilege.contact.read
816 static int base_name_from_perm(const char *perm, char **name) {
818 char *host_dot = NULL;
819 char *rest_slash = NULL;
822 ip = iri_parse(perm);
823 if (ip == NULL || ip->host == NULL) {
824 C_LOGE("Bad permission format : %s", perm);
826 return PC_ERR_INVALID_PARAM;
829 if (ip->path == NULL) {
835 host_dot = strrchr(ip->host, '.');
842 while ((rest_slash = strchr(ip->path, '/'))) {
846 ret = asprintf(name, "%s%s%s%s",
847 host_dot ? host_dot : "", host_dot ? "." : "",
848 ip->host ? ip->host : "", ip->path);
850 C_LOGE("asprintf failed");
852 return PC_ERR_MEM_OPERATION;
856 return PC_OPERATION_SUCCESS;
859 static int perm_file_path(char** path, app_type_t app_type, const char* perm, const char *suffix)
861 const char* app_type_prefix = NULL;
862 char* perm_basename = NULL;
865 if (perm == NULL || strlen(perm) == 0) {
866 C_LOGE("empty permission name");
867 return PC_ERR_INVALID_PARAM;
870 app_type_prefix = app_type_group_name(app_type);
872 ret = base_name_from_perm(perm, &perm_basename);
873 if (ret != PC_OPERATION_SUCCESS) {
874 C_LOGE("Couldn't get permission basename");
878 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s",
879 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
880 perm_basename, suffix);
882 C_LOGE("asprintf failed");
883 return PC_ERR_MEM_OPERATION;
886 C_LOGD("Path : %s", *path);
888 return PC_OPERATION_SUCCESS;
891 static bool file_exists(const char* path) {
892 FILE* file = fopen(path, "r");
900 static int perm_to_smack(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
902 C_LOGD("Enter function: %s", __func__);
904 char* path AUTO_FREE;
905 char* format_string AUTO_FREE;
906 FILE* file AUTO_FCLOSE;
907 char smack_subject[SMACK_LABEL_LEN + 1];
908 char smack_object[SMACK_LABEL_LEN + 1];
909 char smack_accesses[10];
911 // get file name for permission (devcap)
912 ret = perm_file_path(&path, app_type, perm, ".smack");
913 if (ret != PC_OPERATION_SUCCESS) {
914 C_LOGD("No smack config file for permission %s", perm);
918 if (asprintf(&format_string,"%%%ds %%%ds %%%lus\n",
919 SMACK_LABEL_LEN, SMACK_LABEL_LEN, (unsigned long)sizeof(smack_accesses)) == -1) {
920 C_LOGE("asprintf failed");
921 return PC_ERR_MEM_OPERATION;
924 file = fopen(path, "r");
925 C_LOGD("path = %s", path);
927 C_LOGW("fopen failed");
928 return PC_OPERATION_SUCCESS;
931 while (fscanf(file, format_string, smack_subject, smack_object, smack_accesses) == 3) {
932 if (!strcmp(smack_subject, SMACK_APP_LABEL_TEMPLATE))
933 strcpy(smack_subject, app_label);
935 if (!strcmp(smack_object, SMACK_APP_LABEL_TEMPLATE))
936 strcpy(smack_object, app_label);
938 C_LOGD("smack_accesses_add_modify (subject: %s, object: %s, access: %s)", smack_subject, smack_object, smack_accesses);
939 if (smack_accesses_add_modify(smack, smack_subject, smack_object, smack_accesses, "") != 0) {
940 C_LOGE("smack_accesses_add_modify failed");
941 return PC_ERR_INVALID_OPERATION;
945 return PC_OPERATION_SUCCESS;
948 static int perm_to_dac(const char* app_label, app_type_t app_type, const char* perm)
950 C_LOGD("Enter function: %s", __func__);
952 char* path AUTO_FREE;
953 FILE* file AUTO_FCLOSE;
956 ret = perm_file_path(&path, app_type, perm, ".dac");
957 if (ret != PC_OPERATION_SUCCESS) {
958 C_LOGD("No dac config file for permission %s", perm);
962 file = fopen(path, "r");
963 C_LOGD("path = %s", path);
965 C_LOGW("fopen failed");
966 return PC_OPERATION_SUCCESS;
969 while (fscanf(file, "%d\n", &gid) == 1) {
970 SECURE_LOGD("Adding app_id %s to group %d", app_label, gid);
971 ret = add_app_gid(app_label, gid);
972 if (ret != PC_OPERATION_SUCCESS) {
973 C_LOGE("sadd_app_gid failed");
978 return PC_OPERATION_SUCCESS;
981 static int label_all(const FTSENT* ftsent)
983 return DECISION_LABEL;
986 static int label_execs(const FTSENT* ftsent)
988 C_LOGD("Mode: %d", ftsent->fts_statp->st_mode);
989 // label only regular executable files
990 if (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR))
991 return DECISION_LABEL;
992 return DECISION_SKIP;
995 static int label_dirs(const FTSENT* ftsent)
997 // label only directories
998 if (S_ISDIR(ftsent->fts_statp->st_mode))
999 return DECISION_LABEL;
1000 return DECISION_SKIP;
1003 static int label_links_to_execs(const FTSENT* ftsent)
1006 char* target AUTO_FREE;
1008 // check if it's a link
1009 if ( !S_ISLNK(ftsent->fts_statp->st_mode))
1010 return DECISION_SKIP;
1012 target = realpath(ftsent->fts_path, NULL);
1014 C_LOGE("Getting link target for %s failed. Error %s", ftsent->fts_path, strerror(errno));
1015 return PC_ERR_FILE_OPERATION;
1017 if (-1 == stat(target, &buf)) {
1018 C_LOGE("stat failed for %s, error: %s",target, strerror(errno));
1019 return PC_ERR_FILE_OPERATION;
1021 // skip if link target is not a regular executable file
1022 if (buf.st_mode != (buf.st_mode | S_IXUSR | S_IFREG)) {
1023 C_LOGD("%s Is not a regular executable file. Skipping.", target);
1024 return DECISION_SKIP;
1027 return DECISION_LABEL;
1030 static int dir_set_smack_r(const char *path, const char* label,
1031 enum smack_label_type type, label_decision_fn fn)
1033 C_LOGD("Enter function: %s", __func__);
1034 const char* path_argv[] = {path, NULL};
1035 FTS *fts AUTO_FTS_CLOSE;
1039 fts = fts_open((char * const *) path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
1041 C_LOGE("fts_open failed");
1042 return PC_ERR_FILE_OPERATION;
1045 while ((ftsent = fts_read(fts)) != NULL) {
1046 /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
1047 if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
1048 C_LOGE("FTS_ERR error or failed stat(2) (FTS_NS)");
1049 return PC_ERR_FILE_OPERATION;
1057 if (ret == DECISION_LABEL) {
1058 C_LOGD("smack_lsetlabel (label: %s (type: %d), path: %s)", label, type, ftsent->fts_path);
1059 if (smack_lsetlabel(ftsent->fts_path, label, type) != 0) {
1060 C_LOGE("smack_lsetlabel failed");
1061 return PC_ERR_FILE_OPERATION;
1066 /* If last call to fts_read() set errno, we need to return error. */
1068 C_LOGE("Last errno: %s", strerror(errno));
1069 return PC_ERR_FILE_OPERATION;
1071 return PC_OPERATION_SUCCESS;
1074 API char* app_id_from_socket(int sockfd)
1076 C_LOGD("Enter function: %s", __func__);
1083 ret = smack_new_label_from_socket(sockfd, &app_id);
1085 C_LOGE("smack_new_label_from_socket failed");
1089 C_LOGD("app_id: %s", app_id);
1094 static int smack_file_name(const char* app_id, char** path)
1096 if (asprintf(path, SMACK_RULES_DIR "/%s", app_id) == -1) {
1097 C_LOGE("asprintf failed");
1099 return PC_ERR_MEM_OPERATION;
1102 return PC_OPERATION_SUCCESS;
1105 static int load_smack_from_file(const char* app_id, struct smack_accesses** smack, int *fd, char** path)
1107 C_LOGD("Enter function: %s", __func__);
1110 ret = smack_file_name(app_id, path);
1111 if (ret != PC_OPERATION_SUCCESS)
1114 if (smack_accesses_new(smack)) {
1115 C_LOGE("smack_accesses_new failed");
1116 return PC_ERR_MEM_OPERATION;
1119 *fd = open(*path, O_CREAT|O_RDWR, 0644);
1121 C_LOGE("file open failed: %s", strerror(errno));
1122 return PC_ERR_FILE_OPERATION;
1125 if (flock(*fd, LOCK_EX)) {
1126 C_LOGE("flock failed");
1127 return PC_ERR_INVALID_OPERATION;
1130 if (smack_accesses_add_from_file(*smack, *fd)) {
1131 C_LOGE("smack_accesses_add_from_file failed");
1132 return PC_ERR_INVALID_OPERATION;
1135 /* Rewind the file */
1136 if (lseek(*fd, 0, SEEK_SET) == -1) {
1137 C_LOGE("lseek failed");
1138 return PC_ERR_FILE_OPERATION;
1141 return PC_OPERATION_SUCCESS;
1144 static int app_add_rule(const char *app_id, const char *object, const char *perm)
1146 C_LOGD("Enter function: %s", __func__);
1149 char *smack_path AUTO_FREE;
1150 struct smack_accesses* smack AUTO_SMACK_FREE;
1152 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1153 if (ret != PC_OPERATION_SUCCESS) {
1154 C_LOGE("load_smack_from_file failed");
1158 ret = smack_accesses_add_modify(smack, app_id, object, perm, "");
1160 C_LOGE("smack_accesses_add_modify failed");
1161 return PC_ERR_INVALID_OPERATION;
1164 if (have_smack() && smack_accesses_apply(smack)) {
1165 C_LOGE("smack_accesses_apply failed");
1166 return PC_ERR_INVALID_OPERATION;
1169 if (smack_accesses_save(smack, fd)) {
1170 C_LOGE("smack_accesses_save failed");
1171 return PC_ERR_INVALID_OPERATION;
1174 return PC_OPERATION_SUCCESS;
1179 app_register_appsetting(const char *app_id, struct smack_accesses *smack)
1181 C_LOGD("Enter function: %s", __func__);
1185 char **label_app_list AUTO_FREE;
1186 char **label_dir_list AUTO_FREE;
1187 int app_list_len = 0;
1188 int dir_list_len = 0;
1190 if (!smack_label_is_valid(app_id))
1191 return PC_ERR_INVALID_PARAM;
1194 /* writing appsetting_id (app_id) to "database"*/
1195 ret = add_appsetting_id_to_databse(app_id);
1196 if (ret != PC_OPERATION_SUCCESS)
1200 /* Reading labels of all installed apps from "database"*/
1201 ret = get_all_apps_ids(&label_app_list, &app_list_len);
1202 if (ret != PC_OPERATION_SUCCESS) {
1203 C_LOGE("Error while geting data from database");
1207 /*Add smack rules to rx access each app*/
1208 for (i = 0; i < app_list_len; ++i) {
1209 C_LOGD("Appsetting: applying rx rule for %s", label_app_list[i]);
1210 if (smack_accesses_add_modify(smack, app_id,
1211 label_app_list[i], "rx", "") == -1) {
1212 C_LOGE("smack_accesses_add_modify failed");
1213 ret = PC_ERR_INVALID_OPERATION;
1218 /* Reading labels of all registered settings dirs from "database"*/
1219 ret = get_all_settings_dir_ids(
1220 &label_dir_list, &dir_list_len);
1221 if (ret != PC_OPERATION_SUCCESS) {
1222 C_LOGE("Error while geting data from database");
1225 /*Add smack rules to rwx access each app*/
1226 for (i = 0; i < dir_list_len; ++i) {
1227 C_LOGD("Appsetting: applying rwx rule for %s", label_dir_list[i]);
1228 if (smack_accesses_add_modify(smack, app_id,
1229 label_dir_list[i], "rwx", "") == -1) {
1230 C_LOGE("smack_accesses_add_modify failed");
1231 ret = PC_ERR_INVALID_OPERATION;
1233 /* Should we abort adding rules if once
1234 * smack_accesses_add_modify will fail?*/
1239 for (i = 0; i < app_list_len; ++i) {
1240 free(label_app_list[i]);
1242 for (i = 0; i < dir_list_len; ++i) {
1243 free(label_dir_list[i]);
1249 static int app_register_av_internal(const char *app_av_id, struct smack_accesses* smack)
1251 C_LOGD("Enter function: %s", __func__);
1255 char** smack_label_app_list AUTO_FREE;
1256 int smack_label_app_list_len = 0;
1258 if (!smack_label_is_valid(app_av_id) || NULL == smack)
1259 return PC_ERR_INVALID_PARAM;
1261 // writing anti_virus_id (app_av_id) to "database"
1262 ret = add_av_id_to_databse(app_av_id);
1263 if (ret != PC_OPERATION_SUCCESS )
1266 // Reading labels of all installed apps from "database"
1267 ret = get_all_apps_ids(&smack_label_app_list, &smack_label_app_list_len);
1268 if (ret != PC_OPERATION_SUCCESS ) {
1269 C_LOGE("Error while geting data from database");
1272 for (i = 0; i < smack_label_app_list_len; ++i) {
1273 C_LOGD("Applying rwx rule for %s", smack_label_app_list[i]);
1274 if (smack_accesses_add_modify(smack, app_av_id, smack_label_app_list[i], "wrx", "") == -1) {
1275 C_LOGE("smack_accesses_add_modify failed");
1276 ret = PC_ERR_INVALID_OPERATION;
1278 // Should we abort adding rules if once smack_accesses_add_modify will fail?
1283 for (i = 0; i < smack_label_app_list_len; ++i) {
1284 free(smack_label_app_list[i]);
1291 * This function will check in database labels of all anti viruses
1292 * and for all anti viruses will add a rule "anti_virus_label app_id rwx".
1293 * This should be call in app_install function.
1295 static int register_app_for_av(const char * app_id)
1298 char** smack_label_av_list AUTO_FREE;
1299 int smack_label_av_list_len = 0;
1301 // Reading labels of all installed anti viruses from "database"
1302 ret = get_all_avs_ids(&smack_label_av_list, &smack_label_av_list_len);
1303 if (ret != PC_OPERATION_SUCCESS) {
1304 C_LOGE("Error while geting data from database");
1308 // for each anti-virus put rule: "anti_virus_id app_id rwx"
1309 for (i = 0; i < smack_label_av_list_len; ++i) {
1310 ret = app_add_rule(smack_label_av_list[i], app_id, "wrx");
1311 if (ret != PC_OPERATION_SUCCESS) {
1312 C_LOGE("app_add_rule failed");
1316 free(smack_label_av_list[i]);
1319 ret = PC_OPERATION_SUCCESS;
1322 // If something failed, then no all char* smack_label_av_list[i]
1323 // are deallocated. They must be freed
1324 for(; i<smack_label_av_list_len; ++i) {
1325 free(smack_label_av_list[i]);
1332 * This function will check in database labels of all setting applications
1333 * and for all of them will add a rule "appsetting_id app_id rwx".
1334 * This should be call in app_install function.
1336 static int register_app_for_appsetting(const char *app_id)
1338 C_LOGD("Enter function: %s",__func__);
1340 char **smack_label_list AUTO_FREE;
1341 int smack_label_list_len = 0;
1343 /* Reading labels of all installed setting managers from "database"*/
1344 ret = get_all_appsetting_ids(&smack_label_list, &smack_label_list_len);
1345 if (ret != PC_OPERATION_SUCCESS) {
1346 C_LOGE("Error while geting data from database");
1350 /* for each appsetting put rule: "appsetting_id app_id rx"*/
1351 for (i = 0; i < smack_label_list_len; ++i) {
1352 SECURE_LOGD("Appsetting: app_add_rule (%s, %s rx)", smack_label_list[i], app_id);
1353 ret = app_add_rule(smack_label_list[i], app_id, "rx");
1354 if (ret != PC_OPERATION_SUCCESS) {
1355 C_LOGE("app_add_rule failed");
1359 free(smack_label_list[i]);
1362 ret = PC_OPERATION_SUCCESS;
1365 /* If something failed, then no all char* smack_label_list[i]
1366 are deallocated. They must be freed*/
1367 for (; i < smack_label_list_len; ++i) {
1368 free(smack_label_list[i]);
1376 * This function will grant app_id RX access to all public directories and
1377 * files, previously designated by app_setup_path(APP_PATH_PUBLIC_RO)
1378 * This should be call in app_install function.
1380 static int register_app_for_public_dirs(const char *app_id, struct smack_accesses *smack)
1382 C_LOGD("Enter function: %s", __func__);
1384 char **public_dirs AUTO_FREE;
1385 int public_dirs_cnt = 0;
1387 ret = db_get_public_dirs(&public_dirs, &public_dirs_cnt);
1388 if (ret != PC_OPERATION_SUCCESS) {
1389 C_LOGE("Error while geting data from database");
1393 for (i = 0; i < public_dirs_cnt; ++i) {
1394 SECURE_LOGD("Allowing app %s to access public path %s", app_id, public_dirs[i]);
1395 if (smack_accesses_add_modify(smack, app_id, public_dirs[i], "rx", "")) {
1396 C_LOGE("app_add_rule_modify failed");
1397 while (i < public_dirs_cnt)
1398 free(public_dirs[i++]);
1399 return PC_ERR_INVALID_OPERATION;
1401 free(public_dirs[i]);
1404 return PC_OPERATION_SUCCESS;
1407 static int app_add_permissions_internal(const char* app_id, app_type_t app_type, const char** perm_list, int permanent)
1409 C_LOGD("Enter function: %s", __func__);
1410 char* smack_path AUTO_FREE;
1413 struct smack_accesses *smack AUTO_SMACK_FREE;
1414 const char* base_perm = NULL;
1416 if (!smack_label_is_valid(app_id))
1417 return PC_ERR_INVALID_PARAM;
1419 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1420 if (ret != PC_OPERATION_SUCCESS) {
1421 C_LOGE("load_smack_from_file failed");
1425 /* Implicitly enable base permission for an app_type */
1426 base_perm = app_type_name(app_type);
1428 SECURE_LOGD("perm_to_smack params: app_id: %s, %s", app_id, base_perm);
1429 ret = perm_to_smack(smack, app_id, APP_TYPE_OTHER, base_perm);
1430 if (ret != PC_OPERATION_SUCCESS){
1431 C_LOGE("perm_to_smack failed");
1435 for (i = 0; perm_list[i] != NULL; ++i) {
1436 SECURE_LOGD("perm_to_smack params: app_id: %s, perm_list[%d]: %s", app_id, i, perm_list[i]);
1437 if (strcmp(perm_list[i], TIZEN_PRIVILEGE_ANTIVIRUS) == 0) {
1438 ret = app_register_av_internal(app_id, smack);
1439 if (ret != PC_OPERATION_SUCCESS) {
1440 C_LOGE("app_register_av_internal failed");
1444 if (strcmp(perm_list[i], TIZEN_PRIVILEGE_APPSETTING) == 0) {
1445 ret = app_register_appsetting(app_id, smack);
1446 if (ret != PC_OPERATION_SUCCESS) {
1447 C_LOGE("app_register_appsetting failed");
1452 ret = perm_to_smack(smack, app_id, app_type, perm_list[i]);
1453 if (ret != PC_OPERATION_SUCCESS){
1454 C_LOGE("perm_to_smack failed");
1458 ret = perm_to_dac(app_id, app_type, perm_list[i]);
1459 if (ret != PC_OPERATION_SUCCESS){
1460 C_LOGE("perm_to_dac failed");
1465 if (have_smack() && smack_accesses_apply(smack)) {
1466 C_LOGE("smack_accesses_apply failed");
1467 return PC_ERR_INVALID_OPERATION;
1470 if (permanent && smack_accesses_save(smack, fd)) {
1471 C_LOGE("smack_accesses_save failed");
1472 return PC_ERR_INVALID_OPERATION;
1475 return PC_OPERATION_SUCCESS;
1478 API int app_add_permissions(const char* app_id, const char** perm_list)
1480 C_LOGD("Enter function: %s", __func__);
1481 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 1);
1484 API int app_add_volatile_permissions(const char* app_id, const char** perm_list)
1486 C_LOGD("Enter function: %s", __func__);
1487 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 0);
1490 API int app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)
1492 C_LOGD("Enter function: %s", __func__);
1493 return app_add_permissions_internal(pkg_id, app_type, perm_list, persistent);
1496 /* FIXME: this function is only a stub */
1497 API int app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)
1499 C_LOGD("Enter function: %s", __func__);
1500 return PC_OPERATION_SUCCESS;
1503 static int app_revoke_permissions_internal(const char* app_id, bool persistent)
1505 C_LOGD("Enter function: %s", __func__);
1506 char* smack_path AUTO_FREE;
1509 struct smack_accesses *smack AUTO_SMACK_FREE;
1511 if (!smack_label_is_valid(app_id))
1512 return PC_ERR_INVALID_PARAM;
1514 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1515 if (ret != PC_OPERATION_SUCCESS) {
1516 C_LOGE("load_smack_from_file failed");
1520 if (have_smack() && smack_accesses_clear(smack)) {
1521 ret = PC_ERR_INVALID_OPERATION;
1522 C_LOGE("smack_accesses_clear failed");
1526 if (have_smack() && smack_revoke_subject(app_id)) {
1527 ret = PC_ERR_INVALID_OPERATION;
1528 C_LOGE("smack_revoke_subject failed");
1532 if (persistent && ftruncate(fd, 0) == -1)
1533 C_LOGW("file truncate failed");
1535 return PC_OPERATION_SUCCESS;
1538 API int app_revoke_permissions(const char* pkg_id)
1540 C_LOGD("Enter function: %s", __func__);
1543 if (!smack_label_is_valid(pkg_id))
1544 return PC_ERR_INVALID_PARAM;
1546 ret = app_revoke_permissions_internal(pkg_id, true);
1548 C_LOGE("Revoking permissions failed");
1552 return PC_OPERATION_SUCCESS;
1555 API int app_reset_permissions(const char* pkg_id)
1557 C_LOGD("Enter function: %s", __func__);
1560 if (!smack_label_is_valid(pkg_id))
1561 return PC_ERR_INVALID_PARAM;
1563 ret = app_revoke_permissions_internal(pkg_id, false);
1565 C_LOGE("Revoking permissions failed");
1569 /* Add empty permissions set to trigger re-read of rules */
1570 return app_enable_permissions(pkg_id, APP_TYPE_OTHER, (const char*[]){NULL}, 0);
1573 API int app_label_dir(const char* label, const char* path)
1575 C_LOGD("Enter function: %s", __func__);
1577 int ret = PC_OPERATION_SUCCESS;
1579 if (!smack_label_is_valid(label))
1580 return PC_ERR_INVALID_PARAM;
1582 //setting access label on everything in given directory and below
1583 ret = dir_set_smack_r(path, label, SMACK_LABEL_ACCESS, &label_all);
1584 if (PC_OPERATION_SUCCESS != ret)
1587 //setting execute label for everything with permission to execute
1588 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_execs);
1589 if (PC_OPERATION_SUCCESS != ret)
1592 //setting execute label for everything with permission to execute
1593 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_links_to_execs);
1597 int smack_get_access_new(const char* subject, const char* object, char** label)
1599 char buff[ACC_LEN] = {'r', 'w', 'x', 'a', 't'};
1600 char perm[2] = {'-'};
1603 if(!smack_label_is_valid(subject) || !smack_label_is_valid(object) || !label)
1604 return PC_ERR_INVALID_PARAM;
1606 for (i=0; i<ACC_LEN; ++i) {
1608 int ret = smack_have_access(subject, object, perm);
1610 return PC_ERR_INVALID_OPERATION;
1615 *label = malloc(ACC_LEN+1);
1617 return PC_ERR_MEM_OPERATION;
1619 memcpy(*label, buff, ACC_LEN);
1620 (*label)[ACC_LEN] = 0;
1621 return PC_OPERATION_SUCCESS;
1625 * This function will be used to allow direct communication between 2 OSP application.
1626 * This function requires to store "state" with list of added label.
1628 * Full implementation requires some kind of database. This implemetation works without
1629 * database so you wont be able to revoke permissions added by different process.
1631 API int app_give_access(const char* subject, const char* object, const char* permissions)
1633 C_LOGD("Enter function: %s", __func__);
1634 int ret = PC_OPERATION_SUCCESS;
1635 struct smack_accesses *smack AUTO_SMACK_FREE;
1636 char *current_permissions AUTO_FREE;
1639 return PC_OPERATION_SUCCESS;
1641 if (!smack_label_is_valid(subject) || !smack_label_is_valid(object)) {
1642 C_LOGE("Error in %s: invalid param.", __func__);
1643 return PC_ERR_INVALID_PARAM;
1646 if (PC_OPERATION_SUCCESS != (ret = smack_get_access_new(subject, object, ¤t_permissions))) {
1647 C_LOGE("Error in %s: smack_get_access_new failed.", __func__);
1651 if (smack_accesses_new(&smack)) {
1652 C_LOGE("Error in %s: smack_accesses_new failed.", __func__);
1653 return PC_ERR_MEM_OPERATION;
1656 if (smack_accesses_add_modify(smack, subject, object, permissions, "")) {
1657 C_LOGE("Error in %s: smack_accesses_add_modify failed.", __func__);
1658 return PC_ERR_MEM_OPERATION;
1661 if (smack_accesses_apply(smack)) {
1662 C_LOGE("Error in %s: smack_accesses_apply failed.", __func__);
1663 return PC_ERR_NOT_PERMITTED;
1666 return state_save(subject, object, current_permissions);
1670 * This function will be used to revoke direct communication between 2 OSP application.
1672 * Full implementation requires some kind of database. This implemetation works without
1673 * database so you wont be able to revoke permissions added by different process.
1675 API int app_revoke_access(const char* subject, const char* object)
1677 C_LOGD("Enter function: %s", __func__);
1679 return PC_OPERATION_SUCCESS;
1681 if (!smack_label_is_valid(subject) || !smack_label_is_valid(object)) {
1682 C_LOGE("Error in %s: invalid param.", __func__);
1683 return PC_ERR_INVALID_PARAM;
1686 return state_restore(subject, object);
1689 API int app_label_shared_dir(const char* app_label, const char* shared_label, const char* path)
1691 C_LOGD("Enter function: %s", __func__);
1694 if (!smack_label_is_valid(app_label) || !smack_label_is_valid(shared_label))
1695 return PC_ERR_INVALID_PARAM;
1697 if (strcmp(app_label, shared_label) == 0) {
1698 C_LOGE("app_label equals shared_label");
1699 return PC_ERR_INVALID_PARAM;
1702 //setting label on everything in given directory and below
1703 ret = dir_set_smack_r(path, shared_label, SMACK_LABEL_ACCESS, label_all);
1704 if(ret != PC_OPERATION_SUCCESS){
1705 C_LOGE("dir_set_smakc_r failed");
1709 //setting transmute on dir
1710 ret = dir_set_smack_r(path, "1", SMACK_LABEL_TRANSMUTE, label_dirs);
1711 if (ret != PC_OPERATION_SUCCESS) {
1712 C_LOGE("dir_set_smakc_r failed");
1716 ret = app_add_rule(app_label, shared_label, "rwxat");
1717 if (ret != PC_OPERATION_SUCCESS) {
1718 C_LOGE("app_add_rule failed");
1722 return PC_OPERATION_SUCCESS;
1725 API int add_shared_dir_readers(const char* shared_label, const char** app_list)
1727 C_LOGD("Enter function: %s", __func__);
1731 if (!smack_label_is_valid(shared_label))
1732 return PC_ERR_INVALID_PARAM;
1734 for (i = 0; app_list[i] != NULL; i++) {
1736 if (!smack_label_is_valid(app_list[i]))
1737 return PC_ERR_INVALID_PARAM;
1739 ret = app_add_rule(app_list[i], shared_label, "rx");
1740 if (ret != PC_OPERATION_SUCCESS) {
1741 C_LOGE("app_add_rule failed");
1746 return PC_OPERATION_SUCCESS;
1749 static char* smack_label_for_path(const char *app_id, const char *path)
1751 C_LOGD("Enter function: %s", __func__);
1752 char *salt AUTO_FREE;
1756 /* Prefix $1$ causes crypt() to use MD5 function */
1757 if (-1 == asprintf(&salt, "$1$%s", app_id)) {
1758 C_LOGE("asprintf failed");
1762 label = crypt(path, salt);
1763 if (label == NULL) {
1764 C_LOGE("crypt failed");
1768 /* crypt() output may contain slash character,
1769 * which is not legal in Smack labels */
1770 for (x = label; *x; ++x) {
1777 /* FIXME: remove this pragma once deprecated API is deleted */
1778 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1779 API int app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)
1781 C_LOGD("Enter function: %s", __func__);
1784 if (!smack_label_is_valid(pkg_id)) {
1785 C_LOGE("Invalid app_id %s", pkg_id);
1786 return PC_ERR_INVALID_PARAM;
1789 switch (app_path_type) {
1790 case APP_PATH_PRIVATE:
1791 va_start(ap, app_path_type);
1793 return app_label_dir(pkg_id, path);
1795 case APP_PATH_GROUP_RW: {
1796 const char *shared_label;
1798 va_start(ap, app_path_type);
1799 shared_label = va_arg(ap, const char *);
1802 if (!smack_label_is_valid(shared_label)) {
1803 C_LOGE("Invalid shared_label %s", shared_label);
1804 return PC_ERR_INVALID_PARAM;
1807 if (strcmp(pkg_id, shared_label) == 0) {
1808 C_LOGE("app_id equals shared_label");
1809 return PC_ERR_INVALID_PARAM;
1812 return app_label_shared_dir(pkg_id, shared_label, path);
1815 case APP_PATH_PUBLIC_RO: {
1816 char **app_ids AUTO_FREE;
1817 int app_ids_cnt = 0;
1821 va_start(ap, app_path_type);
1824 C_LOGD("New public RO path %s", path);
1825 label = smack_label_for_path(pkg_id, path);
1827 return PC_ERR_INVALID_OPERATION;
1829 C_LOGD("Generated label '%s' for public RO path %s", label, path);
1830 ret = app_label_shared_dir(pkg_id, label, path);
1831 if (ret != PC_OPERATION_SUCCESS)
1834 /* FIXME: This should be in some kind of transaction/lock */
1835 ret = db_add_public_dir(label);
1836 if (ret != PC_OPERATION_SUCCESS)
1839 ret = get_all_apps_ids(&app_ids, &app_ids_cnt);
1840 if (ret != PC_OPERATION_SUCCESS)
1843 for (i = 0; i < app_ids_cnt; ++i) {
1844 SECURE_LOGD("Allowing app %s to access public path %s", app_ids[i], path);
1845 ret = app_add_rule(app_ids[i], label, "rx");
1846 if (ret != PC_OPERATION_SUCCESS) {
1847 C_LOGE("smack_accesses_new failed");
1848 while (i < app_ids_cnt)
1855 return PC_OPERATION_SUCCESS;
1858 case APP_PATH_SETTINGS_RW:
1860 char **app_ids AUTO_FREE;
1861 int app_ids_cnt = 0;
1866 va_start(ap, app_path_type);
1870 label = smack_label_for_path(pkg_id, path);
1872 return PC_ERR_INVALID_OPERATION;
1874 /*set id for path and all subfolders*/
1875 C_LOGD("Appsetting: generated label '%s' for setting path %s", label, path);
1876 ret = app_label_shared_dir(pkg_id, label, path);
1877 if (ret != PC_OPERATION_SUCCESS) {
1878 C_LOGE("Appsetting: app_label_shared_dir failed (%d)", ret);
1882 /*add path to database*/
1883 /* FIXME: This should be in some kind of transaction/lock */
1884 ret = add_setting_dir_id_to_databse(label);
1885 if (ret != PC_OPERATION_SUCCESS) {
1886 C_LOGE("Appsetting: add_setting_dir_id_to_databse failed");
1890 /*read all apps with appsetting privilege*/
1891 ret = get_all_appsetting_ids(&app_ids, &app_ids_cnt);
1892 if (ret != PC_OPERATION_SUCCESS) {
1893 C_LOGE("Appsetting: get_all_appsetting_ids failed");
1896 C_LOGD("Appsetting: %d appsetting privileged apps registeres",
1899 /*give RWX rights to all apps that have appsetting privilege*/
1900 for (i = 0; i < app_ids_cnt; ++i) {
1901 C_LOGD("Appsetting: allowing app %s to access setting path %s",
1903 ret = app_add_rule(app_ids[i], label, "rwx");
1904 if (ret != PC_OPERATION_SUCCESS) {
1905 C_LOGE("app_add_rule failed");
1906 while (i < app_ids_cnt)
1913 return PC_OPERATION_SUCCESS;
1916 case APP_PATH_ANY_LABEL: {
1917 const char *label = NULL;
1918 va_start(ap, app_path_type);
1919 label = va_arg(ap, const char *);
1921 return app_label_dir(label, path);
1925 va_start(ap, app_path_type);
1927 return PC_ERR_INVALID_PARAM;
1930 return PC_OPERATION_SUCCESS;
1932 /* FIXME: remove this pragma once deprecated API is deleted */
1933 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
1935 API int app_add_friend(const char* pkg_id1, const char* pkg_id2)
1937 C_LOGD("Enter function: %s", __func__);
1940 if (!smack_label_is_valid(pkg_id1) || !smack_label_is_valid(pkg_id2))
1941 return PC_ERR_INVALID_PARAM;
1943 ret = app_add_rule(pkg_id1, pkg_id2, "rwxat");
1944 if (ret != PC_OPERATION_SUCCESS) {
1945 C_LOGE("app_add_rule failed");
1949 ret = app_add_rule(pkg_id2, pkg_id1, "rwxat");
1950 if (ret != PC_OPERATION_SUCCESS) {
1951 C_LOGE("app_add_rule failed");
1955 return PC_OPERATION_SUCCESS;
1958 API int app_install(const char* pkg_id)
1960 C_LOGD("Enter function: %s", __func__);
1963 char* smack_path AUTO_FREE;
1964 struct smack_accesses *smack AUTO_SMACK_FREE;
1966 if (!smack_label_is_valid(pkg_id))
1967 return PC_ERR_INVALID_PARAM;
1969 ret = smack_file_name(pkg_id, &smack_path);
1970 if (ret != PC_OPERATION_SUCCESS)
1973 fd = open(smack_path, O_RDWR|O_CREAT, 0644);
1975 C_LOGE("file open failed: %s", strerror(errno));
1976 return PC_ERR_FILE_OPERATION;
1979 if (smack_accesses_new(&smack)) {
1980 C_LOGE("smack_accesses_new failed");
1981 return PC_ERR_MEM_OPERATION;
1984 ret = add_app_id_to_databse(pkg_id);
1985 if (ret != PC_OPERATION_SUCCESS ) {
1986 SECURE_LOGE("Error while adding app %s to database: %s ", pkg_id, strerror(errno));
1990 ret = register_app_for_av(pkg_id);
1991 if (ret != PC_OPERATION_SUCCESS) {
1992 SECURE_LOGE("Error while adding rules for anti viruses to app %s: %s ", pkg_id, strerror(errno));
1996 ret = register_app_for_appsetting(pkg_id);
1997 if (ret != PC_OPERATION_SUCCESS) {
1998 SECURE_LOGE("Error while adding rules for setting managers to app %s: %s ", pkg_id, strerror(errno));
2002 ret = register_app_for_public_dirs(pkg_id, smack);
2003 if (ret != PC_OPERATION_SUCCESS) {
2004 SECURE_LOGE("Error while adding rules for access to public dirs for app %s: %s ", pkg_id, strerror(errno));
2008 if (have_smack() && smack_accesses_apply(smack)) {
2009 C_LOGE("smack_accesses_apply failed");
2010 return PC_ERR_INVALID_OPERATION;
2013 if (smack_accesses_save(smack, fd)) {
2014 C_LOGE("smack_accesses_save failed");
2015 return PC_ERR_INVALID_OPERATION;
2018 return PC_OPERATION_SUCCESS;
2021 API int app_uninstall(const char* pkg_id)
2023 // TODO: When real database will be used, then this function should remove app_id
2025 // It also should remove rules looks like: "anti_virus_label app_id rwx".
2026 C_LOGD("Enter function: %s", __func__);
2027 char* smack_path AUTO_FREE;
2030 if (!smack_label_is_valid(pkg_id))
2031 return PC_ERR_INVALID_PARAM;
2033 ret = smack_file_name(pkg_id, &smack_path);
2034 if (ret != PC_OPERATION_SUCCESS)
2037 if (unlink(smack_path)) {
2038 C_LOGE("unlink failed: ", strerror(errno));
2039 return PC_OPERATION_SUCCESS;
2042 return PC_OPERATION_SUCCESS;
2045 static int save_rules(int fd, struct smack_accesses* accesses) {
2046 if (flock(fd, LOCK_EX)) {
2047 C_LOGE("flock failed, error %s", strerror(errno));
2048 return PC_ERR_FILE_OPERATION;
2051 if (smack_accesses_save(accesses, fd)) {
2052 C_LOGE("smack_accesses_save failed");
2053 return PC_ERR_FILE_OPERATION;
2055 return PC_OPERATION_SUCCESS ;
2058 static int validate_and_add_rule(char* rule, struct smack_accesses* accesses) {
2059 const char* subject = NULL;
2060 const char* object = NULL;
2061 const char* access = NULL;
2062 char* saveptr = NULL;
2064 subject = strtok_r(rule, " \t\n", &saveptr);
2065 object = strtok_r(NULL, " \t\n", &saveptr);
2066 access = strtok_r(NULL, " \t\n", &saveptr);
2068 // check rule validity
2069 if (subject == NULL ||
2072 strtok_r(NULL, " \t\n", &saveptr) != NULL ||
2073 !smack_label_is_valid(subject) ||
2074 !smack_label_is_valid(object))
2076 C_LOGE("Incorrect rule format: %s", rule);
2077 return PC_ERR_INVALID_PARAM;
2080 if (smack_accesses_add_modify(accesses, subject, object, access, "")) {
2081 C_LOGE("smack_accesses_add_modify failed");
2082 return PC_ERR_INVALID_OPERATION;
2084 return PC_OPERATION_SUCCESS ;
2087 static int parse_and_save_rules(const char** smack_rules,
2088 struct smack_accesses* accesses, const char* feature_file) {
2091 int ret = PC_OPERATION_SUCCESS;
2094 for (i = 0; smack_rules[i] != NULL ; i++) {
2095 // ignore empty lines
2096 if (strspn(smack_rules[i], " \t\n") == strlen(smack_rules[i]))
2099 tmp = strdup(smack_rules[i]);
2100 ret = validate_and_add_rule(tmp, accesses);
2102 if (ret != PC_OPERATION_SUCCESS )
2107 fd = open(feature_file, O_CREAT | O_WRONLY, 0644);
2109 C_LOGE("Unable to create file %s. Error: %s", feature_file, strerror(errno));
2110 return PC_ERR_FILE_OPERATION;
2113 ret = save_rules(fd, accesses);
2118 static int save_gids(FILE* file, const gid_t* list_of_db_gids, size_t list_size) {
2119 int ret = PC_OPERATION_SUCCESS;
2124 C_LOGE("Unable to create file. Error: %s", strerror(errno));
2125 return PC_ERR_FILE_OPERATION; // TODO remove smack accesses?
2128 if(-1 == fchmod(fileno(file), 0644)) {
2129 C_LOGE("Unable to chmod file. Error: %s", strerror(errno));
2130 return PC_ERR_FILE_OPERATION;
2133 for (i = 0; i < list_size ; ++i) {
2134 written = fprintf(file, "%u\n", list_of_db_gids[i]);
2136 C_LOGE("fprintf failed for file. Error: %s", strerror(errno));
2137 ret = PC_ERR_FILE_OPERATION;
2144 API int add_api_feature(app_type_t app_type,
2145 const char* api_feature_name,
2146 const char** smack_rules,
2147 const gid_t* list_of_db_gids,
2149 C_LOGD("Enter function: %s", __func__);
2151 int ret = PC_OPERATION_SUCCESS;
2152 char* smack_file AUTO_FREE;
2153 char* dac_file AUTO_FREE;
2154 struct smack_accesses* accesses = NULL;
2157 // TODO check process capabilities
2159 // get feature SMACK file name
2160 ret = perm_file_path(&smack_file, app_type, api_feature_name, ".smack");
2161 if (ret != PC_OPERATION_SUCCESS || !smack_file ) {
2165 // check if feature exists
2166 if (file_exists(smack_file)) {
2167 C_LOGE("Feature file %s already exists", smack_file);
2168 return PC_ERR_INVALID_PARAM;
2171 // check .dac existence only if gids are supported
2172 if (list_of_db_gids && list_size > 0) {
2173 // get feature DAC file name
2174 ret = perm_file_path(&dac_file, app_type, api_feature_name, ".dac");
2175 if (ret != PC_OPERATION_SUCCESS || !dac_file ) {
2179 // check if feature exists
2180 if (file_exists(dac_file)) {
2181 C_LOGE("Feature file %s already exists", dac_file);
2182 return PC_ERR_INVALID_PARAM;
2186 // parse & save rules
2188 if (smack_accesses_new(&accesses)) {
2189 C_LOGE("smack_acceses_new failed");
2190 return PC_ERR_MEM_OPERATION;
2193 ret = parse_and_save_rules(smack_rules, accesses, smack_file);
2194 smack_accesses_free(accesses);
2197 // go through gid list
2198 if (ret == PC_OPERATION_SUCCESS && list_of_db_gids && list_size > 0) {
2200 file = fopen(dac_file, "w+");
2201 ret = save_gids(file, list_of_db_gids, list_size);
2205 // remove both files in case of failure
2206 if (ret != PC_OPERATION_SUCCESS) {
2217 * This function is marked as deprecated and will be removed
2219 API int app_register_av(const char* app_av_id)
2223 char* smack_path AUTO_FREE;
2224 struct smack_accesses* smack AUTO_SMACK_FREE;
2226 ret = load_smack_from_file(app_av_id, &smack, &fd, &smack_path);
2227 if (ret != PC_OPERATION_SUCCESS ) {
2228 C_LOGE("load_smack_from_file failed");
2232 ret = app_register_av_internal(app_av_id, smack);
2233 if (PC_OPERATION_SUCCESS != ret) {
2234 C_LOGE("app_register_av_internal failed");
2238 // Add permisions from OSP_antivirus.samck file
2239 ret = perm_to_smack(smack, app_av_id, APP_TYPE_OSP, TIZEN_PRIVILEGE_ANTIVIRUS);
2240 if (PC_OPERATION_SUCCESS != ret) {
2241 C_LOGE("perm_to_smack failed");
2245 // Add permisions from OSP_antivirus.dac file
2246 ret = perm_to_dac(app_av_id, APP_TYPE_OSP, TIZEN_PRIVILEGE_ANTIVIRUS);
2247 if (ret != PC_OPERATION_SUCCESS) {
2248 C_LOGE("perm_to_dac failed");
2252 if (have_smack() && smack_accesses_apply(smack)) {
2253 C_LOGE("smack_accesses_apply failed");
2254 ret = PC_ERR_INVALID_OPERATION;
2258 if (smack_accesses_save(smack, fd)) {
2259 C_LOGE("smack_accesses_save failed");
2260 ret = PC_ERR_INVALID_OPERATION;