45fe74b0c8304bf7b92e17f1854d383f1a3e5f7b
[platform/core/security/libprivilege-control.git] / src / privilege-control.c
1 /*
2  * libprivilege control
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact: Kidong Kim <kd0228.kim@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #define _GNU_SOURCE
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <pwd.h>
29 #include <grp.h>
30 #include <fts.h>
31 #include <errno.h>
32 #include <math.h>
33 #include <ctype.h>
34 #include <fcntl.h>
35 #include <sys/time.h>
36 #include <sys/stat.h>
37 #include <sys/file.h>
38 #include <sys/smack.h>
39 #include <linux/capability.h>
40 #include <sys/capability.h>
41 #include <sys/mman.h>
42 #include <stdbool.h>
43 #include <search.h>
44
45 #include "privilege-control.h"
46 #include "access-db.h"
47 #include "common.h"
48 #include "rules-db.h"
49
50 #define APP_GID 5000
51 #define APP_UID 5000
52 #define DEVELOPER_GID   5100
53 #define DEVELOPER_UID   5100
54
55 #define APP_USER_NAME   "app"
56 #define DEV_USER_NAME   "developer"
57
58 #define APP_HOME_DIR    TOSTRING(HOMEDIR) "/app"
59 #define DEV_HOME_DIR    TOSTRING(HOMEDIR) "/developer"
60
61 #define APP_GROUP_PATH  TOSTRING(SHAREDIR) "/app_group_list"
62 #define DEV_GROUP_PATH  TOSTRING(SHAREDIR) "/dev_group_list"
63
64 #define SMACK_SRC_FILE_SUFFIX   "_src_file"
65 #define SMACK_SRC_DIR_SUFFIX    "_src_dir"
66 #define SMACK_DATA_SUFFIX       "_data"
67 #define WRT_BASE_DEVCAP         "WRT"
68 #define WRT_CLIENT_PATH         "/usr/bin/wrt-client"
69 #define ACC_LEN                 6
70 #define TIZEN_PRIVILEGE_ANTIVIRUS  "http://tizen.org/privilege/antivirus"
71 #define TIZEN_PRIVILEGE_APPSETTING "http://tizen.org/privilege/appsetting"
72 #define PATH_RULES_PUBLIC_RO       "PATH_RULES_PUBLIC_RO.smack"
73 #define PATH_RULES_GROUP_RW        "PATH_RULES_GROUP_RW.smack"
74
75 typedef struct {
76         char user_name[10];
77         int uid;
78         int gid;
79         char home_dir[64];
80         char group_list[64];
81 } new_user;
82
83 /**
84  * Return values
85  * <0 - error
86  * 0 - skip
87  * 1 - label
88  */
89 typedef int (*label_decision_fn)(const FTSENT*);
90 enum {
91         DECISION_SKIP = 0,
92         DECISION_LABEL = 1
93 };
94
95 __attribute__ ((destructor))
96 static void libprivilege_destructor()
97 {
98         SECURE_C_LOGD("Entering function: %s.", __func__);
99         perm_end();
100 }
101
102 API int perm_begin(void)
103 {
104         SECURE_C_LOGD("Entering function: %s.", __func__);
105         return rdb_modification_start();
106 }
107
108 API int perm_end(void)
109 {
110         SECURE_C_LOGD("Entering function: %s.", __func__);
111
112         return rdb_modification_finish();
113 }
114
115 API int perm_rollback(void)
116 {
117         SECURE_C_LOGD("Entering function: %s.", __func__);
118
119         int ret = rdb_modification_rollback();
120
121         if (ret != PC_OPERATION_SUCCESS) {
122                 C_LOGE("RDB %s failed with: %d", __func__, ret);
123                 return ret;
124         }
125
126         return PC_OPERATION_SUCCESS;
127 }
128
129 API int control_privilege(void)//deprecated
130 {
131         SECURE_C_LOGD("Entering function: %s.", __func__);
132
133         if(getuid() == APP_UID) // current user is 'app'
134                 return PC_OPERATION_SUCCESS;
135
136         if(perm_app_set_privilege("org.tizen.", NULL, NULL) == PC_OPERATION_SUCCESS)
137                 return PC_OPERATION_SUCCESS;
138         else {
139                 C_LOGE("perm_app_set_privilege failed (not permitted).");
140                 return PC_ERR_NOT_PERMITTED;
141         }
142 }
143
144 /**
145  * TODO: this function should be moved to libsmack in open-source.
146  */
147 API int get_smack_label_from_process(pid_t pid, char *smack_label)
148 {
149         SECURE_C_LOGD("Entering function: %s. Params: pid=%i", __func__, pid);
150
151         int ret;
152         int fd AUTO_CLOSE;
153         int PATH_MAX_LEN = 64;
154         char path[PATH_MAX_LEN + 1];
155
156         if (pid < 0) {
157                 C_LOGE("invalid param pid.");
158                 ret = PC_ERR_INVALID_PARAM;
159                 goto out;
160         }
161
162         if(smack_label == NULL) {
163                 C_LOGE("Invalid param smack_label (NULL).");
164                 ret = PC_ERR_INVALID_PARAM;
165                 goto out;
166         }
167
168         bzero(smack_label, SMACK_LABEL_LEN + 1);
169         if (!have_smack()) { // If no smack just return success with empty label
170                 C_LOGD("No SMACK. Returning empty label");
171                 ret = PC_OPERATION_SUCCESS;
172                 goto out;
173         }
174
175         bzero(path, PATH_MAX_LEN + 1);
176         snprintf(path, PATH_MAX_LEN, "/proc/%d/attr/current", pid);
177         fd = open(path, O_RDONLY);
178         if (fd < 0) {
179                 SECURE_C_LOGE("Cannot open file %s (errno: %s)", path, strerror(errno));
180                 ret = PC_ERR_FILE_OPERATION;
181                 goto out;
182         }
183
184         ret = read(fd, smack_label, SMACK_LABEL_LEN);
185         if (ret < 0) {
186                 SECURE_C_LOGE("Cannot read from file %s", path);
187                 ret = PC_ERR_FILE_OPERATION;
188                 goto out;
189         }
190
191         SECURE_C_LOGD("smack_label=%s", smack_label);
192
193         ret = PC_OPERATION_SUCCESS;
194
195 out:
196         return ret;
197 }
198
199 API int smack_pid_have_access(pid_t pid,
200                                                                 const char* object,
201                                                                 const char *access_type)
202 {
203         SECURE_C_LOGD("Entering function: %s. Params: pid=%i, object=%s, access_type=%s",
204                                 __func__, pid, object, access_type);
205
206         int ret;
207         char pid_subject_label[SMACK_LABEL_LEN + 1];
208         cap_t cap;
209         cap_flag_value_t cap_v;
210
211         if (!have_smack()) {
212                 C_LOGD("No SMACK. Return access granted");
213                 return 1;
214         }
215
216         if (pid < 0) {
217                 C_LOGE("Invalid pid.");
218                 return -1;
219         }
220
221         if(object == NULL) {
222                 C_LOGE("Invalid object param.");
223                 return -1;
224         }
225
226         if(access_type == NULL) {
227                 C_LOGE("Invalid access_type param");
228                 return -1;
229         }
230
231         //get SMACK label of process
232         ret = get_smack_label_from_process(pid, pid_subject_label);
233         if (PC_OPERATION_SUCCESS != ret) {
234                 SECURE_C_LOGE("get_smack_label_from_process %d failed: %d", pid, ret);
235                 return -1;
236         }
237         SECURE_C_LOGD("pid %d has label: %s", pid, pid_subject_label);
238
239         // do not call smack_have_access() if label is empty
240         if (pid_subject_label[0] != '\0') {
241                 ret = smack_have_access(pid_subject_label, object, access_type);
242                 if ( -1 == ret) {
243                         C_LOGE("smack_have_access failed.");
244                         return -1;
245                 }
246                 if ( 1 == ret ) { // smack_have_access return 1 (access granted)
247                         C_LOGD("smack_have_access returned 1 (access granted)");
248                         return 1;
249                 }
250         }
251
252         // smack_have_access returned 0 (access denied). Now CAP_MAC_OVERRIDE should be checked
253         C_LOGD("smack_have_access returned 0 (access denied)");
254         cap = cap_get_pid(pid);
255         if (cap == NULL) {
256                 C_LOGE("cap_get_pid failed");
257                 return -1;
258         }
259         ret = cap_get_flag(cap, CAP_MAC_OVERRIDE, CAP_EFFECTIVE, &cap_v);
260         if (0 != ret) {
261                 C_LOGE("cap_get_flag failed");
262                 return -1;
263         }
264
265         if (cap_v == CAP_SET) {
266                 C_LOGD("pid %d has CAP_MAC_OVERRIDE", pid);
267                 return 1;
268
269         } else {
270                 C_LOGD("pid %d doesn't have CAP_MAC_OVERRIDE", pid);
271                 return 0;
272         }
273 }
274
275
276
277 static int get_user_groups(uid_t user_id, int *nbgroup, gid_t **groups_list)
278 {
279         gid_t *groups = NULL;
280         struct passwd * pw;
281         C_LOGD("Enter function: %s", __func__);
282
283         if ((!groups_list) || (!nbgroup))
284                 return PC_ERR_INVALID_OPERATION;
285         pw = getpwuid(user_id);
286         if(!pw) {
287                 C_LOGE("getgrouplist fails : Invalid User ID %d",user_id);
288                 return PC_ERR_INVALID_OPERATION;
289         }
290         *nbgroup = 0;
291         //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.
292         if (getgrouplist(pw->pw_name,  pw->pw_gid, groups, nbgroup) != -1)
293                 return PC_ERR_INVALID_OPERATION;
294
295         C_LOGD("getgrouplist %s user is member of %d groups ",pw->pw_name,*nbgroup);
296         groups = malloc(*nbgroup * sizeof (gid_t));
297         if (!groups)
298                 return PC_ERR_INVALID_OPERATION;
299         //Second call is done with the suitable ngroup value and structure groups allocated.
300         if (getgrouplist(pw->pw_name,  pw->pw_gid, groups, nbgroup) == -1) {
301                 free(groups);
302                 C_LOGE("getgrouplist fails %d",nbgroup);
303                 return PC_ERR_INVALID_OPERATION;
304         }
305         *groups_list = groups;
306         return  PC_OPERATION_SUCCESS;
307 }
308
309 static int set_dac(const char *smack_label, const char *pkg_name)
310 {
311         SECURE_C_LOGD("Entering function: %s. Params: smack_label=%s, pkg_name=%s",
312                                 __func__, smack_label, pkg_name);
313
314         uid_t t_uid = -1;               // uid of current process
315         gid_t *glist = NULL;    // group list
316         int glist_cnt = 0;              // for group list
317         int result;
318         int i;
319         new_user usr;
320         unsigned *additional_gids = NULL;
321
322         /*
323          * initialize user structure
324          */
325         C_LOGD("Initialize user structure");
326         memset(usr.user_name, 0x00, 10);
327         memset(usr.home_dir, 0x00, 64);
328         memset(usr.group_list, 0x00, 64);
329         usr.uid = -1;
330         usr.gid = -1;
331
332         t_uid = getuid();
333         C_LOGD("Current uid is %d", t_uid);
334
335         if(t_uid == 0)  // current user is 'root'
336         {
337                 if(!strncmp(pkg_name, "developer", 9))
338                 {
339                         strncpy(usr.user_name, DEV_USER_NAME, sizeof(usr.user_name));
340                         usr.uid = DEVELOPER_UID;
341                         usr.gid = DEVELOPER_GID;
342                         strncpy(usr.home_dir, DEV_HOME_DIR, sizeof(usr.home_dir));
343                         strncpy(usr.group_list, DEV_GROUP_PATH, sizeof(usr.group_list));
344                 }
345                 else
346                 {
347                         strncpy(usr.user_name, APP_USER_NAME, sizeof(usr.user_name));
348                         usr.uid = APP_UID;
349                         usr.gid = APP_GID;
350                         strncpy(usr.home_dir, APP_HOME_DIR, sizeof(usr.home_dir));
351                 }
352
353                 /*
354                  * get group information
355                  */
356                 C_LOGD("get group information");
357                 if (get_user_groups(usr.uid, &glist_cnt, &glist)) {
358                         result = PC_ERR_FILE_OPERATION; // return -1
359                         goto error;
360                 }
361                 {
362                         gid_t *glist_new;
363                         int i, cnt;
364
365                         result = get_app_gids(smack_label, &additional_gids, &cnt);
366                         if (result != PC_OPERATION_SUCCESS)
367                                 goto error;
368
369                         if (cnt > 0) {
370                                 glist_new = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + cnt));
371                                 if (glist_new == NULL) {
372                                         result = PC_ERR_MEM_OPERATION;  // return -2
373                                         C_LOGE("Memory allocation failed");
374                                         goto error;
375                                 }
376                                 glist = glist_new;
377                                 for (i = 0; i < cnt; ++i) {
378                                         C_LOGD("Additional GID based on enabled permissions: %u", additional_gids[i]);
379                                         glist[glist_cnt++] = additional_gids[i];
380                                 }
381                         }
382                 }
383
384                 /*
385                  * setgroups()
386                  */
387                 C_LOGD("Adding process to the following groups:");
388                 for(i=0; i<glist_cnt; ++i) {
389                         SECURE_C_LOGD("glist [ %d ] = %d", i, glist[i]);
390                 }
391                 C_LOGD("Calling setgroups()");
392                 if(setgroups(glist_cnt, glist) != 0)
393                 {
394                         C_LOGE("setgroups failed");
395                         result = PC_ERR_NOT_PERMITTED;  // return -3
396                         goto error;
397                 }
398                 if(glist != NULL)
399                 {
400                         free(glist);
401                         glist = NULL;
402                 }
403
404                 /*
405                  * setuid() & setgid()
406                  */
407                 C_LOGD("setgid( %d ) & setuid( %d )", usr.gid, usr.uid);
408                 if(setgid(usr.gid) != 0)        // fail
409                 {
410                         C_LOGE("Failed to execute setgid().");
411                         result = PC_ERR_INVALID_OPERATION;
412                         goto error;
413                 }
414                 if(setuid(usr.uid) != 0)        // fail
415                 {
416                         C_LOGE("Failed to execute setuid().");
417                         result = PC_ERR_INVALID_OPERATION;
418                         goto error;
419                 }
420
421                 SECURE_C_LOGD("setenv(): USER = %s, HOME = %s", usr.user_name, usr.home_dir);
422                 if(setenv("USER", usr.user_name, 1) != 0)       //fail
423                 {
424                         C_LOGE("Failed to execute setenv() [USER].");
425                         result = PC_ERR_INVALID_OPERATION;
426                         goto error;
427                 }
428                 if(setenv("HOME", usr.home_dir, 1) != 0)        // fail
429                 {
430                         C_LOGE("Failed to execute setenv() [HOME].");
431                         result = PC_ERR_INVALID_OPERATION;
432                         goto error;
433                 }
434         }
435         else    // current user is not only 'root' but 'app'
436         {
437                 C_LOGE("Current user is NOT root");
438                 result = PC_ERR_NOT_PERMITTED;  // return -3
439                 goto error;
440         }
441
442         result = PC_OPERATION_SUCCESS;
443
444 error:
445         if(glist != NULL)
446                 free(glist);
447         free(additional_gids);
448
449         return result;
450 }
451
452 /**
453  * Get SMACK label from EXEC label of a file.
454  * SMACK label should be freed by caller
455  *
456  * @param path file path to take label from
457  * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
458  */
459 static int get_smack_from_binary(char **smack_label, const char* path, app_type_t type)
460 {
461         SECURE_C_LOGD("Entering function: %s. Params: path=%s, type=%d",
462                                 __func__, path, type);
463         int ret;
464
465         *smack_label = NULL;
466         if (type == PERM_APP_TYPE_WRT
467         || type == PERM_APP_TYPE_WRT_PARTNER
468         || type == PERM_APP_TYPE_WRT_PLATFORM) {
469                 ret = smack_lgetlabel(path, smack_label, SMACK_LABEL_EXEC);
470         } else {
471                 ret = smack_getlabel(path, smack_label, SMACK_LABEL_EXEC);
472         }
473         if (ret != 0) {
474                 C_LOGE("Getting exec label from file %s failed", path);
475                 return PC_ERR_INVALID_OPERATION;
476         }
477
478         return PC_OPERATION_SUCCESS;
479 }
480
481 /**
482  * Set process SMACK label.
483  * This function is emulating EXEC label behavior of SMACK for programs
484  * run by dlopen/dlsym instead of execv.
485  *
486  * @param smack label
487  * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
488  */
489 static int set_smack_for_self (char *smack_label)
490 {
491         SECURE_C_LOGD("Entering function: %s. Params: smack_label=%s",
492                                 __func__, smack_label);
493         int ret;
494
495         if (smack_label == NULL) {
496                 /* No label to set, just return with success */
497                 C_LOGD("No label to set, just return with success.");
498                 ret = PC_OPERATION_SUCCESS;
499         }
500         else {
501                 SECURE_C_LOGD("smack_label=%s", smack_label);
502                 if (have_smack()) {
503                         ret = smack_set_label_for_self(smack_label);
504                         C_LOGD("smack_set_label_for_self returned %d", ret);
505                 } else
506                         ret = PC_OPERATION_SUCCESS;
507         }
508
509         return ret;
510 }
511
512 static int is_widget(const char* path)
513 {
514         SECURE_C_LOGD("Entering function: %s. Params: path=%s",
515                                 __func__, path);
516         char buf[sizeof(WRT_CLIENT_PATH)];
517         int ret;
518
519         ret = readlink(path, buf, sizeof(WRT_CLIENT_PATH));
520         if (ret == -1)
521                 C_LOGD("readlink(%s) returned error: %s. Assuming that app is not a widget", path, strerror(errno));
522         else if (ret == sizeof(WRT_CLIENT_PATH))
523                 C_LOGD("%s is not a widget", path);
524         if (ret == -1 || ret == sizeof(WRT_CLIENT_PATH))
525                 return 0;
526         buf[ret] = '\0';
527         C_LOGD("buf=%s", buf);
528
529         ret = !strcmp(WRT_CLIENT_PATH, buf);
530         C_LOGD("%s is %s widget", path, ret ? "a" : "not a");
531         return (ret);
532 }
533
534 /**
535  * Partially verify, that the type given for app is correct.
536  * This function will use some heuristics to check whether the app type is right.
537  * It is intended for security hardening to catch privilege setting for the
538  * app type not corresponding to the actual binary.
539  * Beware - when it detects an anomaly, the whole process will be terminated.
540  *
541  * @param type claimed application type
542  * @param path file path to executable
543  * @return return recognized type enum on success, terminate the process on error
544  */
545 static app_type_t verify_app_type(const char* type, const char* path)
546 {
547         SECURE_C_LOGD("Entering function: %s. Params: type=%s, path=%s",
548                                 __func__, type, path);
549
550         /* TODO: this should actually be treated as error, but until the old
551          * set_privilege API is removed, it must be ignored */
552         /* And it will be removed very soon */
553         if (path == NULL || type == NULL) {
554                 C_LOGD("PKG_TYPE_OTHER");
555                 return APP_TYPE_OTHER; /* good */
556         }
557
558         if (is_widget(path)) {
559                 if (!strcmp(type, "wgt")) {
560                         C_LOGD("PKG_TYPE_WRT");
561                         return PERM_APP_TYPE_WRT; /* good */
562                 } else if (!strcmp(type, "wgt_partner")) {
563                         C_LOGD("PKG_TYPE_WRT_PARTNER");
564                         return PERM_APP_TYPE_WRT_PARTNER; /* good */
565                 } else if (!strcmp(type, "wgt_platform")) {
566                         C_LOGD("PKG_TYPE_WRT_PLATFORM");
567                         return PERM_APP_TYPE_WRT_PLATFORM; /* good */
568                 }
569
570         } else {
571                 if (!strcmp(type, "osp")) {
572                         C_LOGD("PKG_TYPE_OSP");
573                         return PERM_APP_TYPE_OSP; /* good */
574                 } else if (!strcmp(type, "osp_partner")) {
575                         C_LOGD("PKG_TYPE_OSP_PARTNER");
576                         return PERM_APP_TYPE_OSP_PARTNER; /* good */
577                 } else if (!strcmp(type, "osp_platform")) {
578                         C_LOGD("PKG_TYPE_OSP_PLATFORM");
579                         return PERM_APP_TYPE_OSP_PLATFORM; /* good */
580                 } else if (!strcmp(type, "efl")) {
581                         C_LOGD("PKG_TYPE_EFL");
582                         return PERM_APP_TYPE_EFL; /* good */
583                 }
584         }
585
586         /* bad */
587         C_LOGE("EXIT_FAILURE, app_type = \"%s\" unrecognized", type);
588         exit(EXIT_FAILURE);
589 }
590
591 API int set_app_privilege(const char* name, const char* type, const char* path)//deprecated
592 {
593         SECURE_C_LOGD("Entering function: %s. Params: name=%s, type=%s, path=%s",
594                                 __func__, name, type, path);
595
596         return perm_app_set_privilege(name, type, path);
597 }
598
599 API int perm_app_set_privilege(const char* name, const char* type, const char* path)
600 {
601         SECURE_C_LOGD("Entering function: %s. Params: name=%s, type=%s, path=%s",
602                                 __func__, name, type, path);
603
604         //SECURE_C_LOGD("Function params: name = %s, type = %s, path = %s", name, type, path);
605         int ret = PC_OPERATION_SUCCESS;
606         char *smack_label AUTO_FREE;
607
608         if (name == NULL) {
609                 C_LOGE("Error invalid parameter");
610                 return PC_ERR_INVALID_PARAM;
611         }
612
613         if (path != NULL && have_smack()) {
614                 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
615                 if (ret != PC_OPERATION_SUCCESS)
616                         return ret;
617
618                 ret = set_smack_for_self(smack_label);
619                 if (ret != PC_OPERATION_SUCCESS)
620                         return ret;
621         }
622
623         if (path != NULL && !have_smack()) {
624                 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
625                 if (ret != PC_OPERATION_SUCCESS)
626                         return ret;
627         }
628
629         return set_dac(smack_label, name);
630 }
631
632 API int set_privilege(const char* pkg_name)//deprecated
633 {
634         SECURE_C_LOGD("Entering function: %s. Params: pkg_name=%s",
635                                 __func__, pkg_name);
636
637         return perm_app_set_privilege(pkg_name, NULL, NULL);
638 }
639
640 static int perm_file_path(char** path, app_type_t app_type, const char* perm, const char *suffix, bool is_early)
641 {
642         SECURE_C_LOGD("Entering function: %s. Params: app_type=%d, perm=%s, suffix=%s, is_early=%d",
643                                 __func__, app_type, perm, suffix, is_early);
644
645         const char* app_type_prefix = NULL;
646         char* perm_basename = NULL;
647         int ret = 0;
648
649         if (perm == NULL || strlen(perm) == 0) {
650                 C_LOGE("Empty permission name.");
651                 return PC_ERR_INVALID_PARAM;
652         }
653
654         app_type_prefix = app_type_group_name(app_type);
655
656         ret = base_name_from_perm(perm, &perm_basename);
657         if (ret != PC_OPERATION_SUCCESS) {
658                 C_LOGE("Couldn't get permission basename.");
659                 return ret;
660         }
661
662         if (is_early) {
663                 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s%s",
664                 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
665                 perm_basename, "_early", suffix);
666         }
667         else {
668                 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s",
669                 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
670                 perm_basename, suffix);
671         }
672         if (ret == -1) {
673                 C_LOGE("asprintf failed.");
674                 return PC_ERR_MEM_OPERATION;
675         }
676
677         C_LOGD("Path=%s", *path);
678
679         return PC_OPERATION_SUCCESS;
680 }
681
682 static int perm_to_dac(const char* app_label, app_type_t app_type, const char* perm)
683 {
684         SECURE_C_LOGD("Entering function: %s. Params: app_label=%s, app_type=%d, perm=%s",
685                                 __func__, app_label, app_type, perm);
686
687         int ret;
688         char* path AUTO_FREE;
689         FILE* file AUTO_FCLOSE;
690         int gid;
691
692         ret = perm_file_path(&path, app_type, perm, ".dac", 0);
693         if (ret != PC_OPERATION_SUCCESS) {
694                 C_LOGD("No dac config file for permission %s", perm);
695                 return ret;
696         }
697
698         SECURE_C_LOGD("Opening file %s.", path);
699         file = fopen(path, "r");
700         if (file == NULL) {
701                 C_LOGW("fopen failed.");
702                 return PC_OPERATION_SUCCESS;
703         }
704
705         while (fscanf(file, "%d\n", &gid) == 1) {
706                 SECURE_C_LOGD("Adding app_id %s to group %d", app_label, gid);
707                 ret = add_app_gid(app_label, gid);
708                 if (ret != PC_OPERATION_SUCCESS) {
709                         C_LOGE("add_app_gid failed");
710                         return ret;
711                 }
712         }
713
714         return PC_OPERATION_SUCCESS;
715 }
716
717 static int label_all(const FTSENT* ftsent UNUSED)
718 {
719         SECURE_C_LOGD("Entering function: %s.", __func__);
720
721         return DECISION_LABEL;
722 }
723
724 static int label_execs(const FTSENT* ftsent)
725 {
726         SECURE_C_LOGD("Entering function: %s.", __func__);
727
728         C_LOGD("Mode = %d", ftsent->fts_statp->st_mode);
729         // label only regular executable files
730         if (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR))
731                 return DECISION_LABEL;
732         return DECISION_SKIP;
733 }
734
735 static int label_dirs(const FTSENT* ftsent)
736 {
737         SECURE_C_LOGD("Entering function: %s.", __func__);
738
739         // label only directories
740         if (S_ISDIR(ftsent->fts_statp->st_mode))
741                 return DECISION_LABEL;
742         return DECISION_SKIP;
743 }
744
745 static int label_links_to_execs(const FTSENT* ftsent)
746 {
747         SECURE_C_LOGD("Entering function: %s.", __func__);
748
749         struct stat buf;
750         char* target AUTO_FREE;
751
752         // check if it's a link
753         if ( !S_ISLNK(ftsent->fts_statp->st_mode))
754                 return DECISION_SKIP;
755
756         target = realpath(ftsent->fts_path, NULL);
757         if (!target) {
758                 SECURE_C_LOGE("Getting link target for %s failed (Error = %s)", ftsent->fts_path, strerror(errno));
759                 return PC_ERR_FILE_OPERATION;
760         }
761         if (-1 == stat(target, &buf)) {
762                 SECURE_C_LOGE("stat failed for %s (Error = %s", target, strerror(errno));
763                 return PC_ERR_FILE_OPERATION;
764         }
765         // skip if link target is not a regular executable file
766         if (buf.st_mode != (buf.st_mode | S_IXUSR | S_IFREG)) {
767                 SECURE_C_LOGD("%s is not a regular executable file. Skipping.", target);
768                 return DECISION_SKIP;
769         }
770
771         return DECISION_LABEL;
772 }
773
774 static int dir_set_smack_r(const char *path, const char* label,
775                 enum smack_label_type type, label_decision_fn fn)
776 {
777         SECURE_C_LOGD("Entering function: %s. Params: path=%s, label=%s, type=%d",
778                                 __func__, path, label, type);
779
780         const char* path_argv[] = {path, NULL};
781         FTS *fts AUTO_FTS_CLOSE;
782         FTSENT *ftsent;
783         int ret;
784
785         fts = fts_open((char * const *) path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
786         if (fts == NULL) {
787                 C_LOGE("fts_open failed.");
788                 return PC_ERR_FILE_OPERATION;
789         }
790
791         while ((ftsent = fts_read(fts)) != NULL) {
792                 /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
793                 if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
794                         C_LOGE("FTS_ERR error or failed stat(2) (FTS_NS)");
795                         return PC_ERR_FILE_OPERATION;
796                 }
797
798                 ret = fn(ftsent);
799                 if (ret < 0) {
800                         C_LOGE("fn(ftsent) failed.");
801                         return ret;
802                 }
803
804                 if (ret == DECISION_LABEL) {
805                         C_LOGD("smack_lsetlabel (label: %s (type: %d), path: %s)", label, type, ftsent->fts_path);
806                         if (smack_lsetlabel(ftsent->fts_path, label, type) != 0) {
807                                 C_LOGE("smack_lsetlabel failed.");
808                                 return PC_ERR_FILE_OPERATION;
809                         }
810                 }
811         }
812
813         /* If last call to fts_read() set errno, we need to return error. */
814         if (errno != 0) {
815                 C_LOGE("Last errno from fts_read: %s", strerror(errno));
816                 return PC_ERR_FILE_OPERATION;
817         }
818         return PC_OPERATION_SUCCESS;
819 }
820 API char* app_id_from_socket(int sockfd)//deprecated
821 {
822         SECURE_C_LOGD("Entering function: %s. Params: sockfd=%d",
823                                 __func__, sockfd);
824
825     return perm_app_id_from_socket(sockfd);
826 }
827
828 API char* perm_app_id_from_socket(int sockfd)
829 {
830         SECURE_C_LOGD("Entering function: %s. Params: sockfd=%d",
831                                 __func__, sockfd);
832
833         if (!have_smack()) {
834                 C_LOGD("No SMACK. Returning NULL.");
835                 return NULL;
836         }
837
838         char* app_id;
839         int ret;
840
841         ret = smack_new_label_from_socket(sockfd, &app_id);
842         if (ret < 0) {
843                 C_LOGE("smack_new_label_from_socket failed");
844                 return NULL;
845         }
846
847         SECURE_C_LOGD("app_id = %s", app_id);
848
849         return app_id;
850 }
851
852
853 API int app_add_permissions(const char* app_id, const char** perm_list)//deprecated
854 {
855         SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
856                                 __func__, app_id);
857
858         return perm_app_enable_permissions(app_id, APP_TYPE_OTHER, perm_list, true);
859 }
860
861 API int app_add_volatile_permissions(const char* app_id, const char** perm_list)//deprecated
862 {
863         SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
864                                 __func__, app_id);
865
866         return perm_app_enable_permissions(app_id, APP_TYPE_OTHER, perm_list, false);
867 }
868
869 API int perm_app_setup_permissions(const char* pkg_id, app_type_t app_type,
870                                    const char** perm_list)
871 {
872         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d",
873                                 __func__, pkg_id, app_type);
874         return perm_app_enable_permissions(pkg_id, app_type, perm_list, true);
875 }
876
877 API int app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)//deprecated
878 {
879         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d, persistent=%d",
880                                 __func__, pkg_id, app_type, persistent);
881
882         return perm_app_enable_permissions(pkg_id, app_type, perm_list, persistent);
883 }
884
885 API int perm_app_enable_permissions(const char* pkg_id, app_type_t app_type,
886                                     const char** perm_list, bool persistent)
887 {
888         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d, persistent=%d",
889                                 __func__, pkg_id, app_type, persistent);
890
891         int i, ret;
892
893         if (!smack_label_is_valid(pkg_id)) {
894                 C_LOGE("Invalid param app_id.");
895                 return PC_ERR_INVALID_PARAM;
896         }
897
898         if (perm_list == NULL) {
899                 C_LOGE("Invalid perm_list (NULL).");
900                 return PC_ERR_INVALID_PARAM;
901         }
902
903         if (app_type_group_name(app_type) == NULL) {
904                 C_LOGE("Unknown app type.");
905                 return PC_ERR_INVALID_PARAM;
906         }
907
908         /* Add permission to DAC */
909         for (i = 0; perm_list[i] != NULL; ++i) {
910                 ret = perm_to_dac(pkg_id, app_type, perm_list[i]);
911                 if (ret != PC_OPERATION_SUCCESS) {
912                         C_LOGE("perm_to_dac failed");
913                         return ret;
914                 }
915         }
916
917         /* Enable the permissions: */
918         ret = rdb_enable_app_permissions(pkg_id, app_type, perm_list,
919                                          !((bool)persistent));
920         if (ret != PC_OPERATION_SUCCESS) {
921                 C_LOGE("RDB rdb_enable_app_permissions failed with: %d", ret);
922                 return ret;
923         }
924
925         return PC_OPERATION_SUCCESS;
926 }
927
928 API int app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)//deprecated
929 {
930         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d",
931                                 __func__, pkg_id, app_type);
932
933         return perm_app_disable_permissions(pkg_id, app_type, perm_list);
934 }
935
936 API int perm_app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)
937 {
938         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d",
939                                 __func__, pkg_id, app_type);
940
941         int ret;
942         if (!smack_label_is_valid(pkg_id)) {
943                 C_LOGE("Invalid param app_id.");
944                 return PC_ERR_INVALID_PARAM;
945         }
946
947         if (perm_list == NULL) {
948                 C_LOGE("Invalid perm_list (NULL).");
949                 return PC_ERR_INVALID_PARAM;
950         }
951
952         if (app_type_group_name(app_type) == NULL) {
953                 C_LOGE("Unknown app type.");
954                 return PC_ERR_INVALID_PARAM;
955         }
956
957         ret = rdb_disable_app_permissions(pkg_id, app_type, perm_list);
958         if (ret != PC_OPERATION_SUCCESS) {
959                 C_LOGE("RDB rdb_disable_app_permissions failed with: %d", ret);
960                 return ret;
961         }
962
963         return PC_OPERATION_SUCCESS;
964 }
965
966 API int app_revoke_permissions(const char* pkg_id)//deprecated
967 {
968         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s", __func__, pkg_id);
969         return perm_app_revoke_permissions(pkg_id);
970 }
971
972 API int perm_app_revoke_permissions(const char* pkg_id)
973 {
974         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s", __func__, pkg_id);
975         int ret;
976
977         if (!smack_label_is_valid(pkg_id)) {
978                 C_LOGE("Invalid param app_id.");
979                 return PC_ERR_INVALID_PARAM;
980         }
981
982         ret = rdb_revoke_app_permissions(pkg_id);
983         if (ret != PC_OPERATION_SUCCESS) {
984                 C_LOGE("RDB rdb_disable_app_permissions failed with: %d", ret);
985                 return ret;
986         }
987
988         return PC_OPERATION_SUCCESS;
989 }
990
991 API int app_reset_permissions(const char* pkg_id)//deprecated
992 {
993         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s",
994                                 __func__, pkg_id);
995
996         return perm_app_reset_permissions(pkg_id);
997 }
998
999 API int perm_app_reset_permissions(const char* pkg_id)
1000 {
1001         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s",
1002                                 __func__, pkg_id);
1003         int ret;
1004
1005         if (!smack_label_is_valid(pkg_id)) {
1006                 C_LOGE("Invalid param pkg_id.");
1007                 return PC_ERR_INVALID_PARAM;
1008         }
1009
1010         ret = rdb_reset_app_permissions(pkg_id);
1011         if (ret != PC_OPERATION_SUCCESS) {
1012                 C_LOGE("RDB rdb_disable_app_permissions failed with: %d", ret);
1013                 return ret;
1014         }
1015
1016         return PC_OPERATION_SUCCESS;
1017 }
1018
1019 API int perm_app_has_permission(const char *pkg_id,
1020                                 app_type_t app_type,
1021                                 const char *permission_name,
1022                                 bool *is_enabled)
1023 {
1024         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d, permission_name=%s",
1025                                 __func__, pkg_id, app_type, permission_name);
1026
1027         const char *app_group = app_type_group_name(app_type);
1028
1029         if (app_group == NULL) {
1030                 C_LOGE("Unknown param app type.");
1031                 return PC_ERR_INVALID_PARAM;
1032         }
1033
1034         if (!smack_label_is_valid(pkg_id)) {
1035                 C_LOGE("Invalid param app_id.");
1036                 return PC_ERR_INVALID_PARAM;
1037         }
1038
1039         if (permission_name == NULL) {
1040                 C_LOGE("Invalid param permission_name (NULL).");
1041                 return PC_ERR_INVALID_PARAM;
1042         }
1043
1044         if (is_enabled == NULL) {
1045                 C_LOGE("Invalid param is_enabled (NULL).");
1046                 return PC_ERR_INVALID_PARAM;
1047         }
1048
1049         return rdb_app_has_permission(pkg_id, app_group, permission_name, is_enabled);
1050 }
1051
1052 API int perm_app_get_permissions(const char *pkg_id, app_type_t app_type, char ***ppp_perm_list)
1053 {
1054         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_type=%d", __func__, pkg_id,
1055                       app_type);
1056
1057         const char *app_group = app_type_group_name(app_type);
1058         int ret;
1059
1060         if (ppp_perm_list == NULL) {
1061                 C_LOGE("Invalid param ppp_perm_list (NULL).");
1062                 return PC_ERR_INVALID_PARAM;
1063         }
1064         // Set the given pointer to NULL in case of future failure.
1065         *ppp_perm_list = NULL;
1066
1067         if (app_group == NULL) {
1068                 C_LOGE("Unknown param app type.");
1069                 return PC_ERR_INVALID_PARAM;
1070         }
1071
1072         if (!smack_label_is_valid(pkg_id)) {
1073                 C_LOGE("Invalid param app_id.");
1074                 return PC_ERR_INVALID_PARAM;
1075         }
1076
1077         ret = rdb_app_get_permissions(pkg_id, app_group, ppp_perm_list);
1078         if (ret != PC_OPERATION_SUCCESS) {
1079                 C_LOGE("RDB rdb_app_get_permissions failed with: %d", ret);
1080                 return ret;
1081         }
1082
1083         return PC_OPERATION_SUCCESS;
1084 }
1085
1086 API int perm_get_permissions(char ***ppp_permissions, app_type_t app_type)
1087 {
1088         SECURE_C_LOGD("Entering function: %s. Params: app_type=%d",
1089                       __func__, app_type);
1090         int ret;
1091
1092         if(ppp_permissions == NULL) {
1093                 C_LOGE("Invalid ppp_permissions (NULL).");
1094                 return PC_ERR_INVALID_PARAM;
1095         }
1096         // Set the given pointer to NULL in case of future failure
1097         *ppp_permissions = NULL;
1098
1099         const char *s_permission_type_name = app_type_group_name(app_type);
1100
1101         if(s_permission_type_name == NULL) {
1102                 C_LOGE("Unknown param app type.");
1103                 return PC_ERR_INVALID_PARAM;
1104         }
1105
1106         ret = rdb_get_permissions(ppp_permissions, s_permission_type_name);
1107
1108         if(ret != PC_OPERATION_SUCCESS) {
1109                 C_LOGE("RDB %s failed with: %d", __func__, ret);
1110                 return ret;
1111         }
1112
1113         return PC_OPERATION_SUCCESS;
1114 }
1115
1116 API int perm_get_apps_with_permission(perm_app_status_t **pp_apps,
1117                                       size_t *pi_apps_number,
1118                                       app_type_t app_type,
1119                                       const char *s_permission_name)
1120 {
1121         SECURE_C_LOGD("Entering function: %s. Params: \
1122                        app_type=%d, s_permission_name=%s",
1123                        __func__, app_type, s_permission_name);
1124         int ret;
1125
1126         if(pp_apps == NULL) {
1127                 C_LOGE("Invalid ppp_permissions (NULL).");
1128                 return PC_ERR_INVALID_PARAM;
1129         }
1130         // Set the given pointer to NULL in case of future failure
1131         *pp_apps = NULL;
1132
1133         if(pi_apps_number == NULL) {
1134                 C_LOGE("Invalid pi_apps_number (NULL).");
1135                 return PC_ERR_INVALID_PARAM;
1136         }
1137
1138         if(s_permission_name == NULL) {
1139                 C_LOGE("Invalid s_permission_name (NULL).");
1140                 return PC_ERR_INVALID_PARAM;
1141         }
1142
1143         const char *s_permission_type_name = app_type_group_name(app_type);
1144
1145         if(s_permission_type_name == NULL) {
1146                 C_LOGE("Unknown param app type.");
1147                 return PC_ERR_INVALID_PARAM;
1148         }
1149
1150         ret = rdb_get_apps_with_permission(pp_apps,
1151                                            pi_apps_number,
1152                                            s_permission_type_name,
1153                                            s_permission_name);
1154
1155         if(ret != PC_OPERATION_SUCCESS) {
1156                 C_LOGE("RDB %s failed with: %d", __func__, ret);
1157                 return ret;
1158         }
1159
1160         return PC_OPERATION_SUCCESS;
1161 }
1162
1163 API void perm_free_apps_list(perm_app_status_t *pp_apps,
1164                              size_t i_apps_number)
1165 {
1166         SECURE_C_LOGD("Entering function: %s. Params: i_apps_number=%d",
1167                       __func__, i_apps_number);
1168
1169         size_t i;
1170         if(pp_apps != NULL) {
1171                 for(i = 0; i < i_apps_number; ++i) {
1172                         free(pp_apps[i].app_id);
1173                 }
1174                 free(pp_apps);
1175         }
1176 }
1177
1178 API int app_label_dir(const char* label, const char* path)//deprecated
1179 {
1180         SECURE_C_LOGD("Entering function: %s. Params: label=%s, path=%s",
1181                                 __func__, label, path);
1182
1183         int ret = PC_OPERATION_SUCCESS;
1184
1185         if(path == NULL) {
1186                 C_LOGE("Invalid argument path (NULL).");
1187                 return PC_ERR_INVALID_PARAM;
1188         }
1189
1190         if (!smack_label_is_valid(label)) {
1191                 C_LOGE("Invalid param label.");
1192                 return PC_ERR_INVALID_PARAM;
1193         }
1194
1195         //setting access label on everything in given directory and below
1196         ret = dir_set_smack_r(path, label, SMACK_LABEL_ACCESS, &label_all);
1197         if (PC_OPERATION_SUCCESS != ret)
1198         {
1199                 C_LOGE("dir_set_smack_r failed.");
1200                 return ret;
1201         }
1202
1203         //setting execute label for everything with permission to execute
1204         ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_execs);
1205         if (PC_OPERATION_SUCCESS != ret)
1206         {
1207                 C_LOGE("dir_set_smack_r failed.");
1208                 return ret;
1209         }
1210
1211         //setting execute label for everything with permission to execute
1212         ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_links_to_execs);
1213         return ret;
1214 }
1215
1216
1217 API int app_label_shared_dir(const char* app_label, const char* shared_label, const char* path)//deprecated
1218 {
1219         SECURE_C_LOGD("Entering function: %s. Params: app_label=%s, shared_label=%s, path=%s",
1220                                 __func__, app_label, shared_label, path);
1221         int ret;
1222
1223         if(path == NULL) {
1224                 C_LOGE("Invalid param path.");
1225                 return PC_ERR_INVALID_PARAM;
1226         }
1227
1228         if(!smack_label_is_valid(app_label)) {
1229                 C_LOGE("Invalid param app_label");
1230                 return PC_ERR_INVALID_PARAM;
1231         }
1232
1233         if(!smack_label_is_valid(shared_label)) {
1234                 C_LOGE("Invalid param shared_label");
1235                 return PC_ERR_INVALID_PARAM;
1236         }
1237
1238         if (strcmp(app_label, shared_label) == 0) {
1239                 C_LOGE("app_label equals shared_label");
1240                 return PC_ERR_INVALID_PARAM;
1241         }
1242
1243         //setting label on everything in given directory and below
1244         ret = dir_set_smack_r(path, shared_label, SMACK_LABEL_ACCESS, label_all);
1245         if(ret != PC_OPERATION_SUCCESS){
1246                 C_LOGE("dir_set_smack_r failed.");
1247                 return ret;
1248         }
1249
1250         //setting transmute on dir
1251         ret = dir_set_smack_r(path, "1", SMACK_LABEL_TRANSMUTE, label_dirs);
1252         if (ret != PC_OPERATION_SUCCESS) {
1253                 C_LOGE("dir_set_smack_r failed");
1254                 return ret;
1255         }
1256
1257         return PC_OPERATION_SUCCESS;
1258 }
1259
1260 API int add_shared_dir_readers(const char* shared_label UNUSED, const char** app_list UNUSED)//deprecated
1261 {
1262         SECURE_C_LOGD("Entering function: %s. Params: shared_label=%s",
1263                                 __func__, shared_label);
1264
1265         C_LOGE("add_shared_dir_readers is deprecated and unimplemented!");
1266
1267         // TODO: This function is not implemented with RDB.
1268         return PC_ERR_INVALID_OPERATION;
1269 }
1270
1271 static char* smack_label_for_path(const char *app_id, const char *path)
1272 {
1273         SECURE_C_LOGD("Entering function: %s. Params: app_id=%s, path=%s",
1274                                 __func__, app_id, path);
1275
1276         char *salt AUTO_FREE;
1277         char *label;
1278         char *x;
1279
1280         /* Prefix $1$ causes crypt() to use MD5 function */
1281         if (-1 == asprintf(&salt, "$1$%s", app_id)) {
1282                 C_LOGE("asprintf failed");
1283                 return NULL;
1284         }
1285
1286         label = crypt(path, salt);
1287         if (label == NULL) {
1288                 C_LOGE("crypt failed");
1289                 return NULL;
1290         }
1291
1292         /* crypt() output may contain slash character,
1293          * which is not legal in Smack labels */
1294         for (x = label; *x; ++x) {
1295                 if (*x == '/')
1296                         *x = '%';
1297         }
1298
1299         return label;
1300 }
1301
1302 /* FIXME: remove this pragma once deprecated API is deleted */
1303 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1304 static int perm_app_setup_path_internal(const char* pkg_id, const char* path, app_path_type_t app_path_type, va_list ap)
1305 {
1306         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, path=%s, app_path_type=%d",
1307                                 __func__, pkg_id, path, app_path_type);
1308
1309         if(path == NULL) {
1310                 C_LOGE("Invalid argument path.");
1311                 return PC_ERR_INVALID_PARAM;
1312         }
1313
1314         if (!smack_label_is_valid(pkg_id)) {
1315                 C_LOGE("Invalid pkg_id.");
1316                 SECURE_C_LOGE("Invalid pkg_id %s", pkg_id);
1317                 return PC_ERR_INVALID_PARAM;
1318         }
1319
1320         switch (app_path_type) {
1321         case APP_PATH_PRIVATE:
1322                 C_LOGD("app_path_type is APP_PATH_PRIVATE.");
1323                 return app_label_dir(pkg_id, path);
1324
1325         case APP_PATH_GROUP: {
1326                 C_LOGD("app_path_type is APP_PATH_GROUP.");
1327                 int ret;
1328                 const char *shared_label;
1329
1330                 shared_label = va_arg(ap, const char *);
1331
1332                 if (!smack_label_is_valid(shared_label)) {
1333                         C_LOGE("Invalid shared_label.");
1334                         return PC_ERR_INVALID_PARAM;
1335                 }
1336
1337                 if (strcmp(pkg_id, shared_label) == 0) {
1338                         C_LOGE("pkg_id equals shared_label.");
1339                         return PC_ERR_INVALID_PARAM;
1340                 }
1341
1342                 ret = app_label_shared_dir(pkg_id, shared_label, path);
1343                 if (ret != PC_OPERATION_SUCCESS) {
1344                         C_LOGE("app_label_shared_dir failed: %d", ret);
1345                         return ret;
1346                 }
1347
1348                 // Add the path to the database:
1349                 ret = rdb_add_path(pkg_id, shared_label, path, "rwxatl", "-", "GROUP_PATH");
1350                 if (ret != PC_OPERATION_SUCCESS) {
1351                         C_LOGE("RDB rdb_add_path failed with: %d", ret);
1352                         return ret;
1353                 }
1354
1355                 return PC_OPERATION_SUCCESS;
1356         }
1357
1358         case APP_PATH_PUBLIC: {
1359                 C_LOGD("app_path_type is APP_PATH_PUBLIC.");
1360                 const char *label;
1361                 int ret;
1362
1363                 C_LOGD("New public RO path %s", path);
1364
1365                 // Generate label:
1366                 label = smack_label_for_path(pkg_id, path);
1367                 if (label == NULL) {
1368                         C_LOGE("smack_label_for_path failed.");
1369                         return PC_ERR_INVALID_OPERATION;
1370                 }
1371                 C_LOGD("Generated label '%s' for public RO path %s", label, path);
1372
1373                 ret = app_label_shared_dir(pkg_id, label, path);
1374                 if (ret != PC_OPERATION_SUCCESS) {
1375                         C_LOGE("app_label_shared_dir failed.");
1376                         return ret;
1377                 }
1378
1379                 // Add the path to the database:
1380                 ret = rdb_add_path(pkg_id, label, path, "rwxatl", "-", "PUBLIC_PATH");
1381                 if (ret != PC_OPERATION_SUCCESS) {
1382                         C_LOGE("RDB rdb_add_path failed with: %d", ret);
1383                         return ret;
1384                 }
1385
1386                 return PC_OPERATION_SUCCESS;
1387         }
1388
1389         case APP_PATH_SETTINGS: {
1390                 C_LOGD("app_path_type is APP_PATH_SETTINGS.");
1391                 const char *label;
1392                 int ret;
1393
1394                 // Generate label:
1395                 label = smack_label_for_path(pkg_id, path);
1396                 if (label == NULL) {
1397                         C_LOGE("smack_label_for_path failed.");
1398                         return PC_ERR_INVALID_OPERATION;
1399                 }
1400                 C_LOGD("Appsetting: generated label '%s' for setting path %s", label, path);
1401
1402                 /*set id for path and all subfolders*/
1403                 ret = app_label_shared_dir(pkg_id, label, path);
1404                 if (ret != PC_OPERATION_SUCCESS) {
1405                         C_LOGE("Appsetting: app_label_shared_dir failed (%d)", ret);
1406                         return ret;
1407                 }
1408
1409                 // Add the path to the database:
1410                 ret = rdb_add_path(pkg_id, label, path, "rwxatl", "-", "SETTINGS_PATH");
1411                 if (ret != PC_OPERATION_SUCCESS) {
1412                         C_LOGE("RDB rdb_add_path failed with: %d", ret);
1413                         return ret;
1414                 }
1415
1416                 return PC_OPERATION_SUCCESS;
1417         }
1418
1419         case PERM_APP_PATH_NPRUNTIME: {
1420                 C_LOGD("app_path_type is PERM_APP_PATH_NPRUNTIME.");
1421                 char label[SMACK_LABEL_LEN + 1];
1422                 int ret;
1423
1424                 // Create label:
1425                 if ((strlen(pkg_id) + strlen(".npruntime")) > SMACK_LABEL_LEN) {
1426                         C_LOGE("cannot create npruntime label, pkg_id is too long.");
1427                         return PC_ERR_INVALID_PARAM;
1428                 }
1429                 ret = sprintf(label, "%s.npruntime", pkg_id);
1430                 if (ret <= 0) {
1431                         C_LOGE("creating npruntime label failed.");
1432                         return PC_ERR_INVALID_OPERATION;
1433                 }
1434                 C_LOGD("Generated npruntime label '%s' for path %s", label, path);
1435
1436                 // Label executable/symlink
1437                 ret = set_exec_label(label, path);
1438                 if (ret != PC_OPERATION_SUCCESS) {
1439                         C_LOGE("cannot set executable label '%s' for path %s.", label, path);
1440                         return ret;
1441                 }
1442
1443                 // Add the path to the database:
1444                 ret = rdb_add_path(pkg_id, label, path, "rw", "rxat", "NPRUNTIME_PATH");
1445                 if (ret != PC_OPERATION_SUCCESS) {
1446                         C_LOGE("RDB rdb_add_path failed with: %d", ret);
1447                         return ret;
1448                 }
1449
1450                 return PC_OPERATION_SUCCESS;
1451         }
1452
1453         case APP_PATH_ANY_LABEL: {
1454                 C_LOGD("app_path_type is APP_PATH_ANY_LABEL.");
1455                 const char *label = NULL;
1456                 label = va_arg(ap, const char *);
1457                 return app_label_dir(label, path);
1458         }
1459
1460         default:
1461                 C_LOGE("app_path_type is invalid.");
1462                 return PC_ERR_INVALID_PARAM;
1463         }
1464
1465         return PC_OPERATION_SUCCESS;
1466 }
1467 /* FIXME: remove this pragma once deprecated API is deleted */
1468 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
1469
1470 API int app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)//deprecated
1471 {
1472         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, path=%s, app_path_type=%d",
1473                                 __func__, pkg_id, path, app_path_type);
1474
1475         va_list ap;
1476         int ret;
1477         va_start( ap, app_path_type );
1478         ret = perm_app_setup_path_internal( pkg_id, path, app_path_type, ap );
1479         va_end( ap );
1480         return ret;
1481 }
1482
1483
1484 API int perm_app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)
1485 {
1486         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, path=%s, app_path_type=%d",
1487                                 __func__, pkg_id, path, app_path_type);
1488
1489         va_list ap;
1490         int ret;
1491         va_start( ap, app_path_type );
1492         ret = perm_app_setup_path_internal( pkg_id, path, app_path_type, ap );
1493         va_end( ap );
1494         return ret;
1495 }
1496
1497 API int perm_app_get_paths(const char* pkg_id, app_path_type_t app_path_type, char*** ppp_paths)
1498 {
1499         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, app_path_type=%d", __func__,
1500                       pkg_id, app_path_type);
1501
1502         const char *path_type_name = app_path_type_name(app_path_type);
1503         int ret;
1504
1505         if (ppp_paths == NULL) {
1506                 C_LOGE("Invalid param ppp_paths (NULL).");
1507                 return PC_ERR_INVALID_PARAM;
1508         }
1509         // Set the given pointer to NULL in case of future failure.
1510         *ppp_paths = NULL;
1511
1512         if (path_type_name == NULL) {
1513                 C_LOGE("Unknown or invalid param app_path_type.");
1514                 return PC_ERR_INVALID_PARAM;
1515         }
1516
1517         if (!smack_label_is_valid(pkg_id)) {
1518                 C_LOGE("Invalid param app_id.");
1519                 return PC_ERR_INVALID_PARAM;
1520         }
1521
1522         ret = rdb_get_app_paths(pkg_id, path_type_name, ppp_paths);
1523         if (ret != PC_OPERATION_SUCCESS) {
1524                 C_LOGE("RDB rdb_app_get_paths failed with: %d", ret);
1525                 return ret;
1526         }
1527
1528         return PC_OPERATION_SUCCESS;
1529 }
1530
1531 API int perm_app_remove_path(const char* pkg_id, const char *path)
1532 {
1533         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s, path=%s", __func__, pkg_id, path);
1534
1535         int ret;
1536
1537         if (path == NULL) {
1538                 C_LOGE("Invalid param path (NULL).");
1539                 return PC_ERR_INVALID_PARAM;
1540         }
1541
1542         if (!smack_label_is_valid(pkg_id)) {
1543                 C_LOGE("Invalid param app_id.");
1544                 return PC_ERR_INVALID_PARAM;
1545         }
1546
1547         ret = rdb_remove_path(pkg_id, path);
1548         if (ret != PC_OPERATION_SUCCESS) {
1549                 C_LOGE("RDB rdb_remove_path failed with %d", ret);
1550                 return ret;
1551         }
1552
1553         return PC_OPERATION_SUCCESS;
1554 }
1555
1556 API int app_add_friend(const char* pkg_id1, const char* pkg_id2)//deprecated
1557 {
1558         SECURE_C_LOGD("Entering function: %s. Params: pkg_id1=%s, pkg_id2=%s",
1559                                 __func__, pkg_id1, pkg_id2);
1560
1561         return perm_app_add_friend(pkg_id1, pkg_id2);
1562 }
1563
1564 API int perm_app_add_friend(const char* pkg_id1 UNUSED, const char* pkg_id2 UNUSED)
1565 {
1566         SECURE_C_LOGD("Entering function: %s. Params: pkg_id1=%s, pkg_id2=%s",
1567                                 __func__, pkg_id1, pkg_id2);
1568
1569         C_LOGE("app_register_av is deprecated and unimplemented!");
1570
1571         // TODO: This function is not implemented with RDB.
1572         return PC_ERR_INVALID_OPERATION;
1573 }
1574
1575 API int app_install(const char* pkg_id)//deprecated
1576 {
1577         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s",
1578                                 __func__, pkg_id);
1579
1580         return perm_app_install(pkg_id);
1581 }
1582
1583 API int perm_app_install(const char* pkg_id)
1584 {
1585         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s",
1586                                 __func__, pkg_id);
1587         int ret;
1588
1589         if (!smack_label_is_valid(pkg_id)) {
1590                 C_LOGE("Invalid param pkg_id.");
1591                 return PC_ERR_INVALID_PARAM;
1592         }
1593
1594         // Add application to the database:
1595         ret = rdb_add_application(pkg_id);
1596         if (ret != PC_OPERATION_SUCCESS) {
1597                 C_LOGE("RDB rdb_add_application failed with: %d", ret);
1598                 return ret;
1599         }
1600
1601         return PC_OPERATION_SUCCESS;
1602 }
1603
1604 API int app_uninstall(const char* pkg_id)//deprecated
1605 {
1606         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s",
1607                                 __func__, pkg_id);
1608
1609         return perm_app_uninstall(pkg_id);
1610 }
1611
1612 API int perm_app_uninstall(const char* pkg_id)
1613 {
1614         SECURE_C_LOGD("Entering function: %s. Params: pkg_id=%s", __func__, pkg_id);
1615         int ret;
1616
1617         if (!smack_label_is_valid(pkg_id)) {
1618                 C_LOGE("Invalid param pkg_id.");
1619                 return PC_ERR_INVALID_PARAM;
1620         }
1621
1622         // Remove application from the database
1623         ret = rdb_remove_application(pkg_id);
1624         if (ret != PC_OPERATION_SUCCESS) {
1625                 C_LOGE("RDB rdb_remove_application failed with: %d", ret);
1626                 return ret;
1627         }
1628
1629         return PC_OPERATION_SUCCESS;
1630 }
1631
1632 static int save_gids(FILE* file, const gid_t* list_of_db_gids, size_t list_size) {
1633
1634         SECURE_C_LOGD("Entering function: %s.", __func__);
1635         int ret = PC_OPERATION_SUCCESS;
1636         int written = 0;
1637         size_t i = 0;
1638
1639         if (file == NULL) {
1640                 C_LOGE("Unable to create file. Error: %s", strerror(errno));
1641                 return PC_ERR_FILE_OPERATION;   // TODO remove smack accesses?
1642         }
1643
1644         if(-1 == fchmod(fileno(file), 0644)) {
1645                 C_LOGE("Unable to chmod file. Error: %s", strerror(errno));
1646                 return PC_ERR_FILE_OPERATION;
1647         }
1648
1649         for (i = 0; i < list_size ; ++i) {
1650                 written = fprintf(file, "%u\n", list_of_db_gids[i]);
1651                 if (written <= 0) {
1652                         C_LOGE("fprintf failed for file. Error: %s", strerror(errno));
1653                         ret = PC_ERR_FILE_OPERATION;
1654                         break;
1655                 }
1656         }
1657         return ret;
1658 }
1659
1660 API int add_api_feature(app_type_t app_type,
1661                         const char* api_feature_name,
1662                         const char** smack_rules,
1663                         const gid_t* list_of_db_gids,
1664                         size_t list_size)//deprecated
1665 {
1666         SECURE_C_LOGD("Entering function: %s. Params: app_type=%d, api_feature_name=%s",
1667                                 __func__, app_type, api_feature_name);
1668
1669     return perm_add_api_feature(app_type, api_feature_name, smack_rules, list_of_db_gids, list_size);
1670 }
1671
1672 API int perm_add_api_feature(app_type_t app_type,
1673                                                 const char* api_feature_name,
1674                                                 const char** smack_rules,
1675                                                 const gid_t* list_of_db_gids,
1676                                                 size_t list_size) {
1677         SECURE_C_LOGD("Entering function: %s. Params: app_type=%d, api_feature_name=%s",
1678                                 __func__, app_type, api_feature_name);
1679
1680         int ret = PC_OPERATION_SUCCESS;
1681         char* dac_file AUTO_FREE;
1682         char * base_api_feature_name AUTO_FREE;
1683         FILE* file = NULL;
1684         // struct smack_accesses* accesses = NULL;
1685         const char *s_type_name = app_type_name(app_type);
1686
1687         // Check input values
1688         if (s_type_name == NULL || !strcmp(s_type_name, "")) {
1689                 C_LOGE("Unknown api type");
1690                 return PC_ERR_INVALID_PARAM;
1691         }
1692
1693         if (api_feature_name == NULL || strlen(api_feature_name) == 0) {
1694                 C_LOGE("Api feature name is empty.");
1695                 return PC_ERR_INVALID_PARAM;
1696         }
1697
1698         if (smack_rules && ((ret = validate_all_rules(smack_rules) ) != PC_OPERATION_SUCCESS) ) {
1699                 C_LOGE("Error in rules list.");
1700                 return ret;
1701         }
1702
1703         // check .dac existence only if gids are supported
1704         if (list_of_db_gids && list_size > 0) {
1705                 // get feature DAC file name
1706                 ret = perm_file_path(&dac_file, app_type, api_feature_name, ".dac", 0);
1707                 if (ret != PC_OPERATION_SUCCESS || !dac_file ) {
1708                         C_LOGE("perm_file_path failed.");
1709                         return ret;
1710                 }
1711
1712                 unlink(dac_file);
1713         }
1714
1715         // go through gid list
1716         if (ret == PC_OPERATION_SUCCESS && list_of_db_gids && list_size > 0) {
1717                 // save to file
1718                 SECURE_C_LOGD("Opening file %s.", dac_file);
1719                 file = fopen(dac_file, "w+");
1720                 ret = save_gids(file, list_of_db_gids, list_size);
1721                 if(file) fclose(file);
1722         }
1723
1724         // remove file in case of failure
1725         if (ret != PC_OPERATION_SUCCESS && dac_file) {
1726                 unlink(dac_file);
1727         }
1728
1729         ret = base_name_from_perm(api_feature_name, &base_api_feature_name);
1730         if (ret != PC_OPERATION_SUCCESS){
1731                 C_LOGE("Error during creating base name: ", ret);
1732                 return ret;
1733         }
1734
1735         // Save api feature to the database.
1736         ret = rdb_add_permission_rules(base_api_feature_name, s_type_name, smack_rules);
1737         if (ret != PC_OPERATION_SUCCESS) {
1738                 C_LOGE("RDB rdb_add_permission_rules failed with: %d", ret);
1739                 return ret;
1740         }
1741
1742         return ret;
1743 }
1744
1745 /**
1746  * This function is marked as deprecated and will be removed
1747  */
1748 API int app_register_av(const char* app_av_id UNUSED)//deprecated
1749 {
1750         SECURE_C_LOGD("Entering function: %s. Params: app_av_id=%s",
1751                                 __func__, app_av_id);
1752
1753         C_LOGE("app_register_av is deprecated and unimplemented!");
1754
1755         // TODO: This function is not implemented with RDB.
1756         return PC_ERR_INVALID_OPERATION;
1757 }
1758
1759 API int perm_add_additional_rules(const char** smack_rules){
1760         SECURE_C_LOGD("Entering function: %s.", __func__);
1761         int ret;
1762         if (!smack_rules){
1763                 C_LOGE("smack_rules is NULL");
1764                 return PC_ERR_INVALID_PARAM;
1765         }
1766
1767         ret = rdb_add_additional_rules(smack_rules);
1768         if (ret != PC_OPERATION_SUCCESS) {
1769                 C_LOGE("RDB rdb_add_additional_rules failed with: %d", ret);
1770                 return ret;
1771         }
1772
1773         return PC_OPERATION_SUCCESS;
1774 }
1775
1776 API const char* perm_strerror(int errnum)
1777 {
1778         switch (errnum) {
1779         case PC_OPERATION_SUCCESS:
1780                 return "Success";
1781         case PC_ERR_FILE_OPERATION:
1782                 return "File operation error";
1783         case PC_ERR_MEM_OPERATION:
1784                 return "Memory operation error";
1785         case PC_ERR_NOT_PERMITTED:
1786                 return "Operation not permitted";
1787         case PC_ERR_INVALID_PARAM:
1788                 return "Invalid parameter";
1789         case PC_ERR_INVALID_OPERATION:
1790                 return "Invalid operation";
1791         case PC_ERR_DB_OPERATION:
1792                 return "Database operation error";
1793         case PC_ERR_DB_LABEL_TAKEN:
1794                 return "Label taken by another application";
1795         case PC_ERR_DB_QUERY_PREP:
1796                 return "Query failure during preparation";
1797         case PC_ERR_DB_QUERY_BIND:
1798                 return "Query failure during binding";
1799         case PC_ERR_DB_QUERY_STEP:
1800                 return "Query failure during stepping";
1801         case PC_ERR_DB_CONNECTION:
1802                 return "Cannot establish a connection";
1803         case PC_ERR_DB_NO_SUCH_APP:
1804                 return "No such application";
1805         case PC_ERR_DB_PERM_FORBIDDEN:
1806                 return "Duplicate permission";
1807         default:
1808                 return "Unknown error";
1809         }
1810 }