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 "/etc/smack/accesses.d/"
65 #define SMACK_APP_LABEL_TEMPLATE "~APP~"
66 #define SMACK_SRC_FILE_SUFFIX "_src_file"
67 #define SMACK_SRC_DIR_SUFFIX "_src_dir"
68 #define SMACK_DATA_SUFFIX "_data"
69 #define WRT_BASE_DEVCAP "WRT"
70 #define WRT_CLIENT_PATH "/usr/bin/wrt-client"
72 #define TIZEN_PRIVILEGE_ANTIVIRUS "http://tizen.org/privilege/antivirus"
73 #define TIZEN_PRIVILEGE_APPSETTING "http://tizen.org/privilege/appsetting"
85 typedef struct state_node_t {
89 static void *state_tree = NULL;
97 typedef int (*label_decision_fn)(const FTSENT*);
103 int state_tree_cmp(const void *first, const void *second)
105 return strcmp(((state_node*)first)->key,
106 ((state_node*)second)->key);
109 int state_tree_push(const char* key_param, const char* value_param)
111 state_node *node = malloc(sizeof(state_node));
112 char *key = strdup(key_param);
113 char *value = strdup(value_param);
115 if (!node || !key || !value) {
119 return PC_ERR_MEM_OPERATION;
125 if (NULL != tfind(node, &state_tree, state_tree_cmp)){
129 return PC_OPERATION_SUCCESS; // 04.2013 Temporary fix. Allow for multiple call of app_give_access
132 tsearch(node, &state_tree, state_tree_cmp);
133 return PC_OPERATION_SUCCESS;
136 char* state_tree_pop_new(char *key)
138 state_node search, *node;
144 wtf = tfind(&search, &state_tree, state_tree_cmp);
148 node = *(state_node**)wtf;
152 tdelete(node, &state_tree, state_tree_cmp);
160 int state_save(const char *subject, const char *object, const char *perm)
163 if (-1 == asprintf(&key, "%s|%s", subject, object)) {
164 C_LOGE("Error in %s: asprintf failed.", __func__);
165 return PC_ERR_INVALID_OPERATION;
167 int ret = state_tree_push(key, perm);
172 int state_restore(const char* subject, const char* object)
175 char *perm AUTO_FREE;
176 struct smack_accesses *smack AUTO_SMACK_FREE;
178 if (-1 == asprintf(&key, "%s|%s", subject, object)) {
179 C_LOGE("Error in %s: asprintf failed.", __func__);
180 return PC_ERR_INVALID_OPERATION;
183 perm = state_tree_pop_new(key);
185 C_LOGE("Error in %s: state_tree_pop_new failed - no data for subject=%s object=%s.", __func__, subject, object);
186 return PC_ERR_INVALID_OPERATION;
189 if (smack_accesses_new(&smack)) {
190 C_LOGE("Error in %s: smack_accesses_new failed - memory error.", __func__);
191 return PC_ERR_MEM_OPERATION;
194 if (smack_accesses_add(smack, subject, object, perm)) {
195 C_LOGE("Error in %s: smack_accesses_add failed.", __func__);
196 return PC_ERR_MEM_OPERATION;
199 if (smack_accesses_apply(smack)) {
200 C_LOGE("Error in %s: smack_accesses_apply failed - operation not permitted.", __func__);
201 return PC_ERR_NOT_PERMITTED;
204 return PC_OPERATION_SUCCESS;
207 static inline int have_smack(void)
209 static int have_smack = -1;
211 if (-1 == have_smack) {
212 if (NULL == smack_smackfs_path()) {
213 C_LOGD("Libprivilage-control: no smack found on phone");
216 C_LOGD("Libprivilege-control: found smack on phone");
224 API int control_privilege(void)
226 C_LOGD("Enter function: %s", __func__);
227 if(getuid() == APP_UID) // current user is 'app'
228 return PC_OPERATION_SUCCESS;
230 if(set_app_privilege("org.tizen.", NULL, NULL) == PC_OPERATION_SUCCESS)
231 return PC_OPERATION_SUCCESS;
233 return PC_ERR_NOT_PERMITTED;
237 * TODO: this function should be moved to libsmack in open-source.
239 API int get_smack_label_from_process(pid_t pid, char smack_label[SMACK_LABEL_LEN + 1])
241 C_LOGD("Enter function: %s", __func__);
244 int PATH_MAX_LEN = 64;
245 char path[PATH_MAX_LEN + 1];
248 ret = PC_ERR_INVALID_PARAM;
252 bzero(smack_label, SMACK_LABEL_LEN + 1);
253 if (!have_smack()) { // If no smack just return success with empty label
254 C_LOGD("No SMACK. Return empty label");
255 ret = PC_OPERATION_SUCCESS;
259 bzero(path, PATH_MAX_LEN + 1);
260 snprintf(path, PATH_MAX_LEN, "/proc/%d/attr/current", pid);
261 fd = open(path, O_RDONLY);
263 C_LOGE("cannot open file %s (errno: %s)", path, strerror(errno));
264 ret = PC_ERR_FILE_OPERATION;
268 ret = read(fd, smack_label, SMACK_LABEL_LEN);
270 C_LOGE("cannot read from file %s", path);
271 ret = PC_ERR_FILE_OPERATION;
275 ret = PC_OPERATION_SUCCESS;
281 API int smack_pid_have_access(pid_t pid,
283 const char *access_type)
285 C_LOGD("Enter function: %s", __func__);
287 char pid_subject_label[SMACK_LABEL_LEN + 1];
289 cap_flag_value_t cap_v;
292 C_LOGD("No SMACK. Return access granted");
296 if (pid < 0 || object == NULL || strlen(object) == 0 ||
297 access_type == NULL || strlen(access_type) == 0) {
298 C_LOGE("Invalid param");
302 //get SMACK label of process
303 ret = get_smack_label_from_process(pid, pid_subject_label);
304 if (PC_OPERATION_SUCCESS != ret) {
305 C_LOGE("get_smack_label_from_process %d failed: %d", pid, ret);
308 C_LOGD("pid %d have label: %s", pid, pid_subject_label);
310 // if read empty label then do not call smack_have_access()
311 if (pid_subject_label[0] != '\0') {
312 ret = smack_have_access(pid_subject_label, object, access_type);
314 C_LOGE("smack_have_access failed");
317 if ( 1 == ret ) { // smack_have_access return 1 (access granted)
318 C_LOGD("smack_have_access return 1 (access granted)");
323 // smack_have_access return 0 (access denied). Now CAP_MAC_OVERRIDE should be checked
324 C_LOGD("smack_have_access return 0 (access denied)");
325 cap = cap_get_pid(pid);
327 C_LOGE("cap_get_pid failed");
330 ret = cap_get_flag(cap, CAP_MAC_OVERRIDE, CAP_EFFECTIVE, &cap_v);
332 C_LOGE("cap_get_flag failed");
336 if (cap_v == CAP_SET) {
337 C_LOGD("pid %d have CAP_MAC_OVERRIDE", pid);
341 C_LOGD("pid %d have no CAP_MAC_OVERRIDE", pid);
346 static int set_dac(const char *smack_label, const char *pkg_name)
348 C_LOGD("Enter function: %s", __func__);
349 FILE* fp_group = NULL; // /etc/group
350 uid_t t_uid = -1; // uid of current process
351 gid_t *glist = NULL; // group list
352 gid_t temp_gid = -1; // for group list
353 char buf[10] = {0, }; // contents in group_list file
354 int glist_cnt = 0; // for group list
358 unsigned *additional_gids = NULL;
361 * initialize user structure
363 C_LOGD("initialize user structure");
364 memset(usr.user_name, 0x00, 10);
365 memset(usr.home_dir, 0x00, 64);
366 memset(usr.group_list, 0x00, 64);
371 C_LOGD("Current uid is %d", t_uid);
373 if(t_uid == 0) // current user is 'root'
375 if(!strncmp(pkg_name, "developer", 9))
377 strncpy(usr.user_name, DEV_USER_NAME, sizeof(usr.user_name));
378 usr.uid = DEVELOPER_UID;
379 usr.gid = DEVELOPER_GID;
380 strncpy(usr.home_dir, DEV_HOME_DIR, sizeof(usr.home_dir));
381 strncpy(usr.group_list, DEV_GROUP_PATH, sizeof(usr.group_list));
385 strncpy(usr.user_name, APP_USER_NAME, sizeof(usr.user_name));
388 strncpy(usr.home_dir, APP_HOME_DIR, sizeof(usr.home_dir));
389 strncpy(usr.group_list, APP_GROUP_PATH, sizeof(usr.group_list));
393 * get group information
395 C_LOGD("get group information");
396 if(!(fp_group = fopen(usr.group_list, "r")))
398 C_LOGE("[ERR] file open error: [%s]\n", usr.group_list);
399 result = PC_ERR_FILE_OPERATION; // return -1
403 while(fgets(buf, 10, fp_group) != NULL)
406 temp_gid = strtoul(buf, 0, 10);
407 if(errno != 0) // error occured during strtoul()
409 C_LOGE("[ERR] cannot change string to integer: [%s]", buf);
410 result = PC_ERR_INVALID_OPERATION;
414 glist = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + 1));
417 result = PC_ERR_MEM_OPERATION; // return -2
418 C_LOGE("Cannot allocate memory");
421 glist[glist_cnt] = temp_gid;
431 result = get_app_gids(smack_label, &additional_gids, &cnt);
432 if (result != PC_OPERATION_SUCCESS)
436 glist_new = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + cnt));
437 if (glist_new == NULL) {
438 result = PC_ERR_MEM_OPERATION; // return -2
439 C_LOGE("Cannot allocate memory");
443 for (i = 0; i < cnt; ++i) {
444 C_LOGD("Additional GID based on enabled permissions: %u", additional_gids[i]);
445 glist[glist_cnt++] = additional_gids[i];
453 C_LOGD("Adding process to the following groups:");
454 for(i=0; i<glist_cnt; ++i) {
455 C_LOGD("glist [ %d ] = %d", i, glist[i]);
457 C_LOGD("setgroups()");
458 if(setgroups(glist_cnt, glist) != 0)
460 C_LOGE("[ERR] setgrouops fail\n");
461 result = PC_ERR_NOT_PERMITTED; // return -3
471 * setuid() & setgid()
473 C_LOGD("setgid( %d ) & setuid( %d )", usr.gid, usr.uid);
474 if(setgid(usr.gid) != 0) // fail
476 C_LOGE("[ERR] fail to execute setgid().");
477 result = PC_ERR_INVALID_OPERATION;
480 if(setuid(usr.uid) != 0) // fail
482 C_LOGE("[ERR] fail to execute setuid().");
483 result = PC_ERR_INVALID_OPERATION;
487 C_LOGD("setenv(): USER = %s, HOME = %s", usr.user_name, usr.home_dir);
488 if(setenv("USER", usr.user_name, 1) != 0) //fail
490 C_LOGE("[ERR] fail to execute setenv() [USER].");
491 result = PC_ERR_INVALID_OPERATION;
494 if(setenv("HOME", usr.home_dir, 1) != 0) // fail
496 C_LOGE("[ERR] fail to execute setenv() [HOME].");
497 result = PC_ERR_INVALID_OPERATION;
501 else // current user is not only 'root' but 'app'
503 C_LOGE("[ERR] current user is NOT root\n");
504 result = PC_ERR_NOT_PERMITTED; // return -3
508 result = PC_OPERATION_SUCCESS;
515 free(additional_gids);
521 * Set process SMACK label from EXEC label of a file.
522 * This function is emulating EXEC label behaviour of SMACK for programs
523 * run by dlopen/dlsym instead of execv.
525 * @param path file path to take label from
526 * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
528 static int set_smack_from_binary(char **smack_label, const char* path, app_type_t type)
530 C_LOGD("Enter function: %s", __func__);
533 C_LOGD("Path: %s", path);
536 if(type == APP_TYPE_WGT
537 || type == APP_TYPE_WGT_PARTNER
538 || type == APP_TYPE_WGT_PLATFORM) {
539 ret = smack_lgetlabel(path, smack_label, SMACK_LABEL_EXEC);
541 ret = smack_getlabel(path, smack_label, SMACK_LABEL_EXEC);
544 C_LOGE("Getting exec label from file %s failed", path);
545 return PC_ERR_INVALID_OPERATION;
548 if (*smack_label == NULL) {
549 /* No label to set, just return with success */
550 C_LOGD("No label to set, just return with success");
551 ret = PC_OPERATION_SUCCESS;
554 C_LOGD("label = %s", *smack_label);
556 ret = smack_set_label_for_self(*smack_label);
557 C_LOGD("smack_set_label_for_self returned %d", ret);
559 ret = PC_OPERATION_SUCCESS;
565 static int is_widget(const char* path)
567 C_LOGD("Enter function: %s", __func__);
568 char buf[sizeof(WRT_CLIENT_PATH)];
571 ret = readlink(path, buf, sizeof(WRT_CLIENT_PATH));
573 C_LOGD("readlink(%s) returned error: %s. Assuming that app is not a widget", path, strerror(errno));
574 else if (ret == sizeof(WRT_CLIENT_PATH))
575 C_LOGD("%s is not a widget", path);
576 if (ret == -1 || ret == sizeof(WRT_CLIENT_PATH))
579 C_LOGD("buf = %s", buf);
581 ret = !strcmp(WRT_CLIENT_PATH, buf);
582 C_LOGD("%s is %s widget", path, ret ? "a" : "not a");
587 * Partially verify, that the type given for app is correct.
588 * This function will use some heuristics to check whether the app type is right.
589 * It is intended for security hardening to catch privilege setting for the
590 * app type not corresponding to the actual binary.
591 * Beware - when it detects an anomaly, the whole process will be terminated.
593 * @param type claimed application type
594 * @param path file path to executable
595 * @return return void on success, terminate the process on error
597 static app_type_t verify_app_type(const char* type, const char* path)
599 C_LOGD("Enter function: %s", __func__);
600 /* TODO: this should actually be treated as error, but until the old
601 * set_privilege API is removed, it must be ignored */
603 C_LOGD("PKG_TYPE_OTHER");
604 return APP_TYPE_OTHER; /* good */
607 if (is_widget(path)) {
608 if (!strcmp(type, "wgt")) {
609 C_LOGD("PKG_TYPE_WGT");
610 return APP_TYPE_WGT; /* good */
611 } else if (!strcmp(type, "wgt_partner")) {
612 C_LOGD("PKG_TYPE_WGT_PARTNER");
613 return APP_TYPE_WGT_PARTNER; /* good */
614 } else if (!strcmp(type, "wgt_platform")) {
615 C_LOGD("PKG_TYPE_WGT_PLATFORM");
616 return APP_TYPE_WGT_PLATFORM; /* good */
620 if (type == NULL || (strcmp(type, "wgt")
621 && strcmp(type, "wgt_partner")
622 && strcmp(type, "wgt_platform"))){
623 C_LOGD("PKG_TYPE_OTHER");
624 return APP_TYPE_OTHER; /* good */
629 C_LOGE("EXIT_FAILURE");
633 API int set_app_privilege(const char* name, const char* type, const char* path)
635 C_LOGD("Enter function: %s", __func__);
636 C_LOGD("Function params: name = %s, type = %s, path = %s", name, type, path);
637 char *smack_label AUTO_FREE;
638 int ret = PC_OPERATION_SUCCESS;
641 ret = set_smack_from_binary(&smack_label, path, verify_app_type(type, path));
642 if (ret != PC_OPERATION_SUCCESS)
646 return set_dac(smack_label, name);
649 API int set_privilege(const char* pkg_name)
651 C_LOGD("Enter function: %s", __func__);
652 return set_app_privilege(pkg_name, NULL, NULL);
655 static inline const char* app_type_name(app_type_t app_type)
662 case APP_TYPE_WGT_PARTNER:
663 return "WRT_partner";
664 case APP_TYPE_WGT_PLATFORM:
665 return "WRT_platform";
666 case APP_TYPE_OSP_PARTNER:
667 return "OSP_partner";
668 case APP_TYPE_OSP_PLATFORM:
669 return "OSP_platform";
675 static inline const char* app_type_group_name(app_type_t app_type)
679 case APP_TYPE_WGT_PARTNER:
680 case APP_TYPE_WGT_PLATFORM:
683 case APP_TYPE_OSP_PARTNER:
684 case APP_TYPE_OSP_PLATFORM:
692 * This function changes permission URI to basename for file name.
693 * For e.g. from http://tizen.org/privilege/contact.read will be
694 * created basename : org.tizen.privilege.contact.read
697 static int base_name_from_perm(const char *perm, char **name) {
699 char *host_dot = NULL;
700 char *rest_slash = NULL;
703 ip = iri_parse(perm);
704 if (ip == NULL || ip->host == NULL) {
705 C_LOGE("Bad permission format : %s", perm);
707 return PC_ERR_INVALID_PARAM;
710 if (ip->path == NULL) {
716 host_dot = strrchr(ip->host, '.');
723 while ((rest_slash = strchr(ip->path, '/'))) {
727 ret = asprintf(name, "%s%s%s%s",
728 host_dot ? host_dot : "", host_dot ? "." : "",
729 ip->host ? ip->host : "", ip->path);
731 C_LOGE("asprintf failed");
733 return PC_ERR_MEM_OPERATION;
737 return PC_OPERATION_SUCCESS;
740 static int perm_file_path(char** path, app_type_t app_type, const char* perm, const char *suffix)
742 const char* app_type_prefix = NULL;
743 char* perm_basename = NULL;
746 if (perm == NULL || strlen(perm) == 0) {
747 C_LOGE("empty permission name");
748 return PC_ERR_INVALID_PARAM;
751 app_type_prefix = app_type_group_name(app_type);
753 ret = base_name_from_perm(perm, &perm_basename);
754 if (ret != PC_OPERATION_SUCCESS) {
755 C_LOGE("Couldn't get permission basename");
759 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s",
760 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
761 perm_basename, suffix);
763 C_LOGE("asprintf failed");
764 return PC_ERR_MEM_OPERATION;
767 C_LOGD("Path : %s", *path);
769 return PC_OPERATION_SUCCESS;
772 static bool file_exists(const char* path) {
773 FILE* file = fopen(path, "r");
781 static int perm_to_smack(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
783 C_LOGD("Enter function: %s", __func__);
785 char* path AUTO_FREE;
786 char* format_string AUTO_FREE;
787 FILE* file AUTO_FCLOSE;
788 char smack_subject[SMACK_LABEL_LEN + 1];
789 char smack_object[SMACK_LABEL_LEN + 1];
790 char smack_accesses[10];
792 // get file name for permission (devcap)
793 ret = perm_file_path(&path, app_type, perm, ".smack");
794 if (ret != PC_OPERATION_SUCCESS) {
795 C_LOGD("No smack config file for permission %s", perm);
799 if (asprintf(&format_string,"%%%ds %%%ds %%%lus\n",
800 SMACK_LABEL_LEN, SMACK_LABEL_LEN, (unsigned long)sizeof(smack_accesses)) == -1) {
801 C_LOGE("asprintf failed");
802 return PC_ERR_MEM_OPERATION;
805 file = fopen(path, "r");
806 C_LOGD("path = %s", path);
808 C_LOGE("fopen failed");
809 return PC_OPERATION_SUCCESS;
812 while (fscanf(file, format_string, smack_subject, smack_object, smack_accesses) == 3) {
813 if (!strcmp(smack_subject, SMACK_APP_LABEL_TEMPLATE))
814 strcpy(smack_subject, app_label);
816 if (!strcmp(smack_object, SMACK_APP_LABEL_TEMPLATE))
817 strcpy(smack_object, app_label);
819 C_LOGD("smack_accesses_add_modify (subject: %s, object: %s, access: %s)", smack_subject, smack_object, smack_accesses);
820 if (smack_accesses_add_modify(smack, smack_subject, smack_object, smack_accesses, "") != 0) {
821 C_LOGE("smack_accesses_add_modify failed");
822 return PC_ERR_INVALID_OPERATION;
826 return PC_OPERATION_SUCCESS;
829 static int perm_to_dac(const char* app_label, app_type_t app_type, const char* perm)
831 C_LOGD("Enter function: %s", __func__);
833 char* path AUTO_FREE;
834 FILE* file AUTO_FCLOSE;
837 ret = perm_file_path(&path, app_type, perm, ".dac");
838 if (ret != PC_OPERATION_SUCCESS) {
839 C_LOGD("No dac config file for permission %s", perm);
843 file = fopen(path, "r");
844 C_LOGD("path = %s", path);
846 C_LOGE("fopen failed");
847 return PC_OPERATION_SUCCESS;
850 while (fscanf(file, "%d\n", &gid) == 1) {
851 C_LOGD("Adding app_id %s to group %d", app_label, gid);
852 ret = add_app_gid(app_label, gid);
853 if (ret != PC_OPERATION_SUCCESS) {
854 C_LOGE("sadd_app_gid failed");
859 return PC_OPERATION_SUCCESS;
862 static int label_all(const FTSENT* ftsent)
864 return DECISION_LABEL;
867 static int label_execs(const FTSENT* ftsent)
869 C_LOGD("Mode: %d", ftsent->fts_statp->st_mode);
870 // label only regular executable files
871 if (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR))
872 return DECISION_LABEL;
873 return DECISION_SKIP;
876 static int label_dirs(const FTSENT* ftsent)
878 // label only directories
879 if (S_ISDIR(ftsent->fts_statp->st_mode))
880 return DECISION_LABEL;
881 return DECISION_SKIP;
884 static int label_links_to_execs(const FTSENT* ftsent)
887 char* target AUTO_FREE;
889 // check if it's a link
890 if ( !S_ISLNK(ftsent->fts_statp->st_mode))
891 return DECISION_SKIP;
893 target = realpath(ftsent->fts_path, NULL);
895 C_LOGE("Getting link target for %s failed. Error %s", ftsent->fts_path, strerror(errno));
896 return PC_ERR_FILE_OPERATION;
898 if (-1 == stat(target, &buf)) {
899 C_LOGE("stat failed for %s, error: %s",target, strerror(errno));
900 return PC_ERR_FILE_OPERATION;
902 // skip if link target is not a regular executable file
903 if (buf.st_mode != (buf.st_mode | S_IXUSR | S_IFREG)) {
904 C_LOGD("%s Is not a regular executable file. Skipping.", target);
905 return DECISION_SKIP;
908 return DECISION_LABEL;
911 static int dir_set_smack_r(const char *path, const char* label,
912 enum smack_label_type type, label_decision_fn fn)
914 C_LOGD("Enter function: %s", __func__);
915 const char* path_argv[] = {path, NULL};
916 FTS *fts AUTO_FTS_CLOSE;
920 fts = fts_open((char * const *) path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
922 C_LOGE("fts_open failed");
923 return PC_ERR_FILE_OPERATION;
926 while ((ftsent = fts_read(fts)) != NULL) {
927 /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
928 if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
929 C_LOGE("FTS_ERR error or failed stat(2) (FTS_NS)");
930 return PC_ERR_FILE_OPERATION;
938 if (ret == DECISION_LABEL) {
939 C_LOGD("smack_lsetlabel (label: %s (type: %d), path: %s)", label, type, ftsent->fts_path);
940 if (smack_lsetlabel(ftsent->fts_path, label, type) != 0) {
941 C_LOGE("smack_lsetlabel failed");
942 return PC_ERR_FILE_OPERATION;
947 /* If last call to fts_read() set errno, we need to return error. */
949 C_LOGE("Last errno: %s", strerror(errno));
950 return PC_ERR_FILE_OPERATION;
952 return PC_OPERATION_SUCCESS;
955 API char* app_id_from_socket(int sockfd)
957 C_LOGD("Enter function: %s", __func__);
964 ret = smack_new_label_from_socket(sockfd, &app_id);
966 C_LOGE("smack_new_label_from_socket failed");
970 C_LOGD("app_id: %s", app_id);
975 static int smack_file_name(const char* app_id, char** path)
977 if (asprintf(path, SMACK_RULES_DIR "/%s", app_id) == -1) {
978 C_LOGE("asprintf failed");
980 return PC_ERR_MEM_OPERATION;
983 return PC_OPERATION_SUCCESS;
986 static int load_smack_from_file(const char* app_id, struct smack_accesses** smack, int *fd, char** path)
988 C_LOGD("Enter function: %s", __func__);
991 ret = smack_file_name(app_id, path);
992 if (ret != PC_OPERATION_SUCCESS)
995 if (smack_accesses_new(smack)) {
996 C_LOGE("smack_accesses_new failed");
997 return PC_ERR_MEM_OPERATION;
1000 *fd = open(*path, O_CREAT|O_RDWR, 0644);
1002 C_LOGE("file open failed: %s", strerror(errno));
1003 return PC_ERR_FILE_OPERATION;
1006 if (flock(*fd, LOCK_EX)) {
1007 C_LOGE("flock failed");
1008 return PC_ERR_INVALID_OPERATION;
1011 if (smack_accesses_add_from_file(*smack, *fd)) {
1012 C_LOGE("smack_accesses_add_from_file failed");
1013 return PC_ERR_INVALID_OPERATION;
1016 /* Rewind the file */
1017 if (lseek(*fd, 0, SEEK_SET) == -1) {
1018 C_LOGE("lseek failed");
1019 return PC_ERR_FILE_OPERATION;
1022 return PC_OPERATION_SUCCESS;
1025 static int app_add_rule(const char *app_id, const char *object, const char *perm)
1027 C_LOGD("Enter function: %s", __func__);
1030 char *smack_path AUTO_FREE;
1031 struct smack_accesses* smack AUTO_SMACK_FREE;
1033 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1034 if (ret != PC_OPERATION_SUCCESS) {
1035 C_LOGE("load_smack_from_file failed");
1039 ret = smack_accesses_add_modify(smack, app_id, object, perm, "");
1041 C_LOGE("smack_accesses_add_modify failed");
1042 return PC_ERR_INVALID_OPERATION;
1045 if (have_smack() && smack_accesses_apply(smack)) {
1046 C_LOGE("smack_accesses_apply failed");
1047 return PC_ERR_INVALID_OPERATION;
1050 if (smack_accesses_save(smack, fd)) {
1051 C_LOGE("smack_accesses_save failed");
1052 return PC_ERR_INVALID_OPERATION;
1055 return PC_OPERATION_SUCCESS;
1060 app_register_appsetting(const char *app_id, struct smack_accesses *smack)
1062 C_LOGD("Enter function: %s", __func__);
1066 char **label_app_list AUTO_FREE;
1067 char **label_dir_list AUTO_FREE;
1068 int app_list_len = 0;
1069 int dir_list_len = 0;
1071 if (!smack_label_is_valid(app_id))
1072 return PC_ERR_INVALID_PARAM;
1075 /* writing appsetting_id (app_id) to "database"*/
1076 ret = add_appsetting_id_to_databse(app_id);
1077 if (ret != PC_OPERATION_SUCCESS)
1081 /* Reading labels of all installed apps from "database"*/
1082 ret = get_all_apps_ids(&label_app_list, &app_list_len);
1083 if (ret != PC_OPERATION_SUCCESS) {
1084 C_LOGE("Error while geting data from database");
1088 /*Add smack rules to rx access each app*/
1089 for (i = 0; i < app_list_len; ++i) {
1090 C_LOGD("Appsetting: applying rx rule for %s", label_app_list[i]);
1091 if (smack_accesses_add(smack, app_id,
1092 label_app_list[i], "rx") == -1) {
1093 C_LOGE("smack_accesses_add failed");
1094 ret = PC_ERR_INVALID_OPERATION;
1099 /* Reading labels of all registered settings dirs from "database"*/
1100 ret = get_all_settings_dir_ids(
1101 &label_dir_list, &dir_list_len);
1102 if (ret != PC_OPERATION_SUCCESS) {
1103 C_LOGE("Error while geting data from database");
1106 /*Add smack rules to rwx access each app*/
1107 for (i = 0; i < dir_list_len; ++i) {
1108 C_LOGD("Appsetting: applying rwx rule for %s", label_dir_list[i]);
1109 if (smack_accesses_add(smack, app_id,
1110 label_dir_list[i], "rwx") == -1) {
1111 C_LOGE("smack_accesses_add failed");
1112 ret = PC_ERR_INVALID_OPERATION;
1114 /* Should we abort adding rules if once
1115 * smack_accesses_add will fail?*/
1120 for (i = 0; i < app_list_len; ++i) {
1121 free(label_app_list[i]);
1123 for (i = 0; i < dir_list_len; ++i) {
1124 free(label_dir_list[i]);
1130 static int app_register_av_internal(const char *app_av_id, struct smack_accesses* smack)
1132 C_LOGD("Enter function: %s", __func__);
1136 char** smack_label_app_list AUTO_FREE;
1137 int smack_label_app_list_len = 0;
1139 if (!smack_label_is_valid(app_av_id) || NULL == smack)
1140 return PC_ERR_INVALID_PARAM;
1142 // writing anti_virus_id (app_av_id) to "database"
1143 ret = add_av_id_to_databse(app_av_id);
1144 if (ret != PC_OPERATION_SUCCESS )
1147 // Reading labels of all installed apps from "database"
1148 ret = get_all_apps_ids(&smack_label_app_list, &smack_label_app_list_len);
1149 if (ret != PC_OPERATION_SUCCESS ) {
1150 C_LOGE("Error while geting data from database");
1153 for (i = 0; i < smack_label_app_list_len; ++i) {
1154 C_LOGD("Applying rwx rule for %s", smack_label_app_list[i]);
1155 if (smack_accesses_add_modify(smack, app_av_id, smack_label_app_list[i], "wrx", "") == -1) {
1156 C_LOGE("smack_accesses_add_modify failed");
1157 ret = PC_ERR_INVALID_OPERATION;
1159 // Should we abort adding rules if once smack_accesses_add_modify will fail?
1164 for (i = 0; i < smack_label_app_list_len; ++i) {
1165 free(smack_label_app_list[i]);
1172 * This function will check in database labels of all anti viruses
1173 * and for all anti viruses will add a rule "anti_virus_label app_id rwx".
1174 * This should be call in app_install function.
1176 static int register_app_for_av(const char * app_id)
1179 char** smack_label_av_list AUTO_FREE;
1180 int smack_label_av_list_len = 0;
1182 // Reading labels of all installed anti viruses from "database"
1183 ret = get_all_avs_ids(&smack_label_av_list, &smack_label_av_list_len);
1184 if (ret != PC_OPERATION_SUCCESS) {
1185 C_LOGE("Error while geting data from database");
1189 // for each anti-virus put rule: "anti_virus_id app_id rwx"
1190 for (i = 0; i < smack_label_av_list_len; ++i) {
1191 ret = app_add_rule(smack_label_av_list[i], app_id, "wrx");
1192 if (ret != PC_OPERATION_SUCCESS) {
1193 C_LOGE("app_add_rule failed");
1197 free(smack_label_av_list[i]);
1200 ret = PC_OPERATION_SUCCESS;
1203 // If something failed, then no all char* smack_label_av_list[i]
1204 // are deallocated. They must be freed
1205 for(; i<smack_label_av_list_len; ++i) {
1206 free(smack_label_av_list[i]);
1213 * This function will check in database labels of all setting applications
1214 * and for all of them will add a rule "appsetting_id app_id rwx".
1215 * This should be call in app_install function.
1217 static int register_app_for_appsetting(const char *app_id)
1219 C_LOGD("Enter function: %s",__func__);
1221 char **smack_label_list AUTO_FREE;
1222 int smack_label_list_len = 0;
1224 /* Reading labels of all installed setting managers from "database"*/
1225 ret = get_all_appsetting_ids(&smack_label_list, &smack_label_list_len);
1226 if (ret != PC_OPERATION_SUCCESS) {
1227 C_LOGE("Error while geting data from database");
1231 /* for each appsetting put rule: "appsetting_id app_id rx"*/
1232 for (i = 0; i < smack_label_list_len; ++i) {
1233 C_LOGD("Appsetting: app_add_rule (%s, %s rx)", smack_label_list[i], app_id);
1234 ret = app_add_rule(smack_label_list[i], app_id, "rx");
1235 if (ret != PC_OPERATION_SUCCESS) {
1236 C_LOGE("app_add_rule failed");
1240 free(smack_label_list[i]);
1243 ret = PC_OPERATION_SUCCESS;
1246 /* If something failed, then no all char* smack_label_list[i]
1247 are deallocated. They must be freed*/
1248 for (; i < smack_label_list_len; ++i) {
1249 free(smack_label_list[i]);
1257 * This function will grant app_id RX access to all public directories and
1258 * files, previously designated by app_setup_path(APP_PATH_PUBLIC_RO)
1259 * This should be call in app_install function.
1261 static int register_app_for_public_dirs(const char *app_id, struct smack_accesses *smack)
1263 C_LOGD("Enter function: %s", __func__);
1265 char **public_dirs AUTO_FREE;
1266 int public_dirs_cnt = 0;
1268 ret = db_get_public_dirs(&public_dirs, &public_dirs_cnt);
1269 if (ret != PC_OPERATION_SUCCESS) {
1270 C_LOGE("Error while geting data from database");
1274 for (i = 0; i < public_dirs_cnt; ++i) {
1275 C_LOGD("Allowing app %s to access public path %s", app_id, public_dirs[i]);
1276 if (smack_accesses_add_modify(smack, app_id, public_dirs[i], "rx", "")) {
1277 C_LOGE("app_add_rule_modify failed");
1278 while (i < public_dirs_cnt)
1279 free(public_dirs[i++]);
1280 return PC_ERR_INVALID_OPERATION;
1282 free(public_dirs[i]);
1285 return PC_OPERATION_SUCCESS;
1288 static int app_add_permissions_internal(const char* app_id, app_type_t app_type, const char** perm_list, int permanent)
1290 C_LOGD("Enter function: %s", __func__);
1291 char* smack_path AUTO_FREE;
1294 struct smack_accesses *smack AUTO_SMACK_FREE;
1295 const char* base_perm = NULL;
1297 if (!smack_label_is_valid(app_id))
1298 return PC_ERR_INVALID_PARAM;
1300 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1301 if (ret != PC_OPERATION_SUCCESS) {
1302 C_LOGE("load_smack_from_file failed");
1306 /* Implicitly enable base permission for an app_type */
1307 base_perm = app_type_name(app_type);
1309 C_LOGD("perm_to_smack params: app_id: %s, %s", app_id, base_perm);
1310 ret = perm_to_smack(smack, app_id, APP_TYPE_OTHER, base_perm);
1311 if (ret != PC_OPERATION_SUCCESS){
1312 C_LOGE("perm_to_smack failed");
1316 for (i = 0; perm_list[i] != NULL; ++i) {
1317 C_LOGD("perm_to_smack params: app_id: %s, perm_list[%d]: %s", app_id, i, perm_list[i]);
1318 if (strcmp(perm_list[i], TIZEN_PRIVILEGE_ANTIVIRUS) == 0) {
1319 ret = app_register_av_internal(app_id, smack);
1320 if (ret != PC_OPERATION_SUCCESS) {
1321 C_LOGE("app_register_av_internal failed");
1325 if (strcmp(perm_list[i], TIZEN_PRIVILEGE_APPSETTING) == 0) {
1326 ret = app_register_appsetting(app_id, smack);
1327 if (ret != PC_OPERATION_SUCCESS) {
1328 C_LOGE("app_register_appsetting failed");
1333 ret = perm_to_smack(smack, app_id, app_type, perm_list[i]);
1334 if (ret != PC_OPERATION_SUCCESS){
1335 C_LOGE("perm_to_smack failed");
1339 ret = perm_to_dac(app_id, app_type, perm_list[i]);
1340 if (ret != PC_OPERATION_SUCCESS){
1341 C_LOGE("perm_to_dac failed");
1346 if (have_smack() && smack_accesses_apply(smack)) {
1347 C_LOGE("smack_accesses_apply failed");
1348 return PC_ERR_INVALID_OPERATION;
1351 if (permanent && smack_accesses_save(smack, fd)) {
1352 C_LOGE("smack_accesses_save failed");
1353 return PC_ERR_INVALID_OPERATION;
1356 return PC_OPERATION_SUCCESS;
1359 API int app_add_permissions(const char* app_id, const char** perm_list)
1361 C_LOGD("Enter function: %s", __func__);
1362 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 1);
1365 API int app_add_volatile_permissions(const char* app_id, const char** perm_list)
1367 C_LOGD("Enter function: %s", __func__);
1368 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 0);
1371 API int app_enable_permissions(const char* app_id, app_type_t app_type, const char** perm_list, bool persistent)
1373 C_LOGD("Enter function: %s", __func__);
1374 return app_add_permissions_internal(app_id, app_type, perm_list, persistent);
1377 /* FIXME: this function is only a stub */
1378 API int app_disable_permissions(const char* app_id, app_type_t app_type, const char** perm_list)
1380 C_LOGD("Enter function: %s", __func__);
1381 return PC_OPERATION_SUCCESS;
1384 static int app_revoke_permissions_internal(const char* app_id, bool persistent)
1386 C_LOGD("Enter function: %s", __func__);
1387 char* smack_path AUTO_FREE;
1390 struct smack_accesses *smack AUTO_SMACK_FREE;
1392 if (!smack_label_is_valid(app_id))
1393 return PC_ERR_INVALID_PARAM;
1395 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1396 if (ret != PC_OPERATION_SUCCESS) {
1397 C_LOGE("load_smack_from_file failed");
1401 if (have_smack() && smack_accesses_clear(smack)) {
1402 ret = PC_ERR_INVALID_OPERATION;
1403 C_LOGE("smack_accesses_clear failed");
1407 if (have_smack() && smack_revoke_subject(app_id)) {
1408 ret = PC_ERR_INVALID_OPERATION;
1409 C_LOGE("smack_revoke_subject failed");
1413 if (persistent && ftruncate(fd, 0) == -1)
1414 C_LOGE("file truncate failed");
1416 return PC_OPERATION_SUCCESS;
1419 API int app_revoke_permissions(const char* app_id)
1421 C_LOGD("Enter function: %s", __func__);
1424 if (!smack_label_is_valid(app_id))
1425 return PC_ERR_INVALID_PARAM;
1427 ret = app_revoke_permissions_internal(app_id, true);
1429 C_LOGE("Revoking permissions failed");
1433 return PC_OPERATION_SUCCESS;
1436 API int app_reset_permissions(const char* app_id)
1438 C_LOGD("Enter function: %s", __func__);
1441 if (!smack_label_is_valid(app_id))
1442 return PC_ERR_INVALID_PARAM;
1444 ret = app_revoke_permissions_internal(app_id, false);
1446 C_LOGE("Revoking permissions failed");
1450 /* Add empty permissions set to trigger re-read of rules */
1451 return app_enable_permissions(app_id, APP_TYPE_OTHER, (const char*[]){NULL}, 0);
1454 API int app_label_dir(const char* label, const char* path)
1456 C_LOGD("Enter function: %s", __func__);
1458 int ret = PC_OPERATION_SUCCESS;
1460 if (!smack_label_is_valid(label))
1461 return PC_ERR_INVALID_PARAM;
1463 //setting access label on everything in given directory and below
1464 ret = dir_set_smack_r(path, label, SMACK_LABEL_ACCESS, &label_all);
1465 if (PC_OPERATION_SUCCESS != ret)
1468 //setting execute label for everything with permission to execute
1469 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_execs);
1470 if (PC_OPERATION_SUCCESS != ret)
1473 //setting execute label for everything with permission to execute
1474 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_links_to_execs);
1478 int smack_get_access_new(const char* subject, const char* object, char** label)
1480 char buff[ACC_LEN] = {'r', 'w', 'x', 'a', 't'};
1481 char perm[2] = {'-'};
1484 if(!smack_label_is_valid(subject) || !smack_label_is_valid(object) || !label)
1485 return PC_ERR_INVALID_PARAM;
1487 for (i=0; i<ACC_LEN; ++i) {
1489 int ret = smack_have_access(subject, object, perm);
1491 return PC_ERR_INVALID_OPERATION;
1496 *label = malloc(ACC_LEN+1);
1498 return PC_ERR_MEM_OPERATION;
1500 memcpy(*label, buff, ACC_LEN);
1501 (*label)[ACC_LEN] = 0;
1502 return PC_OPERATION_SUCCESS;
1506 * This function will be used to allow direct communication between 2 OSP application.
1507 * This function requires to store "state" with list of added label.
1509 * Full implementation requires some kind of database. This implemetation works without
1510 * database so you wont be able to revoke permissions added by different process.
1512 API int app_give_access(const char* subject, const char* object, const char* permissions)
1514 C_LOGD("Enter function: %s", __func__);
1515 int ret = PC_OPERATION_SUCCESS;
1516 struct smack_accesses *smack AUTO_SMACK_FREE;
1517 char *current_permissions AUTO_FREE;
1520 return PC_OPERATION_SUCCESS;
1522 if (!smack_label_is_valid(subject) || !smack_label_is_valid(object)) {
1523 C_LOGE("Error in %s: invalid param.", __func__);
1524 return PC_ERR_INVALID_PARAM;
1527 if (PC_OPERATION_SUCCESS != (ret = smack_get_access_new(subject, object, ¤t_permissions))) {
1528 C_LOGE("Error in %s: smack_get_access_new failed.", __func__);
1532 if (smack_accesses_new(&smack)) {
1533 C_LOGE("Error in %s: smack_accesses_new failed.", __func__);
1534 return PC_ERR_MEM_OPERATION;
1537 if (smack_accesses_add_modify(smack, subject, object, permissions, "")) {
1538 C_LOGE("Error in %s: smack_accesses_add_modify failed.", __func__);
1539 return PC_ERR_MEM_OPERATION;
1542 if (smack_accesses_apply(smack)) {
1543 C_LOGE("Error in %s: smack_accesses_apply failed.", __func__);
1544 return PC_ERR_NOT_PERMITTED;
1547 return state_save(subject, object, current_permissions);
1551 * This function will be used to revoke direct communication between 2 OSP application.
1553 * Full implementation requires some kind of database. This implemetation works without
1554 * database so you wont be able to revoke permissions added by different process.
1556 API int app_revoke_access(const char* subject, const char* object)
1558 C_LOGD("Enter function: %s", __func__);
1560 return PC_OPERATION_SUCCESS;
1562 if (!smack_label_is_valid(subject) || !smack_label_is_valid(object)) {
1563 C_LOGE("Error in %s: invalid param.", __func__);
1564 return PC_ERR_INVALID_PARAM;
1567 return state_restore(subject, object);
1570 API int app_label_shared_dir(const char* app_label, const char* shared_label, const char* path)
1572 C_LOGD("Enter function: %s", __func__);
1575 if (!smack_label_is_valid(app_label) || !smack_label_is_valid(shared_label))
1576 return PC_ERR_INVALID_PARAM;
1578 if (strcmp(app_label, shared_label) == 0) {
1579 C_LOGE("app_label equals shared_label");
1580 return PC_ERR_INVALID_PARAM;
1583 //setting label on everything in given directory and below
1584 ret = dir_set_smack_r(path, shared_label, SMACK_LABEL_ACCESS, label_all);
1585 if(ret != PC_OPERATION_SUCCESS){
1586 C_LOGE("dir_set_smakc_r failed");
1590 //setting transmute on dir
1591 ret = dir_set_smack_r(path, "1", SMACK_LABEL_TRANSMUTE, label_dirs);
1592 if (ret != PC_OPERATION_SUCCESS) {
1593 C_LOGE("dir_set_smakc_r failed");
1597 ret = app_add_rule(app_label, shared_label, "rwxat");
1598 if (ret != PC_OPERATION_SUCCESS) {
1599 C_LOGE("app_add_rule failed");
1603 return PC_OPERATION_SUCCESS;
1606 API int add_shared_dir_readers(const char* shared_label, const char** app_list)
1608 C_LOGD("Enter function: %s", __func__);
1612 if (!smack_label_is_valid(shared_label))
1613 return PC_ERR_INVALID_PARAM;
1615 for (i = 0; app_list[i] != NULL; i++) {
1617 if (!smack_label_is_valid(app_list[i]))
1618 return PC_ERR_INVALID_PARAM;
1620 ret = app_add_rule(app_list[i], shared_label, "rx");
1621 if (ret != PC_OPERATION_SUCCESS) {
1622 C_LOGE("app_add_rule failed");
1627 return PC_OPERATION_SUCCESS;
1630 static char* smack_label_for_path(const char *app_id, const char *path)
1632 C_LOGD("Enter function: %s", __func__);
1633 char *salt AUTO_FREE;
1637 /* Prefix $1$ causes crypt() to use MD5 function */
1638 if (-1 == asprintf(&salt, "$1$%s", app_id)) {
1639 C_LOGE("asprintf failed");
1643 label = crypt(path, salt);
1644 if (label == NULL) {
1645 C_LOGE("crypt failed");
1649 /* crypt() output may contain slash character,
1650 * which is not legal in Smack labels */
1651 for (x = label; *x; ++x) {
1658 /* FIXME: remove this pragma once deprecated API is deleted */
1659 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1660 API int app_setup_path(const char* app_id, const char* path, app_path_type_t app_path_type, ...)
1662 C_LOGD("Enter function: %s", __func__);
1665 if (!smack_label_is_valid(app_id)) {
1666 C_LOGE("Invalid app_id %s", app_id);
1667 return PC_ERR_INVALID_PARAM;
1670 switch (app_path_type) {
1671 case APP_PATH_PRIVATE:
1672 va_start(ap, app_path_type);
1674 return app_label_dir(app_id, path);
1676 case APP_PATH_GROUP_RW: {
1677 const char *shared_label;
1679 va_start(ap, app_path_type);
1680 shared_label = va_arg(ap, const char *);
1683 if (!smack_label_is_valid(shared_label)) {
1684 C_LOGE("Invalid shared_label %s", shared_label);
1685 return PC_ERR_INVALID_PARAM;
1688 if (strcmp(app_id, shared_label) == 0) {
1689 C_LOGE("app_id equals shared_label");
1690 return PC_ERR_INVALID_PARAM;
1693 return app_label_shared_dir(app_id, shared_label, path);
1696 case APP_PATH_PUBLIC_RO: {
1697 char **app_ids AUTO_FREE;
1698 int app_ids_cnt = 0;
1702 va_start(ap, app_path_type);
1705 C_LOGD("New public RO path %s", path);
1706 label = smack_label_for_path(app_id, path);
1708 return PC_ERR_INVALID_OPERATION;
1710 C_LOGD("Generated label '%s' for public RO path %s", label, path);
1711 ret = app_label_shared_dir(app_id, label, path);
1712 if (ret != PC_OPERATION_SUCCESS)
1715 /* FIXME: This should be in some kind of transaction/lock */
1716 ret = db_add_public_dir(label);
1717 if (ret != PC_OPERATION_SUCCESS)
1720 ret = get_all_apps_ids(&app_ids, &app_ids_cnt);
1721 if (ret != PC_OPERATION_SUCCESS)
1724 for (i = 0; i < app_ids_cnt; ++i) {
1725 C_LOGD("Allowing app %s to access public path %s", app_id, label[i]);
1726 ret = app_add_rule(app_ids[i], label, "rx");
1727 if (ret != PC_OPERATION_SUCCESS) {
1728 C_LOGE("smack_accesses_new failed");
1729 while (i < app_ids_cnt)
1736 return PC_OPERATION_SUCCESS;
1739 case APP_PATH_SETTINGS_RW:
1741 char **app_ids AUTO_FREE;
1742 int app_ids_cnt = 0;
1747 va_start(ap, app_path_type);
1751 label = smack_label_for_path(app_id, path);
1753 return PC_ERR_INVALID_OPERATION;
1755 /*set id for path and all subfolders*/
1756 C_LOGD("Appsetting: generated label '%s' for setting path %s", label, path);
1757 ret = app_label_shared_dir(app_id, label, path);
1758 if (ret != PC_OPERATION_SUCCESS) {
1759 C_LOGE("Appsetting: app_label_shared_dir failed (%d)", ret);
1763 /*add path to database*/
1764 /* FIXME: This should be in some kind of transaction/lock */
1765 ret = add_setting_dir_id_to_databse(label);
1766 if (ret != PC_OPERATION_SUCCESS) {
1767 C_LOGE("Appsetting: add_setting_dir_id_to_databse failed");
1771 /*read all apps with appsetting privilege*/
1772 ret = get_all_appsetting_ids(&app_ids, &app_ids_cnt);
1773 if (ret != PC_OPERATION_SUCCESS) {
1774 C_LOGE("Appsetting: get_all_appsetting_ids failed");
1777 C_LOGD("Appsetting: %d appsetting privileged apps registeres",
1780 /*give RWX rights to all apps that have appsetting privilege*/
1781 for (i = 0; i < app_ids_cnt; ++i) {
1782 C_LOGD("Appsetting: allowing app %s to access setting path %s",
1784 ret = app_add_rule(app_ids[i], label, "rwx");
1785 if (ret != PC_OPERATION_SUCCESS) {
1786 C_LOGE("app_add_rule failed");
1787 while (i < app_ids_cnt)
1794 return PC_OPERATION_SUCCESS;
1797 va_start(ap, app_path_type);
1799 return PC_ERR_INVALID_PARAM;
1802 return PC_OPERATION_SUCCESS;
1804 /* FIXME: remove this pragma once deprecated API is deleted */
1805 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
1807 API int app_add_friend(const char* app_id1, const char* app_id2)
1809 C_LOGD("Enter function: %s", __func__);
1812 if (!smack_label_is_valid(app_id1) || !smack_label_is_valid(app_id2))
1813 return PC_ERR_INVALID_PARAM;
1815 ret = app_add_rule(app_id1, app_id2, "rwxat");
1816 if (ret != PC_OPERATION_SUCCESS) {
1817 C_LOGE("app_add_rule failed");
1821 ret = app_add_rule(app_id2, app_id1, "rwxat");
1822 if (ret != PC_OPERATION_SUCCESS) {
1823 C_LOGE("app_add_rule failed");
1827 return PC_OPERATION_SUCCESS;
1830 API int app_install(const char* app_id)
1832 C_LOGD("Enter function: %s", __func__);
1835 char* smack_path AUTO_FREE;
1836 struct smack_accesses *smack AUTO_SMACK_FREE;
1838 if (!smack_label_is_valid(app_id))
1839 return PC_ERR_INVALID_PARAM;
1841 ret = smack_file_name(app_id, &smack_path);
1842 if (ret != PC_OPERATION_SUCCESS)
1845 fd = open(smack_path, O_RDWR|O_CREAT, 0644);
1847 C_LOGE("file open failed: %s", strerror(errno));
1848 return PC_ERR_FILE_OPERATION;
1851 if (smack_accesses_new(&smack)) {
1852 C_LOGE("smack_accesses_new failed");
1853 return PC_ERR_MEM_OPERATION;
1856 ret = add_app_id_to_databse(app_id);
1857 if (ret != PC_OPERATION_SUCCESS ) {
1858 C_LOGE("Error while adding app %s to database: %s ", app_id, strerror(errno));
1862 ret = register_app_for_av(app_id);
1863 if (ret != PC_OPERATION_SUCCESS) {
1864 C_LOGE("Error while adding rules for anti viruses to app %s: %s ", app_id, strerror(errno));
1868 ret = register_app_for_appsetting(app_id);
1869 if (ret != PC_OPERATION_SUCCESS) {
1870 C_LOGE("Error while adding rules for setting managers to app %s: %s ", app_id, strerror(errno));
1874 ret = register_app_for_public_dirs(app_id, smack);
1875 if (ret != PC_OPERATION_SUCCESS) {
1876 C_LOGE("Error while adding rules for access to public dirs for app %s: %s ", app_id, strerror(errno));
1880 if (have_smack() && smack_accesses_apply(smack)) {
1881 C_LOGE("smack_accesses_apply failed");
1882 return PC_ERR_INVALID_OPERATION;
1885 if (smack_accesses_save(smack, fd)) {
1886 C_LOGE("smack_accesses_save failed");
1887 return PC_ERR_INVALID_OPERATION;
1890 return PC_OPERATION_SUCCESS;
1893 API int app_uninstall(const char* app_id)
1895 // TODO: When real database will be used, then this function should remove app_id
1897 // It also should remove rules looks like: "anti_virus_label app_id rwx".
1898 C_LOGD("Enter function: %s", __func__);
1899 char* smack_path AUTO_FREE;
1902 if (!smack_label_is_valid(app_id))
1903 return PC_ERR_INVALID_PARAM;
1905 ret = smack_file_name(app_id, &smack_path);
1906 if (ret != PC_OPERATION_SUCCESS)
1909 if (unlink(smack_path)) {
1910 C_LOGE("unlink failed: ", strerror(errno));
1911 return PC_OPERATION_SUCCESS;
1914 return PC_OPERATION_SUCCESS;
1917 static int save_rules(int fd, struct smack_accesses* accesses) {
1918 if (flock(fd, LOCK_EX)) {
1919 C_LOGE("flock failed, error %s", strerror(errno));
1920 return PC_ERR_FILE_OPERATION;
1923 if (smack_accesses_save(accesses, fd)) {
1924 C_LOGE("smack_accesses_save failed");
1925 return PC_ERR_FILE_OPERATION;
1927 return PC_OPERATION_SUCCESS ;
1930 static int validate_and_add_rule(char* rule, struct smack_accesses* accesses) {
1931 const char* subject = NULL;
1932 const char* object = NULL;
1933 const char* access = NULL;
1934 char* saveptr = NULL;
1936 subject = strtok_r(rule, " \t\n", &saveptr);
1937 object = strtok_r(NULL, " \t\n", &saveptr);
1938 access = strtok_r(NULL, " \t\n", &saveptr);
1940 // check rule validity
1941 if (subject == NULL ||
1944 strtok_r(NULL, " \t\n", &saveptr) != NULL ||
1945 !smack_label_is_valid(subject) ||
1946 !smack_label_is_valid(object))
1948 C_LOGE("Incorrect rule format: %s", rule);
1949 return PC_ERR_INVALID_PARAM;
1952 if (smack_accesses_add_modify(accesses, subject, object, access, "")) {
1953 C_LOGE("smack_accesses_add_modify failed");
1954 return PC_ERR_INVALID_OPERATION;
1956 return PC_OPERATION_SUCCESS ;
1959 static int parse_and_save_rules(const char** smack_rules,
1960 struct smack_accesses* accesses, const char* feature_file) {
1963 int ret = PC_OPERATION_SUCCESS;
1966 for (i = 0; smack_rules[i] != NULL ; i++) {
1967 // ignore empty lines
1968 if (strspn(smack_rules[i], " \t\n") == strlen(smack_rules[i]))
1971 tmp = strdup(smack_rules[i]);
1972 ret = validate_and_add_rule(tmp, accesses);
1974 if (ret != PC_OPERATION_SUCCESS )
1979 fd = open(feature_file, O_CREAT | O_WRONLY, 0644);
1981 C_LOGE("Unable to create file %s. Error: %s", feature_file, strerror(errno));
1982 return PC_ERR_FILE_OPERATION;
1985 ret = save_rules(fd, accesses);
1990 static int save_gids(FILE* file, const gid_t* list_of_db_gids, size_t list_size) {
1991 int ret = PC_OPERATION_SUCCESS;
1996 C_LOGE("Unable to create file. Error: %s", strerror(errno));
1997 return PC_ERR_FILE_OPERATION; // TODO remove smack accesses?
2000 if(-1 == fchmod(fileno(file), 0644)) {
2001 C_LOGE("Unable to chmod file. Error: %s", strerror(errno));
2002 return PC_ERR_FILE_OPERATION;
2005 for (i = 0; i < list_size ; ++i) {
2006 written = fprintf(file, "%u\n", list_of_db_gids[i]);
2008 C_LOGE("fprintf failed for file. Error: %s", strerror(errno));
2009 ret = PC_ERR_FILE_OPERATION;
2016 API int add_api_feature(app_type_t app_type,
2017 const char* api_feature_name,
2018 const char** smack_rules,
2019 const gid_t* list_of_db_gids,
2021 C_LOGD("Enter function: %s", __func__);
2023 int ret = PC_OPERATION_SUCCESS;
2024 char* smack_file AUTO_FREE;
2025 char* dac_file AUTO_FREE;
2026 struct smack_accesses* accesses = NULL;
2029 // TODO check process capabilities
2031 // get feature SMACK file name
2032 ret = perm_file_path(&smack_file, app_type, api_feature_name, ".smack");
2033 if (ret != PC_OPERATION_SUCCESS || !smack_file ) {
2037 // check if feature exists
2038 if (file_exists(smack_file)) {
2039 C_LOGE("Feature file %s already exists", smack_file);
2040 return PC_ERR_INVALID_PARAM;
2043 // check .dac existence only if gids are supported
2044 if (list_of_db_gids && list_size > 0) {
2045 // get feature DAC file name
2046 ret = perm_file_path(&dac_file, app_type, api_feature_name, ".dac");
2047 if (ret != PC_OPERATION_SUCCESS || !dac_file ) {
2051 // check if feature exists
2052 if (file_exists(dac_file)) {
2053 C_LOGE("Feature file %s already exists", dac_file);
2054 return PC_ERR_INVALID_PARAM;
2058 // parse & save rules
2060 if (smack_accesses_new(&accesses)) {
2061 C_LOGE("smack_acceses_new failed");
2062 return PC_ERR_MEM_OPERATION;
2065 ret = parse_and_save_rules(smack_rules, accesses, smack_file);
2066 smack_accesses_free(accesses);
2069 // go through gid list
2070 if (ret == PC_OPERATION_SUCCESS && list_of_db_gids && list_size > 0) {
2072 file = fopen(dac_file, "w+");
2073 ret = save_gids(file, list_of_db_gids, list_size);
2077 // remove both files in case of failure
2078 if (ret != PC_OPERATION_SUCCESS) {
2087 * This function is marked as deprecated and will be removed
2089 API int app_register_av(const char* app_av_id)
2093 char* smack_path AUTO_FREE;
2094 struct smack_accesses* smack AUTO_SMACK_FREE;
2096 ret = load_smack_from_file(app_av_id, &smack, &fd, &smack_path);
2097 if (ret != PC_OPERATION_SUCCESS ) {
2098 C_LOGE("load_smack_from_file failed");
2102 ret = app_register_av_internal(app_av_id, smack);
2103 if (PC_OPERATION_SUCCESS != ret) {
2104 C_LOGE("app_register_av_internal failed");
2108 // Add permisions from OSP_antivirus.samck file
2109 ret = perm_to_smack(smack, app_av_id, APP_TYPE_OSP, TIZEN_PRIVILEGE_ANTIVIRUS);
2110 if (PC_OPERATION_SUCCESS != ret) {
2111 C_LOGE("perm_to_smack failed");
2115 // Add permisions from OSP_antivirus.dac file
2116 ret = perm_to_dac(app_av_id, APP_TYPE_OSP, TIZEN_PRIVILEGE_ANTIVIRUS);
2117 if (ret != PC_OPERATION_SUCCESS) {
2118 C_LOGE("perm_to_dac failed");
2122 if (have_smack() && smack_accesses_apply(smack)) {
2123 C_LOGE("smack_accesses_apply failed");
2124 ret = PC_ERR_INVALID_OPERATION;
2128 if (smack_accesses_save(smack, fd)) {
2129 C_LOGE("smack_accesses_save failed");
2130 ret = PC_ERR_INVALID_OPERATION;