4 * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved
6 * Contact: Kidong Kim <kd0228.kim@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
26 #include <sys/types.h>
38 #include <sys/smack.h>
39 #include <linux/capability.h>
40 #include <sys/capability.h>
46 #include "privilege-control.h"
47 #include "access-db.h"
53 #define DEVELOPER_GID 5100
54 #define DEVELOPER_UID 5100
56 #define APP_USER_NAME "app"
57 #define DEV_USER_NAME "developer"
59 #define APP_HOME_DIR TOSTRING(HOMEDIR) "/app"
60 #define DEV_HOME_DIR TOSTRING(HOMEDIR) "/developer"
62 #define APP_GROUP_PATH TOSTRING(SHAREDIR) "/app_group_list"
63 #define DEV_GROUP_PATH TOSTRING(SHAREDIR) "/dev_group_list"
65 #define SMACK_SRC_FILE_SUFFIX "_src_file"
66 #define SMACK_SRC_DIR_SUFFIX "_src_dir"
67 #define SMACK_DATA_SUFFIX "_data"
68 #define WRT_BASE_DEVCAP "WRT"
69 #define WRT_CLIENT_PATH "/usr/bin/wrt-client"
71 #define TIZEN_PRIVILEGE_ANTIVIRUS "http://tizen.org/privilege/antivirus"
72 #define TIZEN_PRIVILEGE_APPSETTING "http://tizen.org/privilege/appsetting"
73 #define PATH_RULES_PUBLIC_RO "PATH_RULES_PUBLIC_RO.smack"
74 #define PATH_RULES_GROUP_RW "PATH_RULES_GROUP_RW.smack"
90 typedef int (*label_decision_fn)(const FTSENT*);
96 __attribute__ ((destructor))
97 static void libprivilege_destructor()
99 SECURE_C_LOGD("Entering function: %s.", __func__);
103 API int perm_begin(void)
105 SECURE_C_LOGD("Entering function: %s.", __func__);
106 return rdb_modification_start();
109 API int perm_end(void)
111 SECURE_C_LOGD("Entering function: %s.", __func__);
113 rdb_modification_finish();
115 return PC_OPERATION_SUCCESS;
118 API int control_privilege(void)//deprecated
120 SECURE_C_LOGD("Entering function: %s.", __func__);
122 if(getuid() == APP_UID) // current user is 'app'
123 return PC_OPERATION_SUCCESS;
125 if(perm_app_set_privilege("org.tizen.", NULL, NULL) == PC_OPERATION_SUCCESS)
126 return PC_OPERATION_SUCCESS;
128 C_LOGE("perm_app_set_privilege failed (not permitted).");
129 return PC_ERR_NOT_PERMITTED;
134 * TODO: this function should be moved to libsmack in open-source.
136 API int get_smack_label_from_process(pid_t pid, char *smack_label)
138 SECURE_C_LOGD("Entering function: %s. Params: pid=%i", __func__, pid);
142 int PATH_MAX_LEN = 64;
143 char path[PATH_MAX_LEN + 1];
146 C_LOGE("invalid param pid.");
147 ret = PC_ERR_INVALID_PARAM;
151 if(smack_label == NULL) {
152 C_LOGE("Invalid param smack_label (NULL).");
153 ret = PC_ERR_INVALID_PARAM;
157 bzero(smack_label, SMACK_LABEL_LEN + 1);
158 if (!have_smack()) { // If no smack just return success with empty label
159 C_LOGD("No SMACK. Returning empty label");
160 ret = PC_OPERATION_SUCCESS;
164 bzero(path, PATH_MAX_LEN + 1);
165 snprintf(path, PATH_MAX_LEN, "/proc/%d/attr/current", pid);
166 fd = open(path, O_RDONLY);
168 SECURE_C_LOGE("Cannot open file %s (errno: %s)", path, strerror(errno));
169 ret = PC_ERR_FILE_OPERATION;
173 ret = read(fd, smack_label, SMACK_LABEL_LEN);
175 SECURE_C_LOGE("Cannot read from file %s", path);
176 ret = PC_ERR_FILE_OPERATION;
180 SECURE_C_LOGD("smack_label=%s", smack_label);
182 ret = PC_OPERATION_SUCCESS;
188 API int smack_pid_have_access(pid_t pid,
190 const char *access_type)
192 SECURE_C_LOGD("Entering function: %s. Params: pid=%i, object=%s, access_type=%s",
193 __func__, pid, object, access_type);
196 char pid_subject_label[SMACK_LABEL_LEN + 1];
198 cap_flag_value_t cap_v;
201 C_LOGD("No SMACK. Return access granted");
206 C_LOGE("Invalid pid.");
211 C_LOGE("Invalid object param.");
215 if(access_type == NULL) {
216 C_LOGE("Invalid access_type param");
220 //get SMACK label of process
221 ret = get_smack_label_from_process(pid, pid_subject_label);
222 if (PC_OPERATION_SUCCESS != ret) {
223 SECURE_C_LOGE("get_smack_label_from_process %d failed: %d", pid, ret);
226 SECURE_C_LOGD("pid %d has label: %s", pid, pid_subject_label);
228 // do not call smack_have_access() if label is empty
229 if (pid_subject_label[0] != '\0') {
230 ret = smack_have_access(pid_subject_label, object, access_type);
232 C_LOGE("smack_have_access failed.");
235 if ( 1 == ret ) { // smack_have_access return 1 (access granted)
236 C_LOGD("smack_have_access returned 1 (access granted)");
241 // smack_have_access returned 0 (access denied). Now CAP_MAC_OVERRIDE should be checked
242 C_LOGD("smack_have_access returned 0 (access denied)");
243 cap = cap_get_pid(pid);
245 C_LOGE("cap_get_pid failed");
248 ret = cap_get_flag(cap, CAP_MAC_OVERRIDE, CAP_EFFECTIVE, &cap_v);
250 C_LOGE("cap_get_flag failed");
254 if (cap_v == CAP_SET) {
255 C_LOGD("pid %d has CAP_MAC_OVERRIDE", pid);
259 C_LOGD("pid %d doesn't have CAP_MAC_OVERRIDE", pid);
264 static int set_dac(const char *smack_label, const char *pkg_name)
266 SECURE_C_LOGD("Entering function: %s. Params: smack_label=%s, pkg_name=%s",
267 __func__, smack_label, pkg_name);
269 FILE* fp_group = NULL; // /etc/group
270 uid_t t_uid = -1; // uid of current process
271 gid_t *glist = NULL; // group list
272 gid_t temp_gid = -1; // for group list
273 char buf[10] = {0, }; // contents in group_list file
274 int glist_cnt = 0; // for group list
278 unsigned *additional_gids = NULL;
281 * initialize user structure
283 C_LOGD("Initialize user structure");
284 memset(usr.user_name, 0x00, 10);
285 memset(usr.home_dir, 0x00, 64);
286 memset(usr.group_list, 0x00, 64);
291 C_LOGD("Current uid is %d", t_uid);
293 if(t_uid == 0) // current user is 'root'
295 if(!strncmp(pkg_name, "developer", 9))
297 strncpy(usr.user_name, DEV_USER_NAME, sizeof(usr.user_name));
298 usr.uid = DEVELOPER_UID;
299 usr.gid = DEVELOPER_GID;
300 strncpy(usr.home_dir, DEV_HOME_DIR, sizeof(usr.home_dir));
301 strncpy(usr.group_list, DEV_GROUP_PATH, sizeof(usr.group_list));
305 strncpy(usr.user_name, APP_USER_NAME, sizeof(usr.user_name));
308 strncpy(usr.home_dir, APP_HOME_DIR, sizeof(usr.home_dir));
309 strncpy(usr.group_list, APP_GROUP_PATH, sizeof(usr.group_list));
313 * get group information
315 C_LOGD("Get group information");
316 SECURE_C_LOGD("Opening file %s.", usr.group_list);
317 if(!(fp_group = fopen(usr.group_list, "r")))
319 C_LOGE("fopen failed.");
320 result = PC_ERR_FILE_OPERATION; // return -1
324 while(fgets(buf, 10, fp_group) != NULL)
327 temp_gid = strtoul(buf, 0, 10);
328 if(errno != 0) // error occured during strtoul()
330 C_LOGE("Cannot change string to integer: %s", buf);
331 result = PC_ERR_INVALID_OPERATION;
335 glist = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + 1));
338 result = PC_ERR_MEM_OPERATION; // return -2
339 C_LOGE("Cannot allocate memory");
342 glist[glist_cnt] = temp_gid;
348 if(NULL != smack_label)
353 result = get_app_gids(smack_label, &additional_gids, &cnt);
354 if (result != PC_OPERATION_SUCCESS)
358 glist_new = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + cnt));
359 if (glist_new == NULL) {
360 result = PC_ERR_MEM_OPERATION; // return -2
361 C_LOGE("Memory allocation failed");
365 for (i = 0; i < cnt; ++i) {
366 C_LOGD("Additional GID based on enabled permissions: %u", additional_gids[i]);
367 glist[glist_cnt++] = additional_gids[i];
375 C_LOGD("Adding process to the following groups:");
376 for(i=0; i<glist_cnt; ++i) {
377 SECURE_C_LOGD("glist [ %d ] = %d", i, glist[i]);
379 C_LOGD("Calling setgroups()");
380 if(setgroups(glist_cnt, glist) != 0)
382 C_LOGE("setgroups failed");
383 result = PC_ERR_NOT_PERMITTED; // return -3
393 * setuid() & setgid()
395 C_LOGD("setgid( %d ) & setuid( %d )", usr.gid, usr.uid);
396 if(setgid(usr.gid) != 0) // fail
398 C_LOGE("Failed to execute setgid().");
399 result = PC_ERR_INVALID_OPERATION;
402 if(setuid(usr.uid) != 0) // fail
404 C_LOGE("Failed to execute setuid().");
405 result = PC_ERR_INVALID_OPERATION;
409 SECURE_C_LOGD("setenv(): USER = %s, HOME = %s", usr.user_name, usr.home_dir);
410 if(setenv("USER", usr.user_name, 1) != 0) //fail
412 C_LOGE("Failed to execute setenv() [USER].");
413 result = PC_ERR_INVALID_OPERATION;
416 if(setenv("HOME", usr.home_dir, 1) != 0) // fail
418 C_LOGE("Failed to execute setenv() [HOME].");
419 result = PC_ERR_INVALID_OPERATION;
423 else // current user is not only 'root' but 'app'
425 C_LOGE("Current user is NOT root");
426 result = PC_ERR_NOT_PERMITTED; // return -3
430 result = PC_OPERATION_SUCCESS;
437 free(additional_gids);
443 * Get SMACK label from EXEC label of a file.
444 * SMACK label should be freed by caller
446 * @param path file path to take label from
447 * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
449 static int get_smack_from_binary(char **smack_label, const char* path, app_type_t type)
451 SECURE_C_LOGD("Entering function: %s. Params: path=%s, type=%d",
452 __func__, path, type);
456 if (type == APP_TYPE_WGT
457 || type == APP_TYPE_WGT_PARTNER
458 || type == APP_TYPE_WGT_PLATFORM) {
459 ret = smack_lgetlabel(path, smack_label, SMACK_LABEL_EXEC);
461 ret = smack_getlabel(path, smack_label, SMACK_LABEL_EXEC);
464 C_LOGE("Getting exec label from file %s failed", path);
465 return PC_ERR_INVALID_OPERATION;
468 return PC_OPERATION_SUCCESS;
472 * Set process SMACK label.
473 * This function is emulating EXEC label behavior of SMACK for programs
474 * run by dlopen/dlsym instead of execv.
477 * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
479 static int set_smack_for_self (char *smack_label)
481 SECURE_C_LOGD("Entering function: %s. Params: smack_label=%s",
482 __func__, smack_label);
485 if (smack_label == NULL) {
486 /* No label to set, just return with success */
487 C_LOGD("No label to set, just return with success.");
488 ret = PC_OPERATION_SUCCESS;
491 SECURE_C_LOGD("smack_label=%s", smack_label);
493 ret = smack_set_label_for_self(smack_label);
494 C_LOGD("smack_set_label_for_self returned %d", ret);
496 ret = PC_OPERATION_SUCCESS;
502 static int is_widget(const char* path)
504 SECURE_C_LOGD("Entering function: %s. Params: path=%s",
506 char buf[sizeof(WRT_CLIENT_PATH)];
509 ret = readlink(path, buf, sizeof(WRT_CLIENT_PATH));
511 C_LOGD("readlink(%s) returned error: %s. Assuming that app is not a widget", path, strerror(errno));
512 else if (ret == sizeof(WRT_CLIENT_PATH))
513 C_LOGD("%s is not a widget", path);
514 if (ret == -1 || ret == sizeof(WRT_CLIENT_PATH))
517 C_LOGD("buf=%s", buf);
519 ret = !strcmp(WRT_CLIENT_PATH, buf);
520 C_LOGD("%s is %s widget", path, ret ? "a" : "not a");
525 * Partially verify, that the type given for app is correct.
526 * This function will use some heuristics to check whether the app type is right.
527 * It is intended for security hardening to catch privilege setting for the
528 * app type not corresponding to the actual binary.
529 * Beware - when it detects an anomaly, the whole process will be terminated.
531 * @param type claimed application type
532 * @param path file path to executable
533 * @return return void on success, terminate the process on error
535 static app_type_t verify_app_type(const char* type, const char* path)
537 SECURE_C_LOGD("Entering function: %s. Params: type=%s, path=%s",
538 __func__, type, path);
540 /* TODO: this should actually be treated as error, but until the old
541 * set_privilege API is removed, it must be ignored */
543 C_LOGD("PKG_TYPE_OTHER");
544 return APP_TYPE_OTHER; /* good */
547 if (is_widget(path)) {
548 if (!strcmp(type, "wgt")) {
549 C_LOGD("PKG_TYPE_WGT");
550 return APP_TYPE_WGT; /* good */
551 } else if (!strcmp(type, "wgt_partner")) {
552 C_LOGD("PKG_TYPE_WGT_PARTNER");
553 return APP_TYPE_WGT_PARTNER; /* good */
554 } else if (!strcmp(type, "wgt_platform")) {
555 C_LOGD("PKG_TYPE_WGT_PLATFORM");
556 return APP_TYPE_WGT_PLATFORM; /* good */
560 if (type == NULL || (strcmp(type, "wgt")
561 && strcmp(type, "wgt_partner")
562 && strcmp(type, "wgt_platform"))){
563 C_LOGD("PKG_TYPE_OTHER");
564 return APP_TYPE_OTHER; /* good */
569 C_LOGE("EXIT_FAILURE");
573 API int set_app_privilege(const char* name, const char* type, const char* path)//deprecated
575 SECURE_C_LOGD("Entering function: %s. Params: name=%s, type=%s, path=%s",
576 __func__, name, type, path);
578 return perm_app_set_privilege(name, type, path);
581 API int perm_app_set_privilege(const char* name, const char* type, const char* path)
583 SECURE_C_LOGD("Entering function: %s. Params: name=%s, type=%s, path=%s",
584 __func__, name, type, path);
586 //SECURE_C_LOGD("Function params: name = %s, type = %s, path = %s", name, type, path);
587 int ret = PC_OPERATION_SUCCESS;
588 char *smack_label AUTO_FREE;
591 C_LOGE("Error invalid parameter");
592 return PC_ERR_INVALID_PARAM;
595 if (path != NULL && have_smack()) {
596 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
597 if (ret != PC_OPERATION_SUCCESS)
600 ret = set_smack_for_self(smack_label);
601 if (ret != PC_OPERATION_SUCCESS)
605 if (path != NULL && !have_smack()) {
606 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
607 if (ret != PC_OPERATION_SUCCESS)
611 return set_dac(smack_label, name);
614 API int set_privilege(const char* pkg_name)//deprecated
616 SECURE_C_LOGD("Entering function: %s. Params: pkg_name=%s",
619 return perm_app_set_privilege(pkg_name, NULL, NULL);
622 static inline const char* app_type_name(app_type_t app_type)
624 SECURE_C_LOGD("Entering function: %s. Params: app_type=%d",
629 C_LOGD("App type = APP_TYPE_WGT");
632 C_LOGD("App type = APP_TYPE_OSP");
634 case APP_TYPE_WGT_PARTNER:
635 C_LOGD("App type = APP_TYPE_WGT_PARTNER");
636 return "WRT_partner";
637 case APP_TYPE_WGT_PLATFORM:
638 C_LOGD("App type = APP_TYPE_WGT_PLATFORM");
639 return "WRT_platform";
640 case APP_TYPE_OSP_PARTNER:
641 C_LOGD("App type = APP_TYPE_OSP_PARTNER");
642 return "OSP_partner";
643 case APP_TYPE_OSP_PLATFORM:
644 C_LOGD("App type = APP_TYPE_OSP_PLATFORM");
645 return "OSP_platform";
649 C_LOGD("App type = other");
654 static inline const char* app_type_group_name(app_type_t app_type)
656 SECURE_C_LOGD("Entering function: %s. Params: app_type=%d",
661 case APP_TYPE_WGT_PARTNER:
662 case APP_TYPE_WGT_PLATFORM:
663 C_LOGD("App type group name = WRT");
666 case APP_TYPE_OSP_PARTNER:
667 case APP_TYPE_OSP_PLATFORM:
668 C_LOGD("App type group name = OST");
678 * This function changes permission URI to basename for file name.
679 * For e.g. from http://tizen.org/privilege/contact.read will be
680 * created basename : org.tizen.privilege.contact.read
683 static int base_name_from_perm(const char *perm, char **name)
685 SECURE_C_LOGD("Entering function: %s. Params: perm=%s",
689 char *host_dot = NULL;
690 char *rest_slash = NULL;
693 ip = iri_parse(perm);
694 if (ip == NULL || ip->host == NULL) {
695 SECURE_C_LOGE("Bad permission format : %s", perm);
697 return PC_ERR_INVALID_PARAM;
700 if (ip->path == NULL) {
706 host_dot = strrchr(ip->host, '.');
713 while ((rest_slash = strchr(ip->path, '/'))) {
717 ret = asprintf(name, "%s%s%s%s",
718 host_dot ? host_dot : "", host_dot ? "." : "",
719 ip->host ? ip->host : "", ip->path);
721 C_LOGE("asprintf failed");
723 return PC_ERR_MEM_OPERATION;
727 return PC_OPERATION_SUCCESS;
730 static int perm_file_path(char** path, app_type_t app_type, const char* perm, const char *suffix, bool is_early)
732 SECURE_C_LOGD("Entering function: %s. Params: app_type=%d, perm=%s, suffix=%s, is_early=%d",
733 __func__, app_type, perm, suffix, is_early);
735 const char* app_type_prefix = NULL;
736 char* perm_basename = NULL;
739 if (perm == NULL || strlen(perm) == 0) {
740 C_LOGE("Empty permission name.");
741 return PC_ERR_INVALID_PARAM;
744 app_type_prefix = app_type_group_name(app_type);
746 ret = base_name_from_perm(perm, &perm_basename);
747 if (ret != PC_OPERATION_SUCCESS) {
748 C_LOGE("Couldn't get permission basename.");
753 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s%s",
754 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
755 perm_basename, "_early", suffix);
758 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s",
759 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
760 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 int perm_to_dac(const char* app_label, app_type_t app_type, const char* perm)
774 SECURE_C_LOGD("Entering function: %s. Params: app_label=%s, app_type=%d, perm=%s",
775 __func__, app_label, app_type, perm);
778 char* path AUTO_FREE;
779 FILE* file AUTO_FCLOSE;
782 ret = perm_file_path(&path, app_type, perm, ".dac", 0);
783 if (ret != PC_OPERATION_SUCCESS) {
784 C_LOGD("No dac config file for permission %s", perm);
788 SECURE_C_LOGD("Opening file %s.", path);
789 file = fopen(path, "r");
791 C_LOGW("fopen failed.");
792 return PC_OPERATION_SUCCESS;
795 while (fscanf(file, "%d\n", &gid) == 1) {
796 SECURE_C_LOGD("Adding app_id %s to group %d", app_label, gid);
797 ret = add_app_gid(app_label, gid);
798 if (ret != PC_OPERATION_SUCCESS) {
799 C_LOGE("add_app_gid failed");
804 return PC_OPERATION_SUCCESS;
807 static int label_all(const FTSENT* ftsent UNUSED)
809 SECURE_C_LOGD("Entering function: %s.", __func__);
811 return DECISION_LABEL;
814 static int label_execs(const FTSENT* ftsent)
816 SECURE_C_LOGD("Entering function: %s.", __func__);
818 C_LOGD("Mode = %d", ftsent->fts_statp->st_mode);
819 // label only regular executable files
820 if (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR))
821 return DECISION_LABEL;
822 return DECISION_SKIP;
825 static int label_dirs(const FTSENT* ftsent)
827 SECURE_C_LOGD("Entering function: %s.", __func__);
829 // label only directories
830 if (S_ISDIR(ftsent->fts_statp->st_mode))
831 return DECISION_LABEL;
832 return DECISION_SKIP;
835 static int label_links_to_execs(const FTSENT* ftsent)
837 SECURE_C_LOGD("Entering function: %s.", __func__);
840 char* target AUTO_FREE;
842 // check if it's a link
843 if ( !S_ISLNK(ftsent->fts_statp->st_mode))
844 return DECISION_SKIP;
846 target = realpath(ftsent->fts_path, NULL);
848 SECURE_C_LOGE("Getting link target for %s failed (Error = %s)", ftsent->fts_path, strerror(errno));
849 return PC_ERR_FILE_OPERATION;
851 if (-1 == stat(target, &buf)) {
852 SECURE_C_LOGE("stat failed for %s (Error = %s", target, strerror(errno));
853 return PC_ERR_FILE_OPERATION;
855 // skip if link target is not a regular executable file
856 if (buf.st_mode != (buf.st_mode | S_IXUSR | S_IFREG)) {
857 SECURE_C_LOGD("%s is not a regular executable file. Skipping.", target);
858 return DECISION_SKIP;
861 return DECISION_LABEL;
864 static int dir_set_smack_r(const char *path, const char* label,
865 enum smack_label_type type, label_decision_fn fn)
867 SECURE_C_LOGD("Entering function: %s. Params: path=%s, label=%s, type=%d",
868 __func__, path, label, type);
870 const char* path_argv[] = {path, NULL};
871 FTS *fts AUTO_FTS_CLOSE;
875 fts = fts_open((char * const *) path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
877 C_LOGE("fts_open failed.");
878 return PC_ERR_FILE_OPERATION;
881 while ((ftsent = fts_read(fts)) != NULL) {
882 /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
883 if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
884 C_LOGE("FTS_ERR error or failed stat(2) (FTS_NS)");
885 return PC_ERR_FILE_OPERATION;
890 C_LOGE("fn(ftsent) failed.");
894 if (ret == DECISION_LABEL) {
895 C_LOGD("smack_lsetlabel (label: %s (type: %d), path: %s)", label, type, ftsent->fts_path);
896 if (smack_lsetlabel(ftsent->fts_path, label, type) != 0) {
897 C_LOGE("smack_lsetlabel failed.");
898 return PC_ERR_FILE_OPERATION;
903 /* If last call to fts_read() set errno, we need to return error. */
905 C_LOGE("Last errno from fts_read: %s", strerror(errno));
906 return PC_ERR_FILE_OPERATION;
908 return PC_OPERATION_SUCCESS;
910 API char* app_id_from_socket(int sockfd)//deprecated
912 SECURE_C_LOGD("Entering function: %s. Params: sockfd=%d",
915 return perm_app_id_from_socket(sockfd);
918 API char* perm_app_id_from_socket(int sockfd)
920 SECURE_C_LOGD("Entering function: %s. Params: sockfd=%d",
924 C_LOGD("No SMACK. Returning NULL.");
931 ret = smack_new_label_from_socket(sockfd, &app_id);
933 C_LOGE("smack_new_label_from_socket failed");
937 SECURE_C_LOGD("app_id = %s", app_id);
943 static int app_add_permissions_internal(const char* app_id, app_type_t app_type, const char** perm_list, int permanent)
945 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s, app_type=%d, permanent=%d",
946 __func__, app_id, app_type, permanent);
949 char* smack_path AUTO_FREE;
950 char* smack_path_early AUTO_FREE;
952 int fd_early AUTO_CLOSE;
953 struct smack_accesses *smack AUTO_SMACK_FREE;
954 struct smack_accesses *smack_early AUTO_SMACK_FREE;
956 if (!smack_label_is_valid(app_id)) {
957 C_LOGE("Invalid param app_id.");
958 return PC_ERR_INVALID_PARAM;
961 if(perm_list == NULL) {
962 C_LOGE("Invalid perm_list (NULL).");
963 return PC_ERR_INVALID_PARAM;
966 if (app_type_group_name(app_type) == NULL) {
967 C_LOGE("Unknown app type.");
968 return PC_ERR_INVALID_PARAM;
971 // Add permission to DAC
972 for (i = 0; perm_list[i] != NULL; ++i) {
973 ret = perm_to_dac(app_id, app_type, perm_list[i]);
974 if (ret != PC_OPERATION_SUCCESS){
975 C_LOGE("perm_to_dac failed");
980 // Enable the permissions:
981 ret = rdb_enable_app_permissions(app_id,
982 app_type_group_name(app_type),
985 if (ret != PC_OPERATION_SUCCESS) {
986 C_LOGE("RDB rdb_enable_app_permissions failed with: %d", ret);
991 SECURE_C_LOGD("Leaving function: %s. Params: app_id=%s, app_type=%d, permanent=%d",
992 __func__, app_id, app_type, permanent);
994 return PC_OPERATION_SUCCESS;
997 API int app_add_permissions(const char* app_id, const char** perm_list)//deprecated
999 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
1002 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 1);
1005 API int app_add_volatile_permissions(const char* app_id, const char** perm_list)//deprecated
1007 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
1010 return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 0);
1013 API int app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)//deprecated
1015 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d, persistent=%d",
1016 __func__, pkg_id, app_type, persistent);
1018 return app_add_permissions_internal(pkg_id, app_type, perm_list, persistent);
1021 API int perm_app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)
1023 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d, persistent=%d",
1024 __func__, pkg_id, app_type, persistent);
1026 return app_add_permissions_internal(pkg_id, app_type, perm_list, persistent);
1029 API int app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)//deprecated
1031 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d",
1032 __func__, pkg_id, app_type);
1034 return perm_app_disable_permissions(pkg_id, app_type, perm_list);
1037 /* FIXME: this function is only a stub */
1038 API int perm_app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)
1040 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d",
1041 __func__, pkg_id, app_type);
1044 if (!smack_label_is_valid(pkg_id)) {
1045 C_LOGE("Invalid param app_id.");
1046 return PC_ERR_INVALID_PARAM;
1049 if (perm_list == NULL) {
1050 C_LOGE("Invalid perm_list (NULL).");
1051 return PC_ERR_INVALID_PARAM;
1054 if (app_type_group_name(app_type) == NULL) {
1055 C_LOGE("Unknown app type.");
1056 return PC_ERR_INVALID_PARAM;
1059 ret = rdb_disable_app_permissions(pkg_id, app_type_group_name(app_type), perm_list);
1060 if (ret != PC_OPERATION_SUCCESS) {
1061 C_LOGE("RDB rdb_disable_app_permissions failed with: %d", ret);
1065 return PC_OPERATION_SUCCESS;
1068 API int app_revoke_permissions(const char* pkg_id)//deprecated
1070 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s", __func__, pkg_id);
1071 return perm_app_revoke_permissions(pkg_id);
1074 API int perm_app_revoke_permissions(const char* pkg_id)
1076 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s", __func__, pkg_id);
1079 if (!smack_label_is_valid(pkg_id)) {
1080 C_LOGE("Invalid param app_id.");
1081 return PC_ERR_INVALID_PARAM;
1084 ret = rdb_revoke_app_permissions(pkg_id);
1085 if (ret != PC_OPERATION_SUCCESS) {
1086 C_LOGE("RDB rdb_disable_app_permissions failed with: %d", ret);
1090 return PC_OPERATION_SUCCESS;
1093 API int app_reset_permissions(const char* pkg_id)//deprecated
1095 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s",
1098 return perm_app_reset_permissions(pkg_id);
1101 API int perm_app_reset_permissions(const char* pkg_id)
1103 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s",
1107 if (!smack_label_is_valid(pkg_id)) {
1108 C_LOGE("Invalid param pkg_id.");
1109 return PC_ERR_INVALID_PARAM;
1112 ret = rdb_reset_app_permissions(pkg_id);
1113 if (ret != PC_OPERATION_SUCCESS) {
1114 C_LOGE("RDB rdb_disable_app_permissions failed with: %d", ret);
1118 return PC_OPERATION_SUCCESS;
1121 API int app_label_dir(const char* label, const char* path)//deprecated
1123 SECURE_C_LOGD("Entering function: %s. Params: label=%s, path=%s",
1124 __func__, label, path);
1126 int ret = PC_OPERATION_SUCCESS;
1129 C_LOGE("Invalid argument path (NULL).");
1130 return PC_ERR_INVALID_PARAM;
1133 if (!smack_label_is_valid(label)) {
1134 C_LOGE("Invalid param label.");
1135 return PC_ERR_INVALID_PARAM;
1138 //setting access label on everything in given directory and below
1139 ret = dir_set_smack_r(path, label, SMACK_LABEL_ACCESS, &label_all);
1140 if (PC_OPERATION_SUCCESS != ret)
1142 C_LOGE("dir_set_smack_r failed.");
1146 //setting execute label for everything with permission to execute
1147 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_execs);
1148 if (PC_OPERATION_SUCCESS != ret)
1150 C_LOGE("dir_set_smack_r failed.");
1154 //setting execute label for everything with permission to execute
1155 ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_links_to_execs);
1160 API int app_label_shared_dir(const char* app_label, const char* shared_label, const char* path)//deprecated
1162 SECURE_C_LOGD("Entering function: %s. Params: app_label=%s, shared_label=%s, path=%s",
1163 __func__, app_label, shared_label, path);
1167 C_LOGE("Invalid param path.");
1168 return PC_ERR_INVALID_PARAM;
1171 if(!smack_label_is_valid(app_label)) {
1172 C_LOGE("Invalid param app_label");
1173 return PC_ERR_INVALID_PARAM;
1176 if(!smack_label_is_valid(shared_label)) {
1177 C_LOGE("Invalid param shared_label");
1178 return PC_ERR_INVALID_PARAM;
1181 if (strcmp(app_label, shared_label) == 0) {
1182 C_LOGE("app_label equals shared_label");
1183 return PC_ERR_INVALID_PARAM;
1186 //setting label on everything in given directory and below
1187 ret = dir_set_smack_r(path, shared_label, SMACK_LABEL_ACCESS, label_all);
1188 if(ret != PC_OPERATION_SUCCESS){
1189 C_LOGE("dir_set_smack_r failed.");
1193 //setting transmute on dir
1194 ret = dir_set_smack_r(path, "1", SMACK_LABEL_TRANSMUTE, label_dirs);
1195 if (ret != PC_OPERATION_SUCCESS) {
1196 C_LOGE("dir_set_smack_r failed");
1200 return PC_OPERATION_SUCCESS;
1203 API int add_shared_dir_readers(const char* shared_label UNUSED, const char** app_list UNUSED)//deprecated
1205 SECURE_C_LOGD("Entering function: %s. Params: shared_label=%s",
1206 __func__, shared_label);
1208 C_LOGE("add_shared_dir_readers is deprecated and unimplemented!");
1210 // TODO: This function is not implemented with RDB.
1211 return PC_ERR_INVALID_OPERATION;
1214 static char* smack_label_for_path(const char *app_id, const char *path)
1216 SECURE_C_LOGD("Entering function: %s. Params: app_id=%s, path=%s",
1217 __func__, app_id, path);
1219 char *salt AUTO_FREE;
1223 /* Prefix $1$ causes crypt() to use MD5 function */
1224 if (-1 == asprintf(&salt, "$1$%s", app_id)) {
1225 C_LOGE("asprintf failed");
1229 label = crypt(path, salt);
1230 if (label == NULL) {
1231 C_LOGE("crypt failed");
1235 /* crypt() output may contain slash character,
1236 * which is not legal in Smack labels */
1237 for (x = label; *x; ++x) {
1245 /* FIXME: remove this pragma once deprecated API is deleted */
1246 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1247 static int perm_app_setup_path_internal(const char* pkg_id, const char* path, app_path_type_t app_path_type, va_list ap)
1249 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, path=%s, app_path_type=%d",
1250 __func__, pkg_id, path, app_path_type);
1253 C_LOGE("Invalid argument path.");
1254 return PC_ERR_INVALID_PARAM;
1257 if (!smack_label_is_valid(pkg_id)) {
1258 C_LOGE("Invalid pkg_id.");
1259 SECURE_C_LOGE("Invalid pkg_id %s", pkg_id);
1260 return PC_ERR_INVALID_PARAM;
1263 switch (app_path_type) {
1264 case APP_PATH_PRIVATE:
1265 C_LOGD("app_path_type is APP_PATH_PRIVATE.");
1266 return app_label_dir(pkg_id, path);
1268 case APP_PATH_GROUP_RW: {
1269 C_LOGD("app_path_type is APP_PATH_GROUP_RW.");
1271 const char *shared_label;
1273 shared_label = va_arg(ap, const char *);
1275 if (!smack_label_is_valid(shared_label)) {
1276 C_LOGE("Invalid shared_label.");
1277 return PC_ERR_INVALID_PARAM;
1280 if (strcmp(pkg_id, shared_label) == 0) {
1281 C_LOGE("pkg_id equals shared_label.");
1282 return PC_ERR_INVALID_PARAM;
1285 // Add the path to the database:
1286 ret = rdb_add_path(pkg_id, shared_label, path, "rwxatl", "GROUP_RW");
1287 if (ret != PC_OPERATION_SUCCESS) {
1288 C_LOGE("RDB rdb_add_path failed with: %d", ret);
1292 ret = app_label_shared_dir(pkg_id, shared_label, path);
1293 if (ret != PC_OPERATION_SUCCESS) {
1294 C_LOGE("app_label_shared_dir failed: %d", ret);
1298 return PC_OPERATION_SUCCESS;
1301 case APP_PATH_PUBLIC_RO: {
1302 C_LOGD("app_path_type is APP_PATH_PUBLIC_RO.");
1303 char **app_ids AUTO_FREE;
1307 C_LOGD("New public RO path %s", path);
1310 label = smack_label_for_path(pkg_id, path);
1311 if (label == NULL) {
1312 C_LOGE("smack_label_for_path failed.");
1313 return PC_ERR_INVALID_OPERATION;
1315 C_LOGD("Generated label '%s' for public RO path %s", label, path);
1317 // Add the path to the database:
1318 ret = rdb_add_path(pkg_id, label, path, "rwxatl", "PUBLIC_RO");
1319 if (ret != PC_OPERATION_SUCCESS) {
1320 C_LOGE("RDB rdb_add_path failed with: %d", ret);
1324 ret = app_label_shared_dir(pkg_id, label, path);
1325 if (ret != PC_OPERATION_SUCCESS) {
1326 C_LOGE("app_label_shared_dir failed.");
1329 return PC_OPERATION_SUCCESS;
1332 case APP_PATH_SETTINGS_RW: {
1333 C_LOGD("app_path_type is APP_PATH_SETTINGS_RW.");
1334 char **app_ids AUTO_FREE;
1339 label = smack_label_for_path(pkg_id, path);
1340 if (label == NULL) {
1341 C_LOGE("smack_label_for_path failed.");
1342 return PC_ERR_INVALID_OPERATION;
1344 C_LOGD("Appsetting: generated label '%s' for setting path %s", label, path);
1347 // Add the path to the database:
1348 ret = rdb_add_path(pkg_id, label, path, "rwxatl", "SETTINGS_RW");
1349 if (ret != PC_OPERATION_SUCCESS) {
1350 C_LOGE("RDB rdb_add_path failed with: %d", ret);
1354 /*set id for path and all subfolders*/
1355 ret = app_label_shared_dir(pkg_id, label, path);
1356 if (ret != PC_OPERATION_SUCCESS) {
1357 C_LOGE("Appsetting: app_label_shared_dir failed (%d)", ret);
1360 return PC_OPERATION_SUCCESS;
1363 case APP_PATH_ANY_LABEL: {
1364 C_LOGD("app_path_type is APP_PATH_ANY_LABEL.");
1365 const char *label = NULL;
1366 label = va_arg(ap, const char *);
1367 return app_label_dir(label, path);
1371 C_LOGE("app_path_type is invalid.");
1372 return PC_ERR_INVALID_PARAM;
1375 return PC_OPERATION_SUCCESS;
1377 /* FIXME: remove this pragma once deprecated API is deleted */
1378 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
1380 API int app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)//deprecated
1382 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, path=%s, app_path_type=%d",
1383 __func__, pkg_id, path, app_path_type);
1387 va_start( ap, app_path_type );
1388 ret = perm_app_setup_path_internal( pkg_id, path, app_path_type, ap );
1394 API int perm_app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)
1396 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, path=%s, app_path_type=%d",
1397 __func__, pkg_id, path, app_path_type);
1401 va_start( ap, app_path_type );
1402 ret = perm_app_setup_path_internal( pkg_id, path, app_path_type, ap );
1407 API int app_add_friend(const char* pkg_id1, const char* pkg_id2)//deprecated
1409 SECURE_C_LOGD("Entering function: %s. Params: pkg_id1=%s, pkg_id2=%s",
1410 __func__, pkg_id1, pkg_id2);
1412 return perm_app_add_friend(pkg_id1, pkg_id2);
1415 API int perm_app_add_friend(const char* pkg_id1 UNUSED, const char* pkg_id2 UNUSED)
1417 SECURE_C_LOGD("Entering function: %s. Params: pkg_id1=%s, pkg_id2=%s",
1418 __func__, pkg_id1, pkg_id2);
1420 C_LOGE("app_register_av is deprecated and unimplemented!");
1422 // TODO: This function is not implemented with RDB.
1423 return PC_ERR_INVALID_OPERATION;
1426 API int app_install(const char* pkg_id)//deprecated
1428 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s",
1431 return perm_app_install(pkg_id);
1434 API int perm_app_install(const char* pkg_id)
1436 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s",
1440 char* smack_path AUTO_FREE;
1441 struct smack_accesses *smack AUTO_SMACK_FREE;
1444 if(ret != PC_OPERATION_SUCCESS) {
1445 C_LOGE("RDB perm_begin failed with: %d", ret);
1449 if (!smack_label_is_valid(pkg_id)) {
1450 C_LOGE("Invalid param pkg_id.");
1451 return PC_ERR_INVALID_PARAM;
1454 // Add application to the database:
1455 ret = rdb_add_application(pkg_id);
1456 if (ret != PC_OPERATION_SUCCESS) {
1457 C_LOGE("RDB rdb_add_application failed with: %d", ret);
1461 return PC_OPERATION_SUCCESS;
1464 API int app_uninstall(const char* pkg_id)//deprecated
1466 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s",
1469 return perm_app_uninstall(pkg_id);
1472 API int perm_app_uninstall(const char* pkg_id)
1474 SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s", __func__, pkg_id);
1475 char* smack_path AUTO_FREE;
1478 if (!smack_label_is_valid(pkg_id)) {
1479 C_LOGE("Invalid param pkg_id.");
1480 return PC_ERR_INVALID_PARAM;
1483 // Remove application from the database
1484 ret = rdb_remove_application(pkg_id);
1485 if (ret != PC_OPERATION_SUCCESS) {
1486 C_LOGE("RDB rdb_remove_application failed with: %d", ret);
1490 return PC_OPERATION_SUCCESS;
1493 static int save_gids(FILE* file, const gid_t* list_of_db_gids, size_t list_size) {
1495 SECURE_C_LOGD("Entering function: %s.", __func__);
1496 int ret = PC_OPERATION_SUCCESS;
1501 C_LOGE("Unable to create file. Error: %s", strerror(errno));
1502 return PC_ERR_FILE_OPERATION; // TODO remove smack accesses?
1505 if(-1 == fchmod(fileno(file), 0644)) {
1506 C_LOGE("Unable to chmod file. Error: %s", strerror(errno));
1507 return PC_ERR_FILE_OPERATION;
1510 for (i = 0; i < list_size ; ++i) {
1511 written = fprintf(file, "%u\n", list_of_db_gids[i]);
1513 C_LOGE("fprintf failed for file. Error: %s", strerror(errno));
1514 ret = PC_ERR_FILE_OPERATION;
1521 API int add_api_feature(app_type_t app_type,
1522 const char* api_feature_name,
1523 const char** smack_rules,
1524 const gid_t* list_of_db_gids,
1525 size_t list_size)//deprecated
1527 SECURE_C_LOGD("Entering function: %s. Params: app_type=%d, api_feature_name=%s",
1528 __func__, app_type, api_feature_name);
1530 return perm_add_api_feature(app_type, api_feature_name, smack_rules, list_of_db_gids, list_size);
1533 API int perm_add_api_feature(app_type_t app_type,
1534 const char* api_feature_name,
1535 const char** smack_rules,
1536 const gid_t* list_of_db_gids,
1538 SECURE_C_LOGD("Entering function: %s. Params: app_type=%d, api_feature_name=%s",
1539 __func__, app_type, api_feature_name);
1541 int ret = PC_OPERATION_SUCCESS;
1542 char* smack_file AUTO_FREE;
1543 char* dac_file AUTO_FREE;
1544 char * base_api_feature_name AUTO_FREE;
1546 // struct smack_accesses* accesses = NULL;
1547 const char *s_type_name = app_type_name(app_type);
1549 // Check input values
1550 if (s_type_name == NULL || !strcmp(s_type_name, "")) {
1551 C_LOGE("Unknown api type");
1552 return PC_ERR_INVALID_PARAM;
1555 if (api_feature_name == NULL || strlen(api_feature_name) == 0) {
1556 C_LOGE("Api feature name is empty.");
1557 return PC_ERR_INVALID_PARAM;
1560 if (smack_rules && ((ret = validate_all_rules(smack_rules) ) != PC_OPERATION_SUCCESS) ) {
1561 C_LOGE("Error in rules list.");
1565 // check .dac existence only if gids are supported
1566 if (list_of_db_gids && list_size > 0) {
1567 // get feature DAC file name
1568 ret = perm_file_path(&dac_file, app_type, api_feature_name, ".dac", 0);
1569 if (ret != PC_OPERATION_SUCCESS || !dac_file ) {
1570 C_LOGE("perm_file_path failed.");
1577 // go through gid list
1578 if (ret == PC_OPERATION_SUCCESS && list_of_db_gids && list_size > 0) {
1580 SECURE_C_LOGD("Opening file %s.", dac_file);
1581 file = fopen(dac_file, "w+");
1582 ret = save_gids(file, list_of_db_gids, list_size);
1583 if(file) fclose(file);
1586 // remove file in case of failure
1587 if (ret != PC_OPERATION_SUCCESS && dac_file) {
1591 ret = base_name_from_perm(api_feature_name, &base_api_feature_name);
1592 if (ret != PC_OPERATION_SUCCESS){
1593 C_LOGE("Error during creating base name: ", ret);
1597 // Save api feature to the database.
1598 ret = rdb_add_permission_rules(base_api_feature_name, s_type_name, smack_rules);
1599 if (ret != PC_OPERATION_SUCCESS) {
1600 C_LOGE("RDB rdb_add_permission_rules failed with: %d", ret);
1608 * This function is marked as deprecated and will be removed
1610 API int app_register_av(const char* app_av_id UNUSED)//deprecated
1612 SECURE_C_LOGD("Entering function: %s. Params: app_av_id=%s",
1613 __func__, app_av_id);
1615 C_LOGE("app_register_av is deprecated and unimplemented!");
1617 // TODO: This function is not implemented with RDB.
1618 return PC_ERR_INVALID_OPERATION;