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>
42 #include "privilege-control.h"
43 #include "access-db.h"
48 #define DEVELOPER_GID 5100
49 #define DEVELOPER_UID 5100
51 #define APP_USER_NAME "app"
52 #define DEV_USER_NAME "developer"
54 #define APP_HOME_DIR TOSTRING(HOMEDIR) "/app"
55 #define DEV_HOME_DIR TOSTRING(HOMEDIR) "/developer"
57 #define APP_GROUP_PATH TOSTRING(SHAREDIR) "/app_group_list"
58 #define DEV_GROUP_PATH TOSTRING(SHAREDIR) "/dev_group_list"
60 #define SMACK_RULES_DIR "/etc/smack/accesses.d/"
62 #define SMACK_APP_LABEL_TEMPLATE "~APP~"
63 #define SMACK_SRC_FILE_SUFFIX "_src_file"
64 #define SMACK_SRC_DIR_SUFFIX "_src_dir"
65 #define SMACK_DATA_SUFFIX "_data"
66 #define WRT_BASE_DEVCAP "WRT"
67 #define WRT_CLIENT_PATH "/usr/bin/wrt-client"
69 #define SMACK_ANTIVIRUS_PERM "antivirus"
71 static int set_smack_for_wrt(char **smack_label, const char* widget_id);
81 typedef struct state_node_t {
85 static void *state_tree = NULL;
87 int state_tree_cmp(const void *first, const void *second)
89 return strcmp(((state_node*)first)->key,
90 ((state_node*)second)->key);
93 int state_tree_push(const char* key_param, const char* value_param)
95 state_node *node = malloc(sizeof(state_node));
96 char *key = strdup(key_param);
97 char *value = strdup(value_param);
99 if (!node || !key || !value) {
103 return PC_ERR_MEM_OPERATION;
109 if (NULL != tfind(node, &state_tree, state_tree_cmp)){
113 return PC_OPERATION_SUCCESS; // 04.2013 Temporary fix. Allow for multiple call of app_give_access
116 tsearch(node, &state_tree, state_tree_cmp);
117 return PC_OPERATION_SUCCESS;
120 char* state_tree_pop_new(char *key)
122 state_node search, *node;
128 wtf = tfind(&search, &state_tree, state_tree_cmp);
132 node = *(state_node**)wtf;
136 tdelete(node, &state_tree, state_tree_cmp);
144 int state_save(const char *subject, const char *object, const char *perm)
147 if (-1 == asprintf(&key, "%s|%s", subject, object))
148 return PC_ERR_INVALID_OPERATION;
149 int ret = state_tree_push(key, perm);
154 int state_restore(const char* subject, const char* object)
157 char *perm AUTO_FREE;
158 struct smack_accesses *smack AUTO_SMACK_FREE;
160 if (-1 == asprintf(&key, "%s|%s", subject, object))
161 return PC_ERR_INVALID_OPERATION;
163 perm = state_tree_pop_new(key);
165 return PC_ERR_INVALID_OPERATION;
167 if (smack_accesses_new(&smack))
168 return PC_ERR_MEM_OPERATION;
170 if (smack_accesses_add(smack, subject, object, perm))
171 return PC_ERR_MEM_OPERATION;
173 if (smack_accesses_apply(smack))
174 return PC_ERR_NOT_PERMITTED;
176 return PC_OPERATION_SUCCESS;
179 static inline int have_smack(void)
181 static int have_smack = -1;
183 if (-1 == have_smack) {
184 if (NULL == smack_smackfs_path()) {
185 C_LOGD("Libprivilage-control: no smack found on phone");
188 C_LOGD("Libprivilege-control: found smack on phone");
196 API int control_privilege(void)
198 C_LOGD("Enter function: %s", __func__);
199 if(getuid() == APP_UID) // current user is 'app'
200 return PC_OPERATION_SUCCESS;
202 if(set_app_privilege("org.tizen.", NULL, NULL) == PC_OPERATION_SUCCESS)
203 return PC_OPERATION_SUCCESS;
205 return PC_ERR_NOT_PERMITTED;
210 static int get_user_groups(uid_t user_id, int *nbgroup, gid_t **groups_list)
212 gid_t *groups = NULL;
214 C_LOGD("Enter function: %s", __func__);
216 if ((!groups_list) || (!nbgroup))
217 return PC_ERR_INVALID_OPERATION;
218 pw = getpwuid(user_id);
220 C_LOGE("getgrouplist fails : Invalid User ID %d",user_id);
221 return PC_ERR_INVALID_OPERATION;
224 //First call is done with *ngroup = 0 to get the number of groups found for the user (Usefull for next malloc operation). It should return -1 in this case.
225 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, nbgroup) != -1)
226 return PC_ERR_INVALID_OPERATION;
228 C_LOGD("getgrouplist %s user is member of %d groups ",pw->pw_name,*nbgroup);
229 groups = malloc(*nbgroup * sizeof (gid_t));
231 return PC_ERR_INVALID_OPERATION;
232 //Second call is done with the suitable ngroup value and structure groups allocated.
233 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, nbgroup) == -1) {
235 C_LOGE("getgrouplist fails %d",nbgroup);
236 return PC_ERR_INVALID_OPERATION;
238 *groups_list = groups;
239 return PC_OPERATION_SUCCESS;
242 static int set_dac(const char *smack_label, const char *pkg_name)
244 C_LOGD("Enter function: %s", __func__);
245 uid_t t_uid = -1; // uid of current process
246 gid_t *glist = NULL; // group list
247 int glist_cnt = 0; // for group list
251 unsigned *additional_gids = NULL;
254 * initialize user structure
256 C_LOGD("initialize user structure");
257 memset(usr.user_name, 0x00, 10);
258 memset(usr.home_dir, 0x00, 64);
259 memset(usr.group_list, 0x00, 64);
264 C_LOGD("Current uid is %d", t_uid);
266 if(t_uid == 0) // current user is 'root'
268 if(!strncmp(pkg_name, "developer", 9))
270 strncpy(usr.user_name, DEV_USER_NAME, sizeof(usr.user_name));
271 usr.uid = DEVELOPER_UID;
272 usr.gid = DEVELOPER_GID;
273 strncpy(usr.home_dir, DEV_HOME_DIR, sizeof(usr.home_dir));
274 strncpy(usr.group_list, DEV_GROUP_PATH, sizeof(usr.group_list));
278 strncpy(usr.user_name, APP_USER_NAME, sizeof(usr.user_name));
281 strncpy(usr.home_dir, APP_HOME_DIR, sizeof(usr.home_dir));
285 * get group information
287 C_LOGD("get group information");
288 if (get_user_groups(usr.uid, &glist_cnt, &glist)) {
289 result = PC_ERR_FILE_OPERATION; // return -1
296 result = get_app_gids(smack_label, &additional_gids, &cnt);
297 if (result != PC_OPERATION_SUCCESS)
301 glist_new = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + cnt));
302 if (glist_new == NULL) {
303 result = PC_ERR_MEM_OPERATION; // return -2
304 C_LOGE("Cannot allocate memory");
308 for (i = 0; i < cnt; ++i) {
309 C_LOGD("Additional GID based on enabled permissions: %u", additional_gids[i]);
310 glist[glist_cnt++] = additional_gids[i];
318 C_LOGD("Adding process to the following groups:");
319 for(i=0; i<glist_cnt; ++i) {
320 C_LOGD("glist [ %d ] = %d", i, glist[i]);
322 C_LOGD("setgroups()");
323 if(setgroups(glist_cnt, glist) != 0)
325 C_LOGE("[ERR] setgrouops fail\n");
326 result = PC_ERR_NOT_PERMITTED; // return -3
336 * setuid() & setgid()
338 C_LOGD("setgid( %d ) & setuid( %d )", usr.gid, usr.uid);
339 if(setgid(usr.gid) != 0) // fail
341 C_LOGE("[ERR] fail to execute setgid().");
342 result = PC_ERR_INVALID_OPERATION;
345 if(setuid(usr.uid) != 0) // fail
347 C_LOGE("[ERR] fail to execute setuid().");
348 result = PC_ERR_INVALID_OPERATION;
352 C_LOGD("setenv(): USER = %s, HOME = %s", usr.user_name, usr.home_dir);
353 if(setenv("USER", usr.user_name, 1) != 0) //fail
355 C_LOGE("[ERR] fail to execute setenv() [USER].");
356 result = PC_ERR_INVALID_OPERATION;
359 if(setenv("HOME", usr.home_dir, 1) != 0) // fail
361 C_LOGE("[ERR] fail to execute setenv() [HOME].");
362 result = PC_ERR_INVALID_OPERATION;
366 else // current user is not only 'root' but 'app'
368 C_LOGE("[ERR] current user is NOT root\n");
369 result = PC_ERR_NOT_PERMITTED; // return -3
373 result = PC_OPERATION_SUCCESS;
378 free(additional_gids);
384 * Set process SMACK label from EXEC label of a file.
385 * This function is emulating EXEC label behaviour of SMACK for programs
386 * run by dlopen/dlsym instead of execv.
388 * @param path file path to take label from
389 * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
391 static int set_smack_from_binary(char **smack_label, const char* path)
393 C_LOGD("Enter function: %s", __func__);
396 C_LOGD("Path: %s", path);
399 ret = smack_getlabel(path, smack_label, SMACK_LABEL_EXEC);
401 C_LOGE("Getting exec label from file %s failed", path);
402 return PC_ERR_INVALID_OPERATION;
405 if (*smack_label == NULL) {
406 /* No label to set, just return with success */
407 C_LOGD("No label to set, just return with success");
408 ret = PC_OPERATION_SUCCESS;
411 C_LOGD("label = %s", *smack_label);
413 ret = smack_set_label_for_self(*smack_label);
414 C_LOGD("smack_set_label_for_self returned %d", ret);
416 ret = PC_OPERATION_SUCCESS;
422 static int is_widget(const char* path)
424 C_LOGD("Enter function: %s", __func__);
425 char buf[sizeof(WRT_CLIENT_PATH)];
428 ret = readlink(path, buf, sizeof(WRT_CLIENT_PATH));
430 C_LOGD("readlink(%s) returned error: %s. Assuming that app is not a widget", path, strerror(errno));
431 else if (ret == sizeof(WRT_CLIENT_PATH))
432 C_LOGD("%s is not a widget", path);
433 if (ret == -1 || ret == sizeof(WRT_CLIENT_PATH))
436 C_LOGD("buf = %s", buf);
438 ret = !strcmp(WRT_CLIENT_PATH, buf);
439 C_LOGD("%s is %s widget", path, ret ? "a" : "not a");
444 * Partially verify, that the type given for app is correct.
445 * This function will use some heuristics to check whether the app type is right.
446 * It is intended for security hardening to catch privilege setting for the
447 * app type not corresponding to the actual binary.
448 * Beware - when it detects an anomaly, the whole process will be terminated.
450 * @param type claimed application type
451 * @param path file path to executable
452 * @return return void on success, terminate the process on error
454 static app_type_t verify_app_type(const char* type, const char* path)
456 C_LOGD("Enter function: %s", __func__);
457 /* TODO: this should actually be treated as error, but until the old
458 * set_privilege API is removed, it must be ignored */
460 C_LOGD("PKG_TYPE_OTHER");
461 return APP_TYPE_OTHER; /* good */
464 if (is_widget(path)) {
465 if (!strcmp(type, "wgt")) {
466 C_LOGD("PKG_TYPE_WGT");
467 return APP_TYPE_WGT; /* good */
470 if (type == NULL || strcmp(type, "wgt")){
471 C_LOGD("PKG_TYPE_OTHER");
472 return APP_TYPE_OTHER; /* good */
477 C_LOGE("EXIT_FAILURE");
481 static const char* parse_widget_id(const char* path)
483 C_LOGD("Enter function: %s", __func__);
484 const char* basename = strrchr(path, '/');
486 if (basename == NULL)
491 C_LOGD("return widget id: %s", basename);
495 API int perm_app_set_privilege(const char* name, const char* type, const char* path)
497 return PC_ERR_INVALID_OPERATION;
500 API int set_app_privilege(const char* name, const char* type, const char* path)
502 C_LOGD("Enter function: %s", __func__);
503 C_LOGD("Function params: name = %s, type = %s, path = %s", name, type, path);
504 const char* widget_id;
505 char *smack_label AUTO_FREE;
506 int ret = PC_OPERATION_SUCCESS;
508 switch(verify_app_type(type, path)) {
510 //widget_id = parse_widget_id(path);
512 if (widget_id == NULL) {
513 C_LOGE("PC_ERR_INVALID_PARAM");
514 ret = PC_ERR_INVALID_PARAM;
518 smack_label = strdup(widget_id);
519 ret = set_smack_from_binary(&smack_label, path);
524 ret = set_smack_from_binary(&smack_label, path);
528 if (ret != PC_OPERATION_SUCCESS)
531 return set_dac(smack_label, name);
534 API int set_privilege(const char* pkg_name)
536 C_LOGD("Enter function: %s", __func__);
537 return set_app_privilege(pkg_name, NULL, NULL);
540 static inline const char* app_type_name(app_type_t app_type)
552 static int perm_file_path(char** path, app_type_t app_type, const char* perm, const char *suffix)
554 const char* app_type_prefix = NULL;
555 const char* perm_basename = NULL;
558 if (perm == NULL || strlen(perm) == 0) {
559 C_LOGE("empty permission name");
560 return PC_ERR_INVALID_PARAM;
563 app_type_prefix = app_type_name(app_type);
565 perm_basename = strrchr(perm, '/');
569 perm_basename = perm;
571 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s",
572 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
573 perm_basename, suffix);
575 C_LOGE("asprintf failed");
576 return PC_ERR_MEM_OPERATION;
579 return PC_OPERATION_SUCCESS;
582 static bool file_exists(const char* path) {
583 FILE* file = fopen(path, "r");
591 static int perm_to_smack(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
593 C_LOGD("Enter function: %s", __func__);
595 char* path AUTO_FREE;
596 char* format_string AUTO_FREE;
597 FILE* file AUTO_FCLOSE;
598 char smack_subject[SMACK_LABEL_LEN + 1];
599 char smack_object[SMACK_LABEL_LEN + 1];
600 char smack_accesses[10];
602 // get file name for permission (devcap)
603 ret = perm_file_path(&path, app_type, perm, ".smack");
604 if (ret != PC_OPERATION_SUCCESS) {
605 C_LOGD("No smack config file for permission %s", perm);
609 if (asprintf(&format_string,"%%%ds %%%ds %%%lus\n",
610 SMACK_LABEL_LEN, SMACK_LABEL_LEN, (unsigned long)sizeof(smack_accesses)) == -1) {
611 C_LOGE("asprintf failed");
612 return PC_ERR_MEM_OPERATION;
615 file = fopen(path, "r");
616 C_LOGD("path = %s", path);
618 C_LOGE("fopen failed");
619 return PC_OPERATION_SUCCESS;
622 while (fscanf(file, format_string, smack_subject, smack_object, smack_accesses) == 3) {
623 if (!strcmp(smack_subject, SMACK_APP_LABEL_TEMPLATE))
624 strcpy(smack_subject, app_label);
626 if (!strcmp(smack_object, SMACK_APP_LABEL_TEMPLATE))
627 strcpy(smack_object, app_label);
629 C_LOGD("smack_accesses_add_modify (subject: %s, object: %s, access: %s)", smack_subject, smack_object, smack_accesses);
630 if (smack_accesses_add_modify(smack, smack_subject, smack_object, smack_accesses, "") != 0) {
631 C_LOGE("smack_accesses_add_modify failed");
632 return PC_ERR_INVALID_OPERATION;
636 return PC_OPERATION_SUCCESS;
639 static int perm_to_dac(const char* app_label, app_type_t app_type, const char* perm)
641 C_LOGD("Enter function: %s", __func__);
643 char* path AUTO_FREE;
644 FILE* file AUTO_FCLOSE;
647 ret = perm_file_path(&path, app_type, perm, ".dac");
648 if (ret != PC_OPERATION_SUCCESS) {
649 C_LOGD("No dac config file for permission %s", perm);
653 file = fopen(path, "r");
654 C_LOGD("path = %s", path);
656 C_LOGE("fopen failed");
657 return PC_OPERATION_SUCCESS;
660 while (fscanf(file, "%d\n", &gid) == 1) {
661 C_LOGD("Adding app_id %s to group %d", app_label, gid);
662 ret = add_app_gid(app_label, gid);
663 if (ret != PC_OPERATION_SUCCESS) {
664 C_LOGE("sadd_app_gid failed");
669 return PC_OPERATION_SUCCESS;
672 static int dir_set_smack_r(const char *path, const char* label,
673 enum smack_label_type type, mode_t type_mask)
675 C_LOGD("Enter function: %s", __func__);
677 const char* path_argv[] = {path, NULL};
681 ret = PC_ERR_FILE_OPERATION;
683 fts = fts_open((char * const *) path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
685 C_LOGE("fts_open failed");
689 while ((ftsent = fts_read(fts)) != NULL) {
690 /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
691 if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
692 C_LOGE("FTS_ERR error or failed stat(2) (FTS_NS)");
696 if (ftsent->fts_statp->st_mode & type_mask) {
697 C_LOGD("smack_lsetlabel (label: %s (type: %d), path: %s)", label, type, ftsent->fts_path);
698 if (smack_lsetlabel(ftsent->fts_path, label, type) != 0) {
699 C_LOGE("smack_lsetlabel failed");
705 /* If last call to fts_read() set errno, we need to return error. */
707 ret = PC_OPERATION_SUCCESS;
709 C_LOGE("Last errno: %s", strerror(errno));
717 static int set_smack_for_wrt(char **smack_label, const char* widget_id)
719 C_LOGD("Enter function: %s", __func__);
721 *smack_label = strdup(widget_id);
722 if (smack_label == NULL)
723 return PC_ERR_MEM_OPERATION;
726 return PC_OPERATION_SUCCESS;
729 ret = app_reset_permissions(widget_id);
730 if (ret != PC_OPERATION_SUCCESS) {
731 C_LOGE("app_reset_permissions failed");
735 if (smack_set_label_for_self(widget_id) != 0) {
736 C_LOGE("smack_set_label_for_self failed");
737 return PC_ERR_INVALID_OPERATION;
739 return PC_OPERATION_SUCCESS;
742 API char* perm_app_id_from_socket(int sockfd)
747 API char* app_id_from_socket(int sockfd)
749 C_LOGD("Enter function: %s", __func__);
756 ret = smack_new_label_from_socket(sockfd, &app_id);
758 C_LOGE("smack_new_label_from_socket failed");
762 C_LOGD("app_id: %s", app_id);
767 static int smack_file_name(const char* app_id, char** path)
769 if (asprintf(path, SMACK_RULES_DIR "/%s", app_id) == -1) {
770 C_LOGE("asprintf failed");
772 return PC_ERR_MEM_OPERATION;
775 return PC_OPERATION_SUCCESS;
778 static int load_smack_from_file(const char* app_id, struct smack_accesses** smack, int *fd, char** path)
780 C_LOGD("Enter function: %s", __func__);
783 ret = smack_file_name(app_id, path);
784 if (ret != PC_OPERATION_SUCCESS)
787 if (smack_accesses_new(smack)) {
788 C_LOGE("smack_accesses_new failed");
789 return PC_ERR_MEM_OPERATION;
792 *fd = open(*path, O_CREAT|O_RDWR, 0644);
794 C_LOGE("file open failed: %s", strerror(errno));
795 return PC_ERR_FILE_OPERATION;
798 if (flock(*fd, LOCK_EX)) {
799 C_LOGE("flock failed");
800 return PC_ERR_INVALID_OPERATION;
803 if (smack_accesses_add_from_file(*smack, *fd)) {
804 C_LOGE("smack_accesses_add_from_file failed");
805 return PC_ERR_INVALID_OPERATION;
808 /* Rewind the file */
809 if (lseek(*fd, 0, SEEK_SET) == -1) {
810 C_LOGE("lseek failed");
811 return PC_ERR_FILE_OPERATION;
814 return PC_OPERATION_SUCCESS;
818 * This function will check in database labels of all anti viruses
819 * and for all anti viruses will add a rule "anti_virus_label app_id rwx".
820 * This should be call in app_install function.
822 static int register_app_for_av(const char * app_id)
825 char** smack_label_av_list AUTO_FREE;
826 int smack_label_av_list_len = 0;
827 struct smack_accesses* smack AUTO_SMACK_FREE;
829 ret = smack_accesses_new(&smack);
830 if (ret != PC_OPERATION_SUCCESS) {
831 C_LOGE("smack_accesses_new failed");
835 // Reading labels of all installed anti viruses from "database"
836 ret = get_all_avs_ids(&smack_label_av_list, &smack_label_av_list_len);
837 if (ret != PC_OPERATION_SUCCESS) {
838 C_LOGE("Error while geting data from database");
842 // for each anti-virus put rule: "anti_virus_id app_id rwx"
843 for (i = 0; i < smack_label_av_list_len; ++i) {
845 char* smack_path AUTO_FREE;
846 C_LOGD("Adding rwx rule for antivirus: %s", smack_label_av_list[i]);
848 ret = load_smack_from_file(smack_label_av_list[i], &smack, &fd, &smack_path);
849 if (ret != PC_OPERATION_SUCCESS ) {
850 C_LOGE("load_smack_from_file failed");
854 if (smack_accesses_add(smack, smack_label_av_list[i], app_id, "wrx") == -1) {
855 C_LOGE("smack_accesses_add failed");
856 ret = PC_ERR_INVALID_OPERATION;
857 goto out; // Should we abort adding rules if once smack_accesses_add will fail?
860 if (have_smack() && smack_accesses_apply(smack)) {
861 C_LOGE("smack_accesses_apply failed");
862 ret = PC_ERR_INVALID_OPERATION;
866 if (smack_accesses_save(smack, fd)) {
867 C_LOGE("smack_accesses_save failed");
868 ret = PC_ERR_INVALID_OPERATION;
871 // Clearing char* smack_label_av_list[i] got from database.
872 free(smack_label_av_list[i]);
875 ret = PC_OPERATION_SUCCESS;
878 // If something failed, then no all char* smack_label_av_list[i]
879 // are deallocated. They must be freed
880 for(; i<smack_label_av_list_len; ++i) {
881 free(smack_label_av_list[i]);
887 static int app_add_permissions_internal(const char* app_id, app_type_t app_type, const char** perm_list, int permanent)
889 C_LOGD("Enter function: %s", __func__);
890 char* smack_path AUTO_FREE;
893 struct smack_accesses *smack AUTO_SMACK_FREE;
894 const char* base_perm = NULL;
896 if (!smack_label_is_valid(app_id))
897 return PC_ERR_INVALID_PARAM;
899 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
900 if (ret != PC_OPERATION_SUCCESS) {
901 C_LOGE("load_smack_from_file failed");
905 /* Implicitly enable base permission for an app_type */
906 base_perm = app_type_name(app_type);
908 C_LOGD("perm_to_smack params: app_id: %s, %s", app_id, base_perm);
909 ret = perm_to_smack(smack, app_id, APP_TYPE_OTHER, base_perm);
910 if (ret != PC_OPERATION_SUCCESS){
911 C_LOGE("perm_to_smack failed");
915 for (i = 0; perm_list[i] != NULL; ++i) {
916 C_LOGD("perm_to_smack params: app_id: %s, perm_list[%d]: %s", app_id, i, perm_list[i]);
917 ret = perm_to_smack(smack, app_id, app_type, perm_list[i]);
918 if (ret != PC_OPERATION_SUCCESS){
919 C_LOGE("perm_to_smack failed");
923 ret = perm_to_dac(app_id, app_type, perm_list[i]);
924 if (ret != PC_OPERATION_SUCCESS){
925 C_LOGE("perm_to_dac failed");
930 if (have_smack() && smack_accesses_apply(smack)) {
931 C_LOGE("smack_accesses_apply failed");
932 return PC_ERR_INVALID_OPERATION;
935 if (permanent && smack_accesses_save(smack, fd)) {
936 C_LOGE("smack_accesses_save failed");
937 return PC_ERR_INVALID_OPERATION;
940 return PC_OPERATION_SUCCESS;
943 API int app_add_permissions(const char* app_id, const char** perm_list)
945 C_LOGD("Enter function: %s", __func__);
946 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 1);
949 API int app_add_volatile_permissions(const char* app_id, const char** perm_list)
951 C_LOGD("Enter function: %s", __func__);
952 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 0);
955 API int app_enable_permissions(const char* app_id, app_type_t app_type, const char** perm_list, bool persistent)
957 C_LOGD("Enter function: %s", __func__);
958 return app_add_permissions_internal(app_id, app_type, perm_list, persistent);
961 API int perm_app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)
963 C_LOGD("Enter function: %s", __func__);
964 return PC_ERR_INVALID_OPERATION;
967 /* FIXME: this function is only a stub */
968 API int perm_app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)
970 return PC_ERR_INVALID_OPERATION;
973 API int app_disable_permissions(const char* app_id, app_type_t app_type, const char** perm_list)
975 C_LOGD("Enter function: %s", __func__);
976 return PC_OPERATION_SUCCESS;
979 static int app_revoke_permissions_internal(const char* app_id, bool persistent)
981 C_LOGD("Enter function: %s", __func__);
982 char* smack_path AUTO_FREE;
985 struct smack_accesses *smack AUTO_SMACK_FREE;
987 if (!smack_label_is_valid(app_id))
988 return PC_ERR_INVALID_PARAM;
990 ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
991 if (ret != PC_OPERATION_SUCCESS) {
992 C_LOGE("load_smack_from_file failed");
996 if (have_smack() && smack_accesses_clear(smack)) {
997 ret = PC_ERR_INVALID_OPERATION;
998 C_LOGE("smack_accesses_clear failed");
1002 if (have_smack() && smack_revoke_subject(app_id)) {
1003 ret = PC_ERR_INVALID_OPERATION;
1004 C_LOGE("smack_revoke_subject failed");
1008 if (persistent && ftruncate(fd, 0) == -1)
1009 C_LOGE("file truncate failed");
1011 return PC_OPERATION_SUCCESS;
1014 API int perm_app_revoke_permissions(const char* pkg_id)
1016 return PC_ERR_INVALID_OPERATION;
1019 API int app_revoke_permissions(const char* app_id)
1021 C_LOGD("Enter function: %s", __func__);
1024 if (!smack_label_is_valid(app_id))
1025 return PC_ERR_INVALID_PARAM;
1027 ret = app_revoke_permissions_internal(app_id, true);
1029 C_LOGE("Revoking permissions failed");
1033 return PC_OPERATION_SUCCESS;
1036 API int perm_app_reset_permissions(const char* pkg_id)
1038 return PC_ERR_INVALID_OPERATION;
1041 API int app_reset_permissions(const char* app_id)
1043 C_LOGD("Enter function: %s", __func__);
1046 if (!smack_label_is_valid(app_id))
1047 return PC_ERR_INVALID_PARAM;
1049 ret = app_revoke_permissions_internal(app_id, false);
1051 C_LOGE("Revoking permissions failed");
1055 /* Add empty permissions set to trigger re-read of rules */
1056 return app_enable_permissions(app_id, APP_TYPE_OTHER, (const char*[]){NULL}, 0);
1059 API int app_label_dir(const char* label, const char* path)
1061 C_LOGD("Enter function: %s", __func__);
1063 int ret = PC_OPERATION_SUCCESS;
1065 if (!smack_label_is_valid(label))
1066 return PC_ERR_INVALID_PARAM;
1068 //setting access label on everything in given directory and below
1069 ret = dir_set_smack_r(path, label, SMACK_LABEL_ACCESS, ~0);
1070 if (PC_OPERATION_SUCCESS != ret)
1073 //setting execute label for everything with permission to execute
1074 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, S_IXUSR);
1075 if (PC_OPERATION_SUCCESS != ret)
1078 //removing execute label from directories
1079 ret = dir_set_smack_r(path, "", SMACK_LABEL_EXEC, S_IFMT & ~S_IFREG);
1084 int smack_get_access_new(const char* subject, const char* object, char** label)
1086 char buff[ACC_LEN] = {'r', 'w', 'x', 'a', 't'};
1087 char perm[2] = {'-'};
1090 if(!smack_label_is_valid(subject) || !smack_label_is_valid(object) || !label)
1091 return PC_ERR_INVALID_PARAM;
1093 for (i=0; i<ACC_LEN; ++i) {
1095 int ret = smack_have_access(subject, object, perm);
1097 return PC_ERR_INVALID_OPERATION;
1102 *label = malloc(ACC_LEN+1);
1104 return PC_ERR_MEM_OPERATION;
1106 memcpy(*label, buff, ACC_LEN);
1107 (*label)[ACC_LEN] = 0;
1108 return PC_OPERATION_SUCCESS;
1112 * This function will be used to allow direct communication between 2 OSP application.
1113 * This function requires to store "state" with list of added label.
1115 * Full implementation requires some kind of database. This implemetation works without
1116 * database so you wont be able to revoke permissions added by different process.
1118 API int app_give_access(const char* subject, const char* object, const char* permissions)
1120 C_LOGD("Enter function: %s", __func__);
1121 int ret = PC_OPERATION_SUCCESS;
1122 struct smack_accesses *smack AUTO_SMACK_FREE;
1123 static const char * const revoke = "-----";
1124 char *current_permissions AUTO_FREE;
1127 return PC_OPERATION_SUCCESS;
1129 if (!smack_label_is_valid(subject) || !smack_label_is_valid(object))
1130 return PC_ERR_INVALID_PARAM;
1132 if (PC_OPERATION_SUCCESS != (ret = smack_get_access_new(subject, object, ¤t_permissions)))
1135 if (smack_accesses_new(&smack))
1136 return PC_ERR_MEM_OPERATION;
1138 if (smack_accesses_add_modify(smack, subject, object, permissions, revoke))
1139 return PC_ERR_MEM_OPERATION;
1141 if (smack_accesses_apply(smack))
1142 return PC_ERR_NOT_PERMITTED;
1144 ret = state_save(subject, object, current_permissions);
1150 * This function will be used to revoke direct communication between 2 OSP application.
1152 * Full implementation requires some kind of database. This implemetation works without
1153 * database so you wont be able to revoke permissions added by different process.
1155 API int app_revoke_access(const char* subject, const char* object)
1157 C_LOGD("Enter function: %s", __func__);
1159 return PC_OPERATION_SUCCESS;
1161 if (!smack_label_is_valid(subject) || !smack_label_is_valid(object))
1162 return PC_ERR_INVALID_PARAM;
1164 return state_restore(subject, object);
1167 API int app_label_shared_dir(const char* app_label, const char* shared_label, const char* path)
1169 C_LOGD("Enter function: %s", __func__);
1170 char* smack_path AUTO_FREE;
1173 struct smack_accesses *smack AUTO_SMACK_FREE;
1175 if (!smack_label_is_valid(app_label) || !smack_label_is_valid(shared_label))
1176 return PC_ERR_INVALID_PARAM;
1178 if (strcmp(app_label, shared_label) == 0) {
1179 C_LOGE("app_label equals shared_label");
1180 return PC_ERR_INVALID_PARAM;
1183 //setting label on everything in given directory and below
1184 ret = dir_set_smack_r(path, shared_label, SMACK_LABEL_ACCESS, ~0);
1185 if(ret != PC_OPERATION_SUCCESS){
1186 C_LOGE("dir_set_smakc_r failed");
1190 //setting transmute on dir
1191 ret = dir_set_smack_r(path, "1", SMACK_LABEL_TRANSMUTE, S_IFDIR);
1192 if (ret != PC_OPERATION_SUCCESS) {
1193 C_LOGE("dir_set_smakc_r failed");
1197 ret = load_smack_from_file(app_label, &smack, &fd, &smack_path);
1198 if (ret != PC_OPERATION_SUCCESS) {
1199 C_LOGE("load_smack_from_file failed");
1203 //setting access rule for application
1204 if (smack_accesses_add(smack, app_label,shared_label, "wrxat") == -1) {
1205 C_LOGE("smack_accesses_add failed");
1209 if (have_smack() && smack_accesses_apply(smack)) {
1210 C_LOGE("smack_accesses_apply failed");
1211 return PC_ERR_INVALID_OPERATION;
1214 if (smack_accesses_save(smack, fd)) {
1215 C_LOGE("smack_accesses_save failed");
1216 return PC_ERR_INVALID_OPERATION;
1219 return PC_OPERATION_SUCCESS;
1222 API int add_shared_dir_readers(const char* shared_label, const char** app_list)
1224 C_LOGD("Enter function: %s", __func__);
1225 int ret = PC_ERR_INVALID_PARAM;
1229 if (!smack_label_is_valid(shared_label))
1230 return PC_ERR_INVALID_PARAM;
1232 for (i = 0; app_list[i] != NULL; i++) {
1233 char *smack_path AUTO_FREE;
1234 struct smack_accesses *smack AUTO_SMACK_FREE;
1236 if (!smack_label_is_valid(app_list[i]))
1237 return PC_ERR_INVALID_PARAM;
1239 ret = load_smack_from_file(
1240 app_list[i], &smack, &fd, &smack_path);
1241 if (ret != PC_OPERATION_SUCCESS) {
1242 C_LOGE("load_smack_from_file failed");
1245 if (smack_accesses_add_modify(smack, app_list[i], shared_label,
1247 C_LOGE("smack_accesses_add failed");
1248 return PC_ERR_INVALID_OPERATION;
1250 if (have_smack() && smack_accesses_apply(smack)) {
1251 C_LOGE("smack_accesses_apply failed");
1252 return PC_ERR_INVALID_OPERATION;
1254 if (smack_accesses_save(smack, fd)) {
1255 C_LOGE("smack_accesses_save failed");
1256 return PC_ERR_INVALID_OPERATION;
1260 return PC_OPERATION_SUCCESS;
1263 API int perm_app_add_friend(const char* pkg_id1, const char* pkg_id2)
1265 return PC_ERR_INVALID_OPERATION;
1268 API int app_add_friend(const char* app_id1, const char* app_id2)
1270 C_LOGD("Enter function: %s", __func__);
1274 char* smack_path1 AUTO_FREE;
1275 char* smack_path2 AUTO_FREE;
1276 struct smack_accesses* smack1 AUTO_SMACK_FREE;
1277 struct smack_accesses* smack2 AUTO_SMACK_FREE;
1279 if (!smack_label_is_valid(app_id1) || !smack_label_is_valid(app_id2))
1280 return PC_ERR_INVALID_PARAM;
1282 ret = load_smack_from_file(app_id1, &smack1, &fd1, &smack_path1);
1283 if (ret != PC_OPERATION_SUCCESS) {
1284 C_LOGE("load_smack_from_file failed");
1288 ret = load_smack_from_file(app_id2, &smack2, &fd2, &smack_path2);
1289 if (ret != PC_OPERATION_SUCCESS) {
1290 C_LOGE("load_smack_from_file failed");
1294 if (smack_accesses_add(smack1, app_id1, app_id2, "wrxat") == -1 ||
1295 (smack_accesses_add(smack2, app_id2, app_id1, "wrxat") == -1)) {
1296 C_LOGE("smack_accesses_add failed");
1301 (smack_accesses_apply(smack1) || smack_accesses_apply(smack2))) {
1302 C_LOGE("smack_accesses_apply failed");
1303 return PC_ERR_INVALID_OPERATION;
1306 if (smack_accesses_save(smack1, fd1) || smack_accesses_save(smack2, fd2)) {
1307 C_LOGE("smack_accesses_save failed");
1308 return PC_ERR_INVALID_OPERATION;
1311 return PC_OPERATION_SUCCESS;
1314 API int perm_app_install(const char* pkg_id)
1316 return PC_ERR_INVALID_OPERATION;
1319 API int app_install(const char* app_id)
1321 C_LOGD("Enter function: %s", __func__);
1324 char* smack_path AUTO_FREE;
1326 if (!smack_label_is_valid(app_id))
1327 return PC_ERR_INVALID_PARAM;
1329 ret = smack_file_name(app_id, &smack_path);
1330 if (ret != PC_OPERATION_SUCCESS)
1333 fd = open(smack_path, O_RDWR|O_CREAT, 0644);
1335 C_LOGE("file open failed: %s", strerror(errno));
1336 return PC_ERR_FILE_OPERATION;
1339 ret = add_app_id_to_databse(app_id);
1340 if (ret != PC_OPERATION_SUCCESS ) {
1341 C_LOGE("Error while adding app %s to database: %s ", app_id, strerror(errno));
1345 ret = register_app_for_av(app_id);
1346 if (ret != PC_OPERATION_SUCCESS) {
1347 C_LOGE("Error while adding rules for anti viruses to app %s: %s ", app_id, strerror(errno));
1351 return PC_OPERATION_SUCCESS;
1354 API int perm_app_uninstall(const char* pkg_id)
1356 return PC_ERR_INVALID_OPERATION;
1359 API int app_uninstall(const char* app_id)
1361 // TODO: When real database will be used, then this function should remove app_id
1363 // It also should remove rules looks like: "anti_virus_label app_id rwx".
1364 C_LOGD("Enter function: %s", __func__);
1365 char* smack_path AUTO_FREE;
1368 if (!smack_label_is_valid(app_id))
1369 return PC_ERR_INVALID_PARAM;
1371 ret = smack_file_name(app_id, &smack_path);
1372 if (ret != PC_OPERATION_SUCCESS)
1375 if (unlink(smack_path)) {
1376 C_LOGE("unlink failed: ", strerror(errno));
1377 // return PC_ERR_INVALID_OPERATION;
1378 return PC_OPERATION_SUCCESS;
1381 return PC_OPERATION_SUCCESS;
1384 static int save_rules(int fd, struct smack_accesses* accesses) {
1385 if (flock(fd, LOCK_EX)) {
1386 C_LOGE("flock failed, error %s", strerror(errno));
1387 return PC_ERR_FILE_OPERATION;
1390 if (smack_accesses_save(accesses, fd)) {
1391 C_LOGE("smack_accesses_save failed");
1392 return PC_ERR_FILE_OPERATION;
1394 return PC_OPERATION_SUCCESS ;
1397 static int validate_and_add_rule(char* rule, struct smack_accesses* accesses) {
1398 const char* subject = NULL;
1399 const char* object = NULL;
1400 const char* access = NULL;
1401 char* saveptr = NULL;
1403 subject = strtok_r(rule, " \t\n", &saveptr);
1404 object = strtok_r(NULL, " \t\n", &saveptr);
1405 access = strtok_r(NULL, " \t\n", &saveptr);
1407 // check rule validity
1408 if (subject == NULL ||
1411 strtok_r(NULL, " \t\n", &saveptr) != NULL ||
1412 !smack_label_is_valid(subject) ||
1413 !smack_label_is_valid(object))
1415 C_LOGE("Incorrect rule format: %s", rule);
1416 return PC_ERR_INVALID_PARAM;
1419 if (smack_accesses_add(accesses, subject, object, access)) {
1420 C_LOGE("smack_accesses_add failed");
1421 return PC_ERR_INVALID_OPERATION;
1423 return PC_OPERATION_SUCCESS ;
1426 static int parse_and_save_rules(const char** smack_rules,
1427 struct smack_accesses* accesses, const char* feature_file) {
1430 int ret = PC_OPERATION_SUCCESS;
1433 for (i = 0; smack_rules[i] != NULL ; i++) {
1434 // ignore empty lines
1435 if (strspn(smack_rules[i], " \t\n") == strlen(smack_rules[i]))
1438 tmp = strdup(smack_rules[i]);
1439 ret = validate_and_add_rule(tmp, accesses);
1441 if (ret != PC_OPERATION_SUCCESS )
1446 fd = open(feature_file, O_CREAT | O_WRONLY, 0644);
1448 C_LOGE("Unable to create file %s. Error: %s", feature_file, strerror(errno));
1449 return PC_ERR_FILE_OPERATION;
1452 ret = save_rules(fd, accesses);
1457 static int save_gids(FILE* file, const gid_t* list_of_db_gids, size_t list_size) {
1458 int ret = PC_OPERATION_SUCCESS;
1463 C_LOGE("Unable to create file. Error: %s", strerror(errno));
1464 return PC_ERR_FILE_OPERATION; // TODO remove smack accesses?
1467 if(-1 == fchmod(fileno(file), 0644)) {
1468 C_LOGE("Unable to chmod file. Error: %s", strerror(errno));
1469 return PC_ERR_FILE_OPERATION;
1472 for (i = 0; i < list_size ; ++i) {
1473 written = fprintf(file, "%u\n", list_of_db_gids[i]);
1475 C_LOGE("fprintf failed for file. Error: %s", strerror(errno));
1476 ret = PC_ERR_FILE_OPERATION;
1483 API int perm_add_api_feature(app_type_t app_type,
1484 const char* api_feature_name,
1485 const char** smack_rules,
1486 const gid_t* list_of_db_gids,
1489 return PC_ERR_INVALID_OPERATION;
1492 API int add_api_feature(app_type_t app_type,
1493 const char* api_feature_name,
1494 const char** smack_rules,
1495 const gid_t* list_of_db_gids,
1497 C_LOGD("Enter function: %s", __func__);
1499 int ret = PC_OPERATION_SUCCESS;
1500 char* smack_file AUTO_FREE;
1501 char* dac_file AUTO_FREE;
1502 struct smack_accesses* accesses = NULL;
1505 // TODO check process capabilities
1507 // get feature SMACK file name
1508 ret = perm_file_path(&smack_file, app_type, api_feature_name, ".smack");
1509 if (ret != PC_OPERATION_SUCCESS || !smack_file ) {
1513 // check if feature exists
1514 if (file_exists(smack_file)) {
1515 C_LOGE("Feature file %s already exists", smack_file);
1516 return PC_ERR_INVALID_PARAM;
1519 // check .dac existence only if gids are supported
1520 if (list_of_db_gids && list_size > 0) {
1521 // get feature DAC file name
1522 ret = perm_file_path(&dac_file, app_type, api_feature_name, ".dac");
1523 if (ret != PC_OPERATION_SUCCESS || !dac_file ) {
1527 // check if feature exists
1528 if (file_exists(dac_file)) {
1529 C_LOGE("Feature file %s already exists", dac_file);
1530 return PC_ERR_INVALID_PARAM;
1534 // parse & save rules
1536 if (smack_accesses_new(&accesses)) {
1537 C_LOGE("smack_acceses_new failed");
1538 return PC_ERR_MEM_OPERATION;
1541 ret = parse_and_save_rules(smack_rules, accesses, smack_file);
1542 smack_accesses_free(accesses);
1545 // go through gid list
1546 if (ret == PC_OPERATION_SUCCESS && list_of_db_gids && list_size > 0) {
1548 file = fopen(dac_file, "w+");
1549 ret = save_gids(file, list_of_db_gids, list_size);
1553 // remove both files in case of failure
1554 if (ret != PC_OPERATION_SUCCESS) {
1562 API int app_register_av(const char* app_av_id)
1564 C_LOGD("Enter function: %s", __func__);
1568 FILE* file AUTO_FCLOSE;
1570 char** smack_label_app_list AUTO_FREE;
1571 int smack_label_app_list_len = 0;
1572 char* smack_path AUTO_FREE;
1573 struct smack_accesses* smack AUTO_SMACK_FREE;
1575 if (!smack_label_is_valid(app_av_id))
1576 return PC_ERR_INVALID_PARAM;
1578 ret = smack_accesses_new(&smack);
1579 if (ret != PC_OPERATION_SUCCESS) {
1580 C_LOGE("smack_accesses_new failed");
1581 return PC_ERR_MEM_OPERATION;
1584 // writing anti_virus_id (app_av_id) to "database"
1585 ret = add_av_id_to_databse(app_av_id);
1586 if (ret != PC_OPERATION_SUCCESS)
1589 ret = load_smack_from_file(app_av_id, &smack, &fd, &smack_path);
1590 if (ret != PC_OPERATION_SUCCESS) {
1591 C_LOGE("load_smack_from_file failed");
1595 // Reading labels of all installed apps from "database"
1596 ret = get_all_apps_ids(&smack_label_app_list, &smack_label_app_list_len);
1597 if (ret != PC_OPERATION_SUCCESS) {
1598 C_LOGE("Error while geting data from database");
1601 for (i=0; i<smack_label_app_list_len; ++i) {
1602 C_LOGD("Applying rwx rule for %s", smack_label_app_list[i]);
1603 if (smack_accesses_add(smack, app_av_id, smack_label_app_list[i], "wrx") == -1) {
1604 C_LOGE("smack_accesses_add failed");
1605 ret = PC_ERR_INVALID_OPERATION;
1606 goto out; // Should we abort adding rules if once smack_accesses_add will fail?
1610 // Add permisions from OSP_antivirus.samck file - only the OSP app can be an Anti Virus
1611 ret = perm_to_smack(smack, app_av_id, APP_TYPE_OSP, SMACK_ANTIVIRUS_PERM);
1612 if (PC_OPERATION_SUCCESS != ret) {
1613 C_LOGE("perm_to_smack failed");
1617 if (have_smack() && smack_accesses_apply(smack)) {
1618 C_LOGE("smack_accesses_apply failed");
1619 ret = PC_ERR_INVALID_OPERATION;
1623 if (smack_accesses_save(smack, fd)) {
1624 C_LOGE("smack_accesses_save failed");
1625 ret = PC_ERR_INVALID_OPERATION;
1630 for (i=0; i<smack_label_app_list_len; ++i) {
1631 free(smack_label_app_list[i]);
1634 return PC_OPERATION_SUCCESS;