Create format strings for scanf statically.
[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 #include <iri.h>
45
46 #include "privilege-control.h"
47 #include "access-db.h"
48 #include "common.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_APP_LABEL_TEMPLATE        "~APP~"
65 #define SMACK_SHARED_DIR_LABEL_TEMPLATE "~APP_SHARED_DIR~"
66
67 #define SMACK_SRC_FILE_SUFFIX   "_src_file"
68 #define SMACK_SRC_DIR_SUFFIX    "_src_dir"
69 #define SMACK_DATA_SUFFIX       "_data"
70 #define WRT_BASE_DEVCAP         "WRT"
71 #define WRT_CLIENT_PATH         "/usr/bin/wrt-client"
72 #define ACC_LEN                 5
73 #define TIZEN_PRIVILEGE_ANTIVIRUS  "http://tizen.org/privilege/antivirus"
74 #define TIZEN_PRIVILEGE_APPSETTING "http://tizen.org/privilege/appsetting"
75 #define PATH_RULES_PUBLIC_RO       "PATH_RULES_PUBLIC_RO.smack"
76 #define PATH_RULES_GROUP_RW        "PATH_RULES_GROUP_RW.smack"
77
78 typedef struct {
79         char user_name[10];
80         int uid;
81         int gid;
82         char home_dir[64];
83         char group_list[64];
84 } new_user;
85
86 /**
87  * Return values
88  * <0 - error
89  * 0 - skip
90  * 1 - label
91  */
92 typedef int (*label_decision_fn)(const FTSENT*);
93 enum {
94         DECISION_SKIP = 0,
95         DECISION_LABEL = 1
96 };
97
98 API int control_privilege(void)//deprecated
99 {
100         C_LOGD("Enter function: %s", __func__);
101         if(getuid() == APP_UID) // current user is 'app'
102                 return PC_OPERATION_SUCCESS;
103
104         if(perm_app_set_privilege("org.tizen.", NULL, NULL) == PC_OPERATION_SUCCESS)
105                 return PC_OPERATION_SUCCESS;
106         else
107                 return PC_ERR_NOT_PERMITTED;
108 }
109
110 /**
111  * TODO: this function should be moved to libsmack in open-source.
112  */
113 API int get_smack_label_from_process(pid_t pid, char smack_label[SMACK_LABEL_LEN + 1])
114 {
115         C_LOGD("Enter function: %s", __func__);
116         int ret;
117         int fd AUTO_CLOSE;
118         int PATH_MAX_LEN = 64;
119         char path[PATH_MAX_LEN + 1];
120
121         if (pid < 0) {
122                 ret = PC_ERR_INVALID_PARAM;
123                 goto out;
124         }
125
126         if(smack_label == NULL) {
127                 C_LOGE("Invalid param smack_label (NULL).");
128                 ret = PC_ERR_INVALID_PARAM;
129                 goto out;
130         }
131
132         bzero(smack_label, SMACK_LABEL_LEN + 1);
133         if (!have_smack()) { // If no smack found just return success and empty label
134                 C_LOGD("No SMACK. Return empty label");
135                 ret = PC_OPERATION_SUCCESS;
136                 goto out;
137         }
138
139         bzero(path, PATH_MAX_LEN + 1);
140         snprintf(path, PATH_MAX_LEN, "/proc/%d/attr/current", pid);
141         fd = open(path, O_RDONLY);
142         if (fd < 0) {
143                 C_LOGE("cannot open file %s (errno: %s)", path, strerror(errno));
144                 ret = PC_ERR_FILE_OPERATION;
145                 goto out;
146         }
147
148         ret = read(fd, smack_label, SMACK_LABEL_LEN);
149         if (ret < 0) {
150                 C_LOGE("cannot read from file %s", path);
151                 ret = PC_ERR_FILE_OPERATION;
152                 goto out;
153         }
154
155         ret = PC_OPERATION_SUCCESS;
156
157 out:
158         return ret;
159 }
160
161 API int smack_pid_have_access(pid_t pid,
162                                                                 const char* object,
163                                                                 const char *access_type)
164 {
165         C_LOGD("Enter function: %s", __func__);
166         int ret;
167         char pid_subject_label[SMACK_LABEL_LEN + 1];
168         cap_t cap;
169         cap_flag_value_t cap_v;
170
171         if (!have_smack()) {
172                 C_LOGD("No SMACK. Return access granted");
173                 return 1;
174         }
175
176         if (pid < 0) {
177                 C_LOGE("Invalid pid.");
178                 return -1;
179         }
180
181         if(object == NULL) {
182                 C_LOGE("Invalid object param.");
183                 return -1;
184         }
185
186         if(access_type == NULL) {
187                 C_LOGE("Invalid access_type param");
188                 return -1;
189         }
190
191         //get SMACK label of process
192         ret = get_smack_label_from_process(pid, pid_subject_label);
193         if (PC_OPERATION_SUCCESS != ret) {
194                 C_LOGE("get_smack_label_from_process %d failed: %d", pid, ret);
195                 return -1;
196         }
197         C_LOGD("pid %d have label: %s", pid, pid_subject_label);
198
199         // do not call smack_have_access() if label is empty
200         if (pid_subject_label[0] != '\0') {
201                 ret = smack_have_access(pid_subject_label, object, access_type);
202                 if ( -1 == ret) {
203                         C_LOGE("smack_have_access failed");
204                         return -1;
205                 }
206                 if ( 1 == ret ) { // smack_have_access return 1 (access granted)
207                         C_LOGD("smack_have_access returned 1 (access granted)");
208                         return 1;
209                 }
210         }
211
212         // smack_have_access returned 0 (access denied). Now CAP_MAC_OVERRIDE should be checked
213         C_LOGD("smack_have_access returned 0 (access denied)");
214         cap = cap_get_pid(pid);
215         if (cap == NULL) {
216                 C_LOGE("cap_get_pid failed");
217                 return -1;
218         }
219         ret = cap_get_flag(cap, CAP_MAC_OVERRIDE, CAP_EFFECTIVE, &cap_v);
220         if (0 != ret) {
221                 C_LOGE("cap_get_flag failed");
222                 return -1;
223         }
224
225         if (cap_v == CAP_SET) {
226                 C_LOGD("pid %d has CAP_MAC_OVERRIDE", pid);
227                 return 1;
228
229         } else {
230                 C_LOGD("pid %d doesn't have CAP_MAC_OVERRIDE", pid);
231                 return 0;
232         }
233 }
234
235 static int set_dac(const char *smack_label, const char *pkg_name)
236 {
237         C_LOGD("Enter function: %s", __func__);
238         FILE* fp_group = NULL;  // /etc/group
239         uid_t t_uid = -1;               // uid of current process
240         gid_t *glist = NULL;    // group list
241         gid_t temp_gid = -1;    // for group list
242         char buf[10] = {0, };           // contents in group_list file
243         int glist_cnt = 0;              // for group list
244         int result;
245         int i;
246         new_user usr;
247         unsigned *additional_gids = NULL;
248
249         /*
250          * initialize user structure
251          */
252         C_LOGD("initialize user structure");
253         memset(usr.user_name, 0x00, 10);
254         memset(usr.home_dir, 0x00, 64);
255         memset(usr.group_list, 0x00, 64);
256         usr.uid = -1;
257         usr.gid = -1;
258
259         t_uid = getuid();
260         C_LOGD("Current uid is %d", t_uid);
261
262         if(t_uid == 0)  // current user is 'root'
263         {
264                 if(!strncmp(pkg_name, "developer", 9))
265                 {
266                         strncpy(usr.user_name, DEV_USER_NAME, sizeof(usr.user_name));
267                         usr.uid = DEVELOPER_UID;
268                         usr.gid = DEVELOPER_GID;
269                         strncpy(usr.home_dir, DEV_HOME_DIR, sizeof(usr.home_dir));
270                         strncpy(usr.group_list, DEV_GROUP_PATH, sizeof(usr.group_list));
271                 }
272                 else
273                 {
274                         strncpy(usr.user_name, APP_USER_NAME, sizeof(usr.user_name));
275                         usr.uid = APP_UID;
276                         usr.gid = APP_GID;
277                         strncpy(usr.home_dir, APP_HOME_DIR, sizeof(usr.home_dir));
278                         strncpy(usr.group_list, APP_GROUP_PATH, sizeof(usr.group_list));
279                 }
280
281                 /*
282                  * get group information
283                  */
284                 C_LOGD("get group information");
285                 if(!(fp_group = fopen(usr.group_list, "r")))
286                 {
287                         C_LOGE("File open error: %s", usr.group_list);
288                         result = PC_ERR_FILE_OPERATION; // return -1
289                         goto error;
290                 }
291
292                 while(fgets(buf, 10, fp_group) != NULL)
293                 {
294                         errno = 0;
295                         temp_gid = strtoul(buf, 0, 10);
296                         if(errno != 0)  // error occured during strtoul()
297                         {
298                                 C_LOGE("Cannot change string to integer: %s", buf);
299                                 result = PC_ERR_INVALID_OPERATION;
300                                 goto error;
301                         }
302
303                         glist = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + 1));
304                         if(!glist)
305                         {
306                                 result = PC_ERR_MEM_OPERATION;  // return -2
307                                 C_LOGE("Cannot allocate memory");
308                                 goto error;
309                         }
310                         glist[glist_cnt] = temp_gid;
311                         glist_cnt++;
312                 }
313                 fclose(fp_group);
314                 fp_group = NULL;
315
316                 if(NULL != smack_label)
317                 {
318                         gid_t *glist_new;
319                         int i, cnt;
320
321                         result = get_app_gids(smack_label, &additional_gids, &cnt);
322                         if (result != PC_OPERATION_SUCCESS)
323                                 goto error;
324
325                         if (cnt > 0) {
326                                 glist_new = (gid_t*)realloc(glist, sizeof(gid_t) * (glist_cnt + cnt));
327                                 if (glist_new == NULL) {
328                                         result = PC_ERR_MEM_OPERATION;  // return -2
329                                         C_LOGE("Memory allocation failed");
330                                         goto error;
331                                 }
332                                 glist = glist_new;
333                                 for (i = 0; i < cnt; ++i) {
334                                         C_LOGD("Additional GID based on enabled permissions: %u", additional_gids[i]);
335                                         glist[glist_cnt++] = additional_gids[i];
336                                 }
337                         }
338                 }
339
340                 /*
341                  * setgroups()
342                  */
343                 C_LOGD("Adding process to the following groups:");
344                 for(i=0; i<glist_cnt; ++i) {
345                         C_LOGD("glist [ %d ] = %d", i, glist[i]);
346                 }
347                 C_LOGD("setgroups()");
348                 if(setgroups(glist_cnt, glist) != 0)
349                 {
350                         C_LOGE("setgroups failed");
351                         result = PC_ERR_NOT_PERMITTED;  // return -3
352                         goto error;
353                 }
354                 if(glist != NULL)
355                 {
356                         free(glist);
357                         glist = NULL;
358                 }
359
360                 /*
361                  * setuid() & setgid()
362                  */
363                 C_LOGD("setgid( %d ) & setuid( %d )", usr.gid, usr.uid);
364                 if(setgid(usr.gid) != 0)        // fail
365                 {
366                         C_LOGE("Failed to execute setgid().");
367                         result = PC_ERR_INVALID_OPERATION;
368                         goto error;
369                 }
370                 if(setuid(usr.uid) != 0)        // fail
371                 {
372                         C_LOGE("Failed to execute setuid().");
373                         result = PC_ERR_INVALID_OPERATION;
374                         goto error;
375                 }
376
377                 SECURE_SLOGD("setenv(): USER = %s, HOME = %s", usr.user_name, usr.home_dir);
378                 if(setenv("USER", usr.user_name, 1) != 0)       //fail
379                 {
380                         C_LOGE("Failed to execute setenv() [USER].");
381                         result = PC_ERR_INVALID_OPERATION;
382                         goto error;
383                 }
384                 if(setenv("HOME", usr.home_dir, 1) != 0)        // fail
385                 {
386                         C_LOGE("Failed to execute setenv() [HOME].");
387                         result = PC_ERR_INVALID_OPERATION;
388                         goto error;
389                 }
390         }
391         else    // current user is not only 'root' but 'app'
392         {
393                 C_LOGE("Current user is NOT root");
394                 result = PC_ERR_NOT_PERMITTED;  // return -3
395                 goto error;
396         }
397
398         result = PC_OPERATION_SUCCESS;
399
400 error:
401         if(fp_group != NULL)
402                 fclose(fp_group);
403         if(glist != NULL)
404                 free(glist);
405         free(additional_gids);
406
407         return result;
408 }
409
410 /**
411  * Get SMACK label from EXEC label of a file.
412  * SMACK label should be freed by caller
413  *
414  * @param path file path to take label from
415  * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
416  */
417 static int get_smack_from_binary(char **smack_label, const char* path, app_type_t type)
418 {
419         C_LOGD("Enter function: %s", __func__);
420         int ret;
421
422         C_LOGD("Path: %s", path);
423
424         *smack_label = NULL;
425         if (type == APP_TYPE_WGT
426         || type == APP_TYPE_WGT_PARTNER
427         || type == APP_TYPE_WGT_PLATFORM) {
428                 ret = smack_lgetlabel(path, smack_label, SMACK_LABEL_EXEC);
429         } else {
430                 ret = smack_getlabel(path, smack_label, SMACK_LABEL_EXEC);
431         }
432         if (ret != 0) {
433                 C_LOGE("Getting exec label from file %s failed", path);
434                 return PC_ERR_INVALID_OPERATION;
435         }
436
437         return PC_OPERATION_SUCCESS;
438 }
439
440 /**
441  * Set process SMACK label.
442  * This function is emulating EXEC label behavior of SMACK for programs
443  * run by dlopen/dlsym instead of execv.
444  *
445  * @param smack label
446  * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
447  */
448 static int set_smack_for_self (char *smack_label)
449 {
450         C_LOGD("Enter function: %s", __func__);
451         int ret;
452
453         if (smack_label == NULL) {
454                 /* No label to set, just return with success */
455                 C_LOGD("No label to set, just return with success");
456                 ret = PC_OPERATION_SUCCESS;
457         }
458         else {
459                 C_LOGD("label = %s", smack_label);
460                 if (have_smack()) {
461                         ret = smack_set_label_for_self(smack_label);
462                         C_LOGD("smack_set_label_for_self returned %d", ret);
463                 } else
464                         ret = PC_OPERATION_SUCCESS;
465         }
466
467         return ret;
468 }
469
470 static int is_widget(const char* path)
471 {
472         C_LOGD("Enter function: %s", __func__);
473         char buf[sizeof(WRT_CLIENT_PATH)];
474         int ret;
475
476         ret = readlink(path, buf, sizeof(WRT_CLIENT_PATH));
477         if (ret == -1)
478                 C_LOGD("readlink(%s) returned error: %s. Assuming that app is not a widget", path, strerror(errno));
479         else if (ret == sizeof(WRT_CLIENT_PATH))
480                 C_LOGD("%s is not a widget", path);
481         if (ret == -1 || ret == sizeof(WRT_CLIENT_PATH))
482                 return 0;
483         buf[ret] = '\0';
484         C_LOGD("buf = %s", buf);
485
486         ret = !strcmp(WRT_CLIENT_PATH, buf);
487         C_LOGD("%s is %s widget", path, ret ? "a" : "not a");
488         return (ret);
489 }
490
491 /**
492  * Partially verify, that the type given for app is correct.
493  * This function will use some heuristics to check whether the app type is right.
494  * It is intended for security hardening to catch privilege setting for the
495  * app type not corresponding to the actual binary.
496  * Beware - when it detects an anomaly, the whole process will be terminated.
497  *
498  * @param type claimed application type
499  * @param path file path to executable
500  * @return return void on success, terminate the process on error
501  */
502 static app_type_t verify_app_type(const char* type, const char* path)
503 {
504         C_LOGD("Enter function: %s", __func__);
505         /* TODO: this should actually be treated as error, but until the old
506          * set_privilege API is removed, it must be ignored */
507         if (path == NULL) {
508                 C_LOGD("PKG_TYPE_OTHER");
509                 return APP_TYPE_OTHER; /* good */
510         }
511
512         if (is_widget(path)) {
513                 if (!strcmp(type, "wgt")) {
514                         C_LOGD("PKG_TYPE_WGT");
515                         return APP_TYPE_WGT; /* good */
516                 } else if (!strcmp(type, "wgt_partner")) {
517                         C_LOGD("PKG_TYPE_WGT_PARTNER");
518                         return APP_TYPE_WGT_PARTNER; /* good */
519                 } else if (!strcmp(type, "wgt_platform")) {
520                         C_LOGD("PKG_TYPE_WGT_PLATFORM");
521                         return APP_TYPE_WGT_PLATFORM; /* good */
522                 }
523
524         } else {
525                 if (type == NULL || (strcmp(type, "wgt")
526                                 && strcmp(type, "wgt_partner")
527                                 && strcmp(type, "wgt_platform"))){
528                         C_LOGD("PKG_TYPE_OTHER");
529                         return APP_TYPE_OTHER; /* good */
530                 }
531         }
532
533         /* bad */
534         C_LOGE("EXIT_FAILURE");
535         exit(EXIT_FAILURE);
536 }
537
538 API int set_app_privilege(const char* name, const char* type, const char* path)//deprecated
539 {
540     return perm_app_set_privilege(name, type, path);
541 }
542
543 API int perm_app_set_privilege(const char* name, const char* type, const char* path)
544 {
545         C_LOGD("Enter function: %s", __func__);
546         SECURE_SLOGD("Function params: name = %s, type = %s, path = %s", name, type, path);
547         int ret = PC_OPERATION_SUCCESS;
548         int were_rules_loaded = 0;
549         char *smack_label AUTO_FREE;
550
551         if (name == NULL) {
552                 C_LOGE("Error invalid parameter");
553                 return PC_ERR_INVALID_PARAM;
554         }
555
556         if (path != NULL && have_smack()) {
557                 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
558                 if (ret != PC_OPERATION_SUCCESS)
559                         return ret;
560
561                 were_rules_loaded = check_if_rules_were_loaded(smack_label);
562                 if (were_rules_loaded < 0) {
563                         C_LOGE("Error while check_if_rules_was_loaded");
564                         return PC_ERR_INVALID_OPERATION;
565                 }
566                 if (!were_rules_loaded) { // first run of application
567                         C_LOGD("This is first run of this application. Adding SMACK rules");
568                         ret = add_app_first_run_rules(smack_label);
569                         if (ret != PC_OPERATION_SUCCESS ) {
570                                 C_LOGW("Warning: add_app_first_run_rules failed");
571                                 // should we return here with error code?
572                         }
573                         mark_rules_as_loaded(smack_label);
574                 }
575
576                 ret = set_smack_for_self(smack_label);
577                 if (ret != PC_OPERATION_SUCCESS)
578                         return ret;
579         }
580
581         if (path != NULL && !have_smack()) {
582                 ret = get_smack_from_binary(&smack_label, path, verify_app_type(type, path));
583                 if (ret != PC_OPERATION_SUCCESS)
584                         return ret;
585         }
586
587         return set_dac(smack_label, name);
588 }
589
590 API int set_privilege(const char* pkg_name)//deprecated
591 {
592         C_LOGD("Enter function: %s", __func__);
593         return perm_app_set_privilege(pkg_name, NULL, NULL);
594 }
595
596 static inline const char* app_type_name(app_type_t app_type)
597 {
598         switch (app_type) {
599         case APP_TYPE_WGT:
600                 return "WRT";
601         case APP_TYPE_OSP:
602                 return "OSP";
603         case APP_TYPE_WGT_PARTNER:
604                 return "WRT_partner";
605         case APP_TYPE_WGT_PLATFORM:
606                 return "WRT_platform";
607         case APP_TYPE_OSP_PARTNER:
608                 return "OSP_partner";
609         case APP_TYPE_OSP_PLATFORM:
610                 return "OSP_platform";
611         case APP_TYPE_EFL:
612                 return "EFL";
613         default:
614                 return NULL;
615         }
616 }
617
618 static inline const char* app_type_group_name(app_type_t app_type)
619 {
620         switch (app_type) {
621         case APP_TYPE_WGT:
622         case APP_TYPE_WGT_PARTNER:
623         case APP_TYPE_WGT_PLATFORM:
624                 return "WRT";
625         case APP_TYPE_OSP:
626         case APP_TYPE_OSP_PARTNER:
627         case APP_TYPE_OSP_PLATFORM:
628                 return "OSP";
629         case APP_TYPE_EFL:
630                 return "EFL";
631         default:
632                 return NULL;
633         }
634 }
635
636 /**
637  * This function changes permission URI to basename for file name.
638  * For e.g. from http://tizen.org/privilege/contact.read will be
639  * created basename : org.tizen.privilege.contact.read
640  */
641
642 static int base_name_from_perm(const char *perm, char **name) {
643         iri_t *ip = NULL;
644         char *host_dot = NULL;
645         char *rest_slash = NULL;
646         int ret;
647
648         ip = iri_parse(perm);
649         if (ip == NULL || ip->host == NULL) {
650                 C_LOGE("Bad permission format : %s", perm);
651                 iri_destroy(ip);
652                 return PC_ERR_INVALID_PARAM;
653         }
654
655         if (ip->path == NULL) {
656                 ip->path = ip->host;
657                 ip->host = NULL;
658         }
659
660         if (ip->host) {
661                 host_dot = strrchr(ip->host, '.');
662                 if (host_dot) {
663                         *host_dot = '\0';
664                         ++host_dot;
665                 }
666         }
667
668         while ((rest_slash = strchr(ip->path, '/'))) {
669                 *rest_slash = '.';
670         }
671
672         ret = asprintf(name, "%s%s%s%s",
673                         host_dot ? host_dot : "", host_dot ? "." : "",
674                         ip->host ? ip->host : "", ip->path);
675         if (ret == -1) {
676                 C_LOGE("asprintf failed");
677                 iri_destroy(ip);
678                 return PC_ERR_MEM_OPERATION;
679         }
680
681         iri_destroy(ip);
682         return PC_OPERATION_SUCCESS;
683 }
684
685 static int perm_file_path(char** path, app_type_t app_type, const char* perm, const char *suffix, bool is_early)
686 {
687         const char* app_type_prefix = NULL;
688         char* perm_basename = NULL;
689         int ret = 0;
690
691         if (perm == NULL || strlen(perm) == 0) {
692                 C_LOGE("empty permission name");
693                 return PC_ERR_INVALID_PARAM;
694         }
695
696         app_type_prefix = app_type_group_name(app_type);
697
698         ret = base_name_from_perm(perm, &perm_basename);
699         if (ret != PC_OPERATION_SUCCESS) {
700                 C_LOGE("Couldn't get permission basename");
701                 return ret;
702         }
703
704         if (is_early) {
705                 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s%s",
706                 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
707                 perm_basename, "_early", suffix);
708         }
709         else {
710                 ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s",
711                 app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
712                 perm_basename, suffix);
713         }
714         if (ret == -1) {
715                 C_LOGE("asprintf failed");
716                 return PC_ERR_MEM_OPERATION;
717         }
718
719         C_LOGD("Path : %s", *path);
720
721         return PC_OPERATION_SUCCESS;
722 }
723
724 static int perm_to_smack_from_file(struct smack_accesses* smack,
725                                            const char* app_label,
726                                            const char* app_label_template,
727                                            const char* rules_file_path)
728 {
729         C_LOGD("Enter function: %s", __func__);
730
731         char smack_subject[SMACK_LABEL_LEN + 1];
732         char smack_object[SMACK_LABEL_LEN + 1];
733         char smack_accesses[ACC_LEN + 1];
734         FILE* file AUTO_FCLOSE;
735
736         file = fopen(rules_file_path, "r");
737         C_LOGD("path = %s", rules_file_path);
738         if (file == NULL) {
739                 C_LOGW("fopen failed [%s] %s", rules_file_path, strerror(errno));
740                 return PC_OPERATION_SUCCESS;
741         }
742
743         while (fscanf(file,
744                         "%" TOSTRING(SMACK_LABEL_LEN) "s "
745                         "%" TOSTRING(SMACK_LABEL_LEN) "s "
746                         "%" TOSTRING(ACC_LEN) "s\n",
747                         smack_subject, smack_object, smack_accesses) == 3) {
748                 if (!strcmp(smack_subject, app_label_template))
749                         strcpy(smack_subject, app_label);
750
751                 if (!strcmp(smack_object, app_label_template))
752                         strcpy(smack_object, app_label);
753
754                 C_LOGD("smack_accesses_add_modify (subject: %s, object: %s, access: %s)", smack_subject, smack_object, smack_accesses);
755                 if (smack_accesses_add_modify(smack, smack_subject, smack_object, smack_accesses, "") != 0) {
756                         C_LOGE("smack_accesses_add_modify failed");
757                         return PC_ERR_INVALID_OPERATION;
758                 }
759         }
760
761         return PC_OPERATION_SUCCESS;
762 }
763
764 static int perm_to_smack_generic(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm, bool is_early)
765 {
766         C_LOGD("Enter function: %s", __func__);
767
768         int ret;
769         char* path AUTO_FREE;
770
771         // get file name for permission (devcap)
772         ret = perm_file_path(&path, app_type, perm, ".smack", is_early);
773         if (ret != PC_OPERATION_SUCCESS) {
774                 C_LOGD("No smack config file for permission %s", perm);
775                 return ret;
776         }
777
778         ret = perm_to_smack_from_file(smack, app_label, SMACK_APP_LABEL_TEMPLATE, path);
779         if (ret != PC_OPERATION_SUCCESS) {
780                 return ret;
781         }
782
783         return PC_OPERATION_SUCCESS;
784 }
785
786 static int perm_to_smack_early(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
787 {
788         C_LOGD("Enter function: %s", __func__);
789
790         return perm_to_smack_generic(smack, app_label, app_type, perm, 1);
791 }
792
793 static int perm_to_smack(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
794 {
795         C_LOGD("Enter function: %s", __func__);
796
797         return perm_to_smack_generic(smack, app_label, app_type, perm, 0);
798 }
799
800 static int perm_to_dac(const char* app_label, app_type_t app_type, const char* perm)
801 {
802         C_LOGD("Enter function: %s", __func__);
803         int ret;
804         char* path AUTO_FREE;
805         FILE* file AUTO_FCLOSE;
806         int gid;
807
808         ret = perm_file_path(&path, app_type, perm, ".dac", 0);
809         if (ret != PC_OPERATION_SUCCESS) {
810                 C_LOGD("No dac config file for permission %s", perm);
811                 return ret;
812         }
813
814         file = fopen(path, "r");
815         C_LOGD("path = %s", path);
816         if (file == NULL) {
817                 C_LOGW("fopen failed");
818                 return PC_OPERATION_SUCCESS;
819         }
820
821         while (fscanf(file, "%d\n", &gid) == 1) {
822                 SECURE_SLOGD("Adding app_id %s to group %d", app_label, gid);
823                 ret = add_app_gid(app_label, gid);
824                 if (ret != PC_OPERATION_SUCCESS) {
825                         C_LOGE("sadd_app_gid failed");
826                         return ret;
827                 }
828         }
829
830         return PC_OPERATION_SUCCESS;
831 }
832
833 static int label_all(const FTSENT* ftsent)
834 {
835         return DECISION_LABEL;
836 }
837
838 static int label_execs(const FTSENT* ftsent)
839 {
840         C_LOGD("Mode: %d", ftsent->fts_statp->st_mode);
841         // label only regular executable files
842         if (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR))
843                 return DECISION_LABEL;
844         return DECISION_SKIP;
845 }
846
847 static int label_dirs(const FTSENT* ftsent)
848 {
849         // label only directories
850         if (S_ISDIR(ftsent->fts_statp->st_mode))
851                 return DECISION_LABEL;
852         return DECISION_SKIP;
853 }
854
855 static int label_links_to_execs(const FTSENT* ftsent)
856 {
857         struct stat buf;
858         char* target AUTO_FREE;
859
860         // check if it's a link
861         if ( !S_ISLNK(ftsent->fts_statp->st_mode))
862                 return DECISION_SKIP;
863
864         target = realpath(ftsent->fts_path, NULL);
865         if (!target) {
866                 C_LOGE("Getting link target for %s failed. Error %s", ftsent->fts_path, strerror(errno));
867                 return PC_ERR_FILE_OPERATION;
868         }
869         if (-1 == stat(target, &buf)) {
870                 C_LOGE("stat failed for %s, error: %s",target, strerror(errno));
871                 return PC_ERR_FILE_OPERATION;
872         }
873         // skip if link target is not a regular executable file
874         if (buf.st_mode != (buf.st_mode | S_IXUSR | S_IFREG)) {
875                 C_LOGD("%s is not a regular executable file. Skipping.", target);
876                 return DECISION_SKIP;
877         }
878
879         return DECISION_LABEL;
880 }
881
882 static int dir_set_smack_r(const char *path, const char* label,
883                 enum smack_label_type type, label_decision_fn fn)
884 {
885         C_LOGD("Enter function: %s", __func__);
886         const char* path_argv[] = {path, NULL};
887         FTS *fts AUTO_FTS_CLOSE;
888         FTSENT *ftsent;
889         int ret;
890
891         fts = fts_open((char * const *) path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
892         if (fts == NULL) {
893                 C_LOGE("fts_open failed");
894                 return PC_ERR_FILE_OPERATION;
895         }
896
897         while ((ftsent = fts_read(fts)) != NULL) {
898                 /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
899                 if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
900                         C_LOGE("FTS_ERR error or failed stat(2) (FTS_NS)");
901                         return PC_ERR_FILE_OPERATION;
902                 }
903
904                 ret = fn(ftsent);
905                 if (ret < 0) {
906                         return ret;
907                 }
908
909                 if (ret == DECISION_LABEL) {
910                         C_LOGD("smack_lsetlabel (label: %s (type: %d), path: %s)", label, type, ftsent->fts_path);
911                         if (smack_lsetlabel(ftsent->fts_path, label, type) != 0) {
912                                 C_LOGE("smack_lsetlabel failed");
913                                 return PC_ERR_FILE_OPERATION;
914                         }
915                 }
916         }
917
918         /* If last call to fts_read() set errno, we need to return error. */
919         if (errno != 0) {
920                 C_LOGE("Last errno: %s", strerror(errno));
921                 return PC_ERR_FILE_OPERATION;
922         }
923         return PC_OPERATION_SUCCESS;
924 }
925
926 API char* app_id_from_socket(int sockfd)//deprecated
927 {
928     return perm_app_id_from_socket(sockfd);
929 }
930
931 API char* perm_app_id_from_socket(int sockfd)
932 {
933         C_LOGD("Enter function: %s", __func__);
934         if (!have_smack())
935                 return NULL;
936
937         char* app_id;
938         int ret;
939
940         ret = smack_new_label_from_socket(sockfd, &app_id);
941         if (ret < 0) {
942                 C_LOGE("smack_new_label_from_socket failed");
943                 return NULL;
944         }
945
946         SECURE_SLOGD("app_id: %s", app_id);
947
948         return app_id;
949 }
950
951 static int app_add_rule(const char *app_id, const char *object, const char *perm)
952 {
953         C_LOGD("Enter function: %s", __func__);
954         int ret;
955         int fd AUTO_CLOSE;
956         char *smack_path AUTO_FREE;
957         struct smack_accesses* smack AUTO_SMACK_FREE;
958
959         ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
960         if (ret != PC_OPERATION_SUCCESS) {
961                 C_LOGE("load_smack_from_file failed");
962                 return ret;
963         }
964
965         ret = smack_accesses_add_modify(smack, app_id, object, perm, "");
966         if (ret == -1) {
967                 C_LOGE("smack_accesses_add_modify failed");
968                 return PC_ERR_INVALID_OPERATION;
969         }
970
971         if (have_smack() && smack_accesses_apply(smack)) {
972                 C_LOGE("smack_accesses_apply failed");
973                 return PC_ERR_INVALID_OPERATION;
974         }
975
976         if (smack_accesses_save(smack, fd)) {
977                 C_LOGE("smack_accesses_save failed");
978                 return PC_ERR_INVALID_OPERATION;
979         }
980
981         return PC_OPERATION_SUCCESS;
982 }
983
984
985 static int
986 app_register_appsetting(const char *app_id, struct smack_accesses *smack)
987 {
988         C_LOGD("Enter function: %s", __func__);
989         int ret;
990         int i;
991
992         char **label_app_list AUTO_FREE;
993         char **label_dir_list AUTO_FREE;
994         int app_list_len = 0;
995         int dir_list_len = 0;
996
997         if (!smack_label_is_valid(app_id))
998                 return PC_ERR_INVALID_PARAM;
999
1000
1001         /* writing appsetting_id (app_id) to "database"*/
1002         ret = add_appsetting_id_to_databse(app_id);
1003         if (ret != PC_OPERATION_SUCCESS)
1004                 goto out;
1005
1006
1007         /* Reading labels of all installed apps from "database"*/
1008         ret = get_all_apps_ids(&label_app_list, &app_list_len);
1009         if (ret != PC_OPERATION_SUCCESS) {
1010                 C_LOGE("Error while getting data from database");
1011                 goto out;
1012         }
1013
1014         /*Add smack rules with rx access to each app*/
1015         for (i = 0; i < app_list_len; ++i) {
1016                 C_LOGD("Appsetting: applying rx rule for %s", label_app_list[i]);
1017                 if (smack_accesses_add_modify(smack, app_id,
1018                                 label_app_list[i], "rx", "") == -1) {
1019                         C_LOGE("smack_accesses_add_modify failed");
1020                         ret = PC_ERR_INVALID_OPERATION;
1021                         goto out;
1022                 }
1023         }
1024
1025         /* Reading labels of all registered settings dirs from "database"*/
1026         ret = get_all_settings_dir_ids(
1027                         &label_dir_list, &dir_list_len);
1028         if (ret != PC_OPERATION_SUCCESS) {
1029                 C_LOGE("Error while getting data from database");
1030                 goto out;
1031         }
1032         /*Add smack rules with rwx access to each app*/
1033         for (i = 0; i < dir_list_len; ++i) {
1034                 C_LOGD("Appsetting: applying rwx rule for %s", label_dir_list[i]);
1035                 if (smack_accesses_add_modify(smack, app_id,
1036                                 label_dir_list[i], "rwx", "") == -1) {
1037                         C_LOGE("smack_accesses_add_modify failed");
1038                         ret = PC_ERR_INVALID_OPERATION;
1039                         goto out;
1040                         /* Should we abort adding rules if
1041                          * smack_accesses_add_modify fails once?*/
1042                 }
1043         }
1044
1045         out:
1046         for (i = 0; i < app_list_len; ++i) {
1047                 free(label_app_list[i]);
1048         }
1049         for (i = 0; i < dir_list_len; ++i) {
1050                 free(label_dir_list[i]);
1051         }
1052
1053         return ret;
1054 }
1055
1056 static int app_register_av_internal(const char *app_av_id, struct smack_accesses* smack)
1057 {
1058         C_LOGD("Enter function: %s", __func__);
1059         int ret;
1060         int i;
1061
1062         char** smack_label_app_list AUTO_FREE;
1063         int smack_label_app_list_len = 0;
1064
1065         if (!smack_label_is_valid(app_av_id) || NULL == smack)
1066                 return PC_ERR_INVALID_PARAM;
1067
1068         // writing anti_virus_id (app_av_id) to "database"
1069         ret = add_av_id_to_databse(app_av_id);
1070         if (ret != PC_OPERATION_SUCCESS )
1071                 goto out;
1072
1073         // Reading labels of all installed apps from "database"
1074         ret = get_all_apps_ids(&smack_label_app_list, &smack_label_app_list_len);
1075         if (ret != PC_OPERATION_SUCCESS ) {
1076                 C_LOGE("Error while geting data from database");
1077                 goto out;
1078         }
1079         for (i = 0; i < smack_label_app_list_len; ++i) {
1080                 C_LOGD("Applying rwx rule for %s", smack_label_app_list[i]);
1081                 if (smack_accesses_add_modify(smack, app_av_id, smack_label_app_list[i], "wrx", "") == -1) {
1082                         C_LOGE("smack_accesses_add_modify failed");
1083                         ret = PC_ERR_INVALID_OPERATION;
1084                         goto out;
1085                         // Should we abort adding rules once smack_accesses_add_modify will fail?
1086                 }
1087         }
1088
1089 out:
1090         for (i = 0; i < smack_label_app_list_len; ++i) {
1091                 free(smack_label_app_list[i]);
1092         }
1093
1094         return ret;
1095 }
1096
1097 /**
1098  *  This function will find labels of all anti viruses in database
1099  *  and for all of them will add a rule "anti_virus_label app_id rwx".
1100  *  This should be called in app_install function.
1101  */
1102 static int register_app_for_av(const char * app_id)
1103 {
1104         int ret, i;
1105         char** smack_label_av_list AUTO_FREE;
1106         int smack_label_av_list_len = 0;
1107
1108         // Reading labels of all installed anti viruses from "database"
1109         ret = get_all_avs_ids(&smack_label_av_list, &smack_label_av_list_len);
1110         if (ret != PC_OPERATION_SUCCESS) {
1111                 C_LOGE("Error while geting data from database");
1112                 return ret;
1113         }
1114
1115         // for each anti-virus label put rule: "anti_virus_label app_id rwx"
1116         for (i = 0; i < smack_label_av_list_len; ++i) {
1117                 SECURE_SLOGD("Antivirus: app_add_rule (%s, %s rx)", smack_label_av_list[i], app_id);
1118                 if (strcmp(app_id, smack_label_av_list[i])==0) {
1119                         SECURE_SLOGW("Trying to add antivirus rule for self. Skipping");
1120                         continue;
1121                 }
1122                 ret = app_add_rule(smack_label_av_list[i], app_id, "wrx");
1123                 if (ret != PC_OPERATION_SUCCESS) {
1124                         C_LOGE("app_add_rule failed");
1125                         goto out;
1126                 }
1127
1128                 free(smack_label_av_list[i]);
1129         }
1130
1131         ret = PC_OPERATION_SUCCESS;
1132
1133 out:
1134         // If something failed, then no entry of smack_label_av_list[i]
1135         // was deallocated. They all must be freed.
1136         for(; i<smack_label_av_list_len; ++i) {
1137                 free(smack_label_av_list[i]);
1138         }
1139
1140         return ret;
1141 }
1142
1143 /**
1144  *  This function will find labels of all setting applications in database
1145  *  and for all of them will add a rule "appsetting_id app_id rwx".
1146  *  This should be called in app_install function.
1147  */
1148 static int register_app_for_appsetting(const char *app_id)
1149 {
1150         C_LOGD("Enter function: %s",__func__);
1151         int ret, i;
1152         char **smack_label_list AUTO_FREE;
1153         int smack_label_list_len = 0;
1154
1155         /* Reading labels of all installed setting managers from "database"*/
1156         ret = get_all_appsetting_ids(&smack_label_list, &smack_label_list_len);
1157         if (ret != PC_OPERATION_SUCCESS) {
1158                 C_LOGE("Error while geting data from database");
1159                 return ret;
1160         }
1161
1162         /* for each appsetting put rule: "appsetting_id app_id rx"*/
1163         for (i = 0; i < smack_label_list_len; ++i) {
1164
1165                 SECURE_SLOGD("Appsetting: app_add_rule (%s, %s rx)", smack_label_list[i], app_id);
1166                 if (strcmp(app_id, smack_label_list[i])==0) {
1167                         SECURE_SLOGW("Trying to add setting rule for self. Skipping");
1168                         continue;
1169                 }
1170                 ret = app_add_rule(smack_label_list[i], app_id, "rx");
1171                 if (ret != PC_OPERATION_SUCCESS) {
1172                         C_LOGE("app_add_rule failed");
1173                         goto out;
1174                 }
1175
1176                 free(smack_label_list[i]);
1177         }
1178
1179         ret = PC_OPERATION_SUCCESS;
1180
1181 out:
1182         /* If something failed, then no entry of smack_label_list[i]
1183          was deallocated. They all must be freed.*/
1184         for (; i < smack_label_list_len; ++i) {
1185                 free(smack_label_list[i]);
1186         }
1187
1188         return ret;
1189 }
1190
1191
1192 /**
1193  *  This function will grant app_id rx access to all public directories and
1194  *  files previously designated by app_setup_path(APP_PATH_PUBLIC_RO)
1195  *  This should be called in app_install function.
1196  */
1197 static int register_app_for_public_dirs(const char *app_id, struct smack_accesses *smack)
1198 {
1199         C_LOGD("Enter function: %s", __func__);
1200         int ret, i;
1201         char **public_dirs AUTO_FREE;
1202         int public_dirs_cnt = 0;
1203
1204         ret = db_get_public_dirs(&public_dirs, &public_dirs_cnt);
1205         if (ret != PC_OPERATION_SUCCESS) {
1206                 C_LOGE("Error while getting data from database");
1207                 return ret;
1208         }
1209
1210         for (i = 0; i < public_dirs_cnt; ++i) {
1211                 SECURE_SLOGD("Allowing app %s to access public path %s", app_id, public_dirs[i]);
1212                 if (smack_accesses_add_modify(smack, app_id, public_dirs[i], "rx", "")) {
1213                         C_LOGE("app_add_rule_modify failed");
1214                         while (i < public_dirs_cnt)
1215                                 free(public_dirs[i++]);
1216                         return PC_ERR_INVALID_OPERATION;
1217                 }
1218                 free(public_dirs[i]);
1219         }
1220
1221         return PC_OPERATION_SUCCESS;
1222 }
1223
1224 static int app_add_permissions_internal(const char* app_id, app_type_t app_type, const char** perm_list, int permanent)
1225 {
1226         C_LOGD("Enter function: %s", __func__);
1227         int i, ret;
1228         char* smack_path AUTO_FREE;
1229         char* smack_path_early AUTO_FREE;
1230         int fd AUTO_CLOSE;
1231         int fd_early AUTO_CLOSE;
1232         struct smack_accesses *smack AUTO_SMACK_FREE;
1233         struct smack_accesses *smack_early AUTO_SMACK_FREE;
1234         const char* base_perm = NULL;
1235
1236         if (!smack_label_is_valid(app_id))
1237                 return PC_ERR_INVALID_PARAM;
1238
1239         if(perm_list == NULL) {
1240                 C_LOGE("Invalid perm_list (NULL).");
1241                 return PC_ERR_INVALID_PARAM;
1242         }
1243
1244         ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1245         if (ret != PC_OPERATION_SUCCESS) {
1246                 C_LOGE("load_smack_from_file failed");
1247                 return ret;
1248         }
1249
1250         ret = load_smack_from_file_early(app_id, &smack_early, &fd_early, &smack_path_early);
1251         if (ret != PC_OPERATION_SUCCESS) {
1252                 C_LOGE("load_smack_from_file failed");
1253                 return ret;
1254         }
1255
1256         /* Implicitly enable base permission for an app_type */
1257         base_perm = app_type_name(app_type);
1258         if (base_perm) {
1259                 SECURE_SLOGD("perm_to_smack params: app_id: %s, %s", app_id, base_perm);
1260                 ret = perm_to_smack(smack, app_id, APP_TYPE_OTHER, base_perm);
1261                 if (ret != PC_OPERATION_SUCCESS){
1262                         C_LOGE("perm_to_smack failed");
1263                         return ret;
1264                 }
1265
1266                 // Add early permission - such permissions should be enabled right after system boot
1267                 SECURE_SLOGD("perm_to_smack params: app_id: %s, %s", app_id, base_perm);
1268                 ret = perm_to_smack_early(smack_early, app_id, APP_TYPE_OTHER, base_perm);
1269                 if (ret != PC_OPERATION_SUCCESS){
1270                         C_LOGE("perm_to_smack failed");
1271                         return ret;
1272                 }
1273
1274         }
1275         for (i = 0; perm_list[i] != NULL; ++i) {
1276                 SECURE_SLOGD("perm_to_smack params: app_id: %s, perm_list[%d]: %s", app_id, i, perm_list[i]);
1277                 if (strcmp(perm_list[i], TIZEN_PRIVILEGE_ANTIVIRUS) == 0) {
1278                         ret = app_register_av_internal(app_id, smack);
1279                         if (ret != PC_OPERATION_SUCCESS) {
1280                                 C_LOGE("app_register_av_internal failed");
1281                                 return ret;
1282                         }
1283                 }
1284                 if (strcmp(perm_list[i], TIZEN_PRIVILEGE_APPSETTING) == 0) {
1285                         ret = app_register_appsetting(app_id, smack);
1286                         if (ret != PC_OPERATION_SUCCESS) {
1287                                 C_LOGE("app_register_appsetting failed");
1288                                 return ret;
1289                         }
1290                 }
1291
1292                 ret = perm_to_smack(smack, app_id, app_type, perm_list[i]);
1293                 if (ret != PC_OPERATION_SUCCESS){
1294                         C_LOGE("perm_to_smack failed");
1295                         return ret;
1296                 }
1297
1298                 ret = perm_to_smack_early(smack_early, app_id, app_type, perm_list[i]);
1299                 if (ret != PC_OPERATION_SUCCESS){
1300                         C_LOGE("perm_to_smack_early failed");
1301                         return ret;
1302                 }
1303
1304                 ret = perm_to_dac(app_id, app_type, perm_list[i]);
1305                 if (ret != PC_OPERATION_SUCCESS){
1306                         C_LOGE("perm_to_dac failed");
1307                         return ret;
1308                 }
1309         }
1310
1311         if (have_smack() && smack_accesses_apply(smack)) {
1312                 C_LOGE("smack_accesses_apply failed");
1313                 return PC_ERR_INVALID_OPERATION;
1314         }
1315
1316         if (have_smack() && smack_accesses_apply(smack_early)) {
1317                 C_LOGE("smack_accesses_apply (early) failed");
1318                 return PC_ERR_INVALID_OPERATION;
1319         }
1320
1321         if (permanent && smack_accesses_save(smack, fd)) {
1322                 C_LOGE("smack_accesses_save failed");
1323                 return PC_ERR_INVALID_OPERATION;
1324         }
1325
1326         if (permanent && smack_accesses_save(smack_early, fd_early)) {
1327                 C_LOGE("smack_accesses_save (early) failed");
1328                 return PC_ERR_INVALID_OPERATION;
1329         }
1330
1331         return PC_OPERATION_SUCCESS;
1332 }
1333
1334 API int app_add_permissions(const char* app_id, const char** perm_list)//deprecated
1335 {
1336         C_LOGD("Enter function: %s", __func__);
1337         return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 1);
1338 }
1339
1340 API int app_add_volatile_permissions(const char* app_id, const char** perm_list)//deprecated
1341 {
1342         C_LOGD("Enter function: %s", __func__);
1343         return app_add_permissions_internal(app_id, APP_TYPE_OTHER, perm_list, 0);
1344 }
1345
1346 API int app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)//deprecated
1347 {
1348         C_LOGD("Enter function: %s", __func__);
1349         return app_add_permissions_internal(pkg_id, app_type, perm_list, persistent);
1350 }
1351
1352 API int perm_app_enable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list, bool persistent)
1353 {
1354     C_LOGD("Enter function: %s", __func__);
1355     return app_add_permissions_internal(pkg_id, app_type, perm_list, persistent);
1356 }
1357
1358 API int app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)//deprecated
1359 {
1360     return perm_app_disable_permissions(pkg_id, app_type, perm_list);
1361 }
1362
1363 /* FIXME: this function is only a stub */
1364 API int perm_app_disable_permissions(const char* pkg_id, app_type_t app_type, const char** perm_list)
1365 {
1366         C_LOGD("Enter function: %s", __func__);
1367         return PC_OPERATION_SUCCESS;
1368 }
1369
1370 static int app_revoke_permissions_internal(const char* app_id, bool persistent)
1371 {
1372         C_LOGD("Enter function: %s", __func__);
1373         char* smack_path AUTO_FREE;
1374         int ret;
1375         int fd AUTO_CLOSE;
1376         struct smack_accesses *smack AUTO_SMACK_FREE;
1377
1378         if (!smack_label_is_valid(app_id))
1379                 return PC_ERR_INVALID_PARAM;
1380
1381         ret = load_smack_from_file(app_id, &smack, &fd, &smack_path);
1382         if (ret != PC_OPERATION_SUCCESS) {
1383                 C_LOGE("load_smack_from_file failed");
1384                 return ret;
1385         }
1386
1387         if (have_smack() && smack_accesses_clear(smack)) {
1388                 ret = PC_ERR_INVALID_OPERATION;
1389                 C_LOGE("smack_accesses_clear failed");
1390                 return ret;
1391         }
1392
1393         if (have_smack() && smack_revoke_subject(app_id)) {
1394                 ret = PC_ERR_INVALID_OPERATION;
1395                 C_LOGE("smack_revoke_subject failed");
1396                 return ret;
1397         }
1398
1399         if (persistent && ftruncate(fd, 0) == -1)
1400                 C_LOGW("file truncation failed");
1401
1402         return PC_OPERATION_SUCCESS;
1403 }
1404
1405 API int app_revoke_permissions(const char* pkg_id)//deprecated
1406 {
1407     return perm_app_revoke_permissions(pkg_id);
1408 }
1409
1410 API int perm_app_revoke_permissions(const char* pkg_id)
1411 {
1412     C_LOGD("Enter function: %s", __func__);
1413     int ret;
1414
1415     if (!smack_label_is_valid(pkg_id))
1416         return PC_ERR_INVALID_PARAM;
1417
1418     ret = app_revoke_permissions_internal(pkg_id, true);
1419     if (ret) {
1420         C_LOGE("Revoking permissions failed");
1421         return ret;
1422     }
1423
1424     return PC_OPERATION_SUCCESS;
1425 }
1426
1427 API int app_reset_permissions(const char* pkg_id)//deprecated
1428 {
1429     return perm_app_reset_permissions(pkg_id);
1430 }
1431
1432 API int perm_app_reset_permissions(const char* pkg_id)
1433 {
1434         C_LOGD("Enter function: %s", __func__);
1435         int ret;
1436
1437         if (!smack_label_is_valid(pkg_id))
1438                 return PC_ERR_INVALID_PARAM;
1439
1440         ret = app_revoke_permissions_internal(pkg_id, false);
1441         if (ret) {
1442                 C_LOGE("Revoking permissions failed");
1443                 return ret;
1444         }
1445
1446         /* Add empty permissions set to trigger re-read of rules */
1447         return perm_app_enable_permissions(pkg_id, APP_TYPE_OTHER, (const char*[]){NULL}, 0);
1448 }
1449
1450 API int app_label_dir(const char* label, const char* path)//deprecated
1451 {
1452         C_LOGD("Enter function: %s", __func__);
1453
1454         int ret = PC_OPERATION_SUCCESS;
1455
1456         if(path == NULL) {
1457                 C_LOGE("Invalid argument path (NULL).");
1458                 return PC_ERR_INVALID_PARAM;
1459         }
1460
1461         if (!smack_label_is_valid(label))
1462                 return PC_ERR_INVALID_PARAM;
1463
1464         //setting access label on everything in given directory and below
1465         ret = dir_set_smack_r(path, label, SMACK_LABEL_ACCESS, &label_all);
1466         if (PC_OPERATION_SUCCESS != ret)
1467                 return ret;
1468
1469         //setting execute label for everything with permission to execute
1470         ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_execs);
1471         if (PC_OPERATION_SUCCESS != ret)
1472                 return ret;
1473
1474         //setting execute label for everything with permission to execute
1475         ret = dir_set_smack_r(path, label, SMACK_LABEL_EXEC, &label_links_to_execs);
1476         return ret;
1477 }
1478
1479 int smack_get_access_new(const char* subject, const char* object, char** label)
1480 {
1481         char buff[ACC_LEN] = {'r', 'w', 'x', 'a', 't'};
1482         char perm[2] = {'-'};
1483         int i;
1484
1485         if(!smack_label_is_valid(subject) || !smack_label_is_valid(object) || !label)
1486                 return PC_ERR_INVALID_PARAM;
1487
1488         for (i=0; i<ACC_LEN; ++i) {
1489                 perm[0] = buff[i];
1490                 int ret = smack_have_access(subject, object, perm);
1491                 if (-1 == ret)
1492                         return PC_ERR_INVALID_OPERATION;
1493                 if (0 == ret)
1494                         buff[i] = '-';
1495         }
1496
1497         *label = malloc(ACC_LEN+1);
1498         if (NULL == *label)
1499                 return PC_ERR_MEM_OPERATION;
1500
1501         memcpy(*label, buff, ACC_LEN);
1502         (*label)[ACC_LEN] = 0;
1503         return PC_OPERATION_SUCCESS;
1504 }
1505
1506 static int app_uninstall_remove_early_rules(const char *app_id)
1507 {
1508         C_LOGD("Enter function: %s(%s)", __func__, app_id);
1509
1510         int ret;
1511         int fd AUTO_CLOSE;
1512         int size;
1513         char tmp;
1514         char *data, *data_end;
1515         char *line_begin, *line_end, *write_pos;
1516         char subject[SMACK_LABEL_LEN + 1];
1517         char object[SMACK_LABEL_LEN + 1];
1518
1519         fd = open(SMACK_STARTUP_RULES_FILE, O_RDWR);
1520         if (fd < 0) {
1521                 C_LOGE("Unable to open file %s: %s", SMACK_STARTUP_RULES_FILE, strerror(errno));
1522                 return PC_ERR_FILE_OPERATION;
1523         }
1524
1525         if (flock(fd, LOCK_EX)) {
1526                 C_LOGE("flock failed, error %s", strerror(errno));
1527                 return PC_ERR_FILE_OPERATION;
1528         }
1529
1530         size = lseek(fd, 0, SEEK_END);
1531         if (size < 0) {
1532                 C_LOGE("Unable to read file %s: %s", SMACK_STARTUP_RULES_FILE, strerror(errno));
1533                 return PC_ERR_FILE_OPERATION;
1534         }
1535
1536         if (size == 0)
1537                 return PC_OPERATION_SUCCESS;
1538
1539         data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1540         if (data == MAP_FAILED) {
1541                 C_LOGE("Unable to read file %s: %s", SMACK_STARTUP_RULES_FILE, strerror(errno));
1542                 return PC_ERR_FILE_OPERATION;
1543         }
1544         data_end = data + size;
1545
1546         line_begin = write_pos = data;
1547         while (line_begin < data_end) {
1548                 line_end = memchr(line_begin, '\n', data_end - line_begin);
1549                 if (line_end == NULL)
1550                         line_end = data_end - 1;
1551
1552                 tmp = *line_end;
1553                 *line_end = '\0';
1554                 C_LOGD("Considering early rule: %s", line_begin);
1555
1556                 ret = sscanf(line_begin, "%" TOSTRING(SMACK_LABEL_LEN) "s %" TOSTRING(SMACK_LABEL_LEN) "s", subject, object);
1557                 if (ret != 2) {
1558                         C_LOGD("Rule format is invalid, skipping it.");
1559                         goto loop_next;
1560                 }
1561
1562                 if (!strcmp(subject, app_id) || !strcmp(object, app_id)) {
1563                         C_LOGD("Rule belongs to an app being removed, skipping it.");
1564                         goto loop_next;
1565                 }
1566
1567                 C_LOGD("Rule still needed, keeping it.");
1568                 *line_end = tmp;
1569                 if (write_pos != line_begin)
1570                         memcpy(write_pos, line_begin, line_end - line_begin + 1);
1571                 write_pos += (line_end - line_begin + 1);
1572
1573         loop_next:
1574                 *line_end = tmp;
1575                 line_begin = line_end + 1;
1576         }
1577
1578         munmap(data, size);
1579         ret = ftruncate(fd, write_pos - data);
1580         if (ret < 0) {
1581                 C_LOGE("Unable to truncate file %s to %d bytes: %s", SMACK_STARTUP_RULES_FILE, write_pos, strerror(errno));
1582
1583                 return PC_ERR_FILE_OPERATION;
1584         }
1585
1586         return PC_OPERATION_SUCCESS;
1587 }
1588
1589 API int app_label_shared_dir(const char* app_label, const char* shared_label, const char* path)//deprecated
1590 {
1591         C_LOGD("Enter function: %s", __func__);
1592         int ret;
1593
1594         if(path == NULL)
1595         {
1596                 C_LOGE("Invalid param path.");
1597                 return PC_ERR_INVALID_PARAM;
1598         }
1599
1600         if (!smack_label_is_valid(app_label) || !smack_label_is_valid(shared_label))
1601                 return PC_ERR_INVALID_PARAM;
1602
1603         if (strcmp(app_label, shared_label) == 0) {
1604                 C_LOGE("app_label equals shared_label");
1605                 return PC_ERR_INVALID_PARAM;
1606         }
1607
1608         //setting label on everything in given directory and below
1609         ret = dir_set_smack_r(path, shared_label, SMACK_LABEL_ACCESS, label_all);
1610         if(ret != PC_OPERATION_SUCCESS){
1611                 C_LOGE("dir_set_smack_r failed");
1612                 return ret;
1613         }
1614
1615         //setting transmute on dir
1616         ret = dir_set_smack_r(path, "1", SMACK_LABEL_TRANSMUTE, label_dirs);
1617         if (ret != PC_OPERATION_SUCCESS) {
1618                 C_LOGE("dir_set_smack_r failed");
1619                 return ret;
1620         }
1621
1622         ret = app_add_rule(app_label, shared_label, "rwxat");
1623         if (ret != PC_OPERATION_SUCCESS) {
1624                 C_LOGE("app_add_rule failed");
1625                 return ret;
1626         }
1627
1628         return PC_OPERATION_SUCCESS;
1629 }
1630
1631 API int add_shared_dir_readers(const char* shared_label, const char** app_list)//deprecated
1632 {
1633         C_LOGD("Enter function: %s", __func__);
1634         int ret;
1635         int i;
1636
1637         if(app_list == NULL) {
1638                 C_LOGE("Invalid param app_list.");
1639                 return PC_ERR_INVALID_PARAM;
1640         }
1641
1642         if (!smack_label_is_valid(shared_label))
1643                                 return PC_ERR_INVALID_PARAM;
1644
1645         for (i = 0; app_list[i] != NULL; i++) {
1646
1647                 if (!smack_label_is_valid(app_list[i]))
1648                                         return PC_ERR_INVALID_PARAM;
1649
1650                 ret = app_add_rule(app_list[i], shared_label, "rx");
1651                 if (ret != PC_OPERATION_SUCCESS) {
1652                         C_LOGE("app_add_rule failed");
1653                         return ret;
1654                 }
1655         }
1656
1657         return PC_OPERATION_SUCCESS;
1658 }
1659
1660 static char* smack_label_for_path(const char *app_id, const char *path)
1661 {
1662         C_LOGD("Enter function: %s", __func__);
1663         char *salt AUTO_FREE;
1664         char *label;
1665         char *x;
1666
1667         /* Prefix $1$ causes crypt() to use MD5 function */
1668         if (-1 == asprintf(&salt, "$1$%s", app_id)) {
1669                 C_LOGE("asprintf failed");
1670                 return NULL;
1671         }
1672
1673         label = crypt(path, salt);
1674         if (label == NULL) {
1675                 C_LOGE("crypt failed");
1676                 return NULL;
1677         }
1678
1679         /* crypt() output may contain slash character,
1680          * which is not legal in Smack labels */
1681         for (x = label; *x; ++x) {
1682                 if (*x == '/')
1683                         *x = '%';
1684         }
1685
1686         return label;
1687 }
1688 /*
1689  * This function should be called in perm_app_setup_path_internal().
1690  * After installation of new application (pkg_id) and labeling its shared directory (RW or RO),
1691  * all others apps installed in system should get rules to this shared directory.
1692  * This function will add and store those rules in rule-file of new installed app (pkg_id)
1693  */
1694 static int add_other_apps_rules_for_shared_dir(const char *pkg_id, const char *type_of_shared_dir, const char *shared_dir_label)
1695 {
1696         C_LOGD("Enter function: %s", __func__);
1697
1698         int ret;
1699         int fd AUTO_CLOSE;
1700         char *smack_path AUTO_FREE;
1701         char *smack_rules_file_path AUTO_FREE;
1702         struct smack_accesses* smack AUTO_SMACK_FREE;
1703
1704         ret = load_smack_from_file(pkg_id, &smack, &fd, &smack_path);
1705         if (ret != PC_OPERATION_SUCCESS ) {
1706                 C_LOGE("load_smack_from_file failed: %d", ret);
1707                 return ret;
1708         }
1709
1710         ret = asprintf(&smack_rules_file_path, TOSTRING(SHAREDIR)"/%s", type_of_shared_dir);
1711         if (ret < 0) {
1712                 C_LOGE("asprintf failed");
1713                 return PC_ERR_MEM_OPERATION;
1714         }
1715
1716         ret = perm_to_smack_from_file(smack, shared_dir_label, SMACK_SHARED_DIR_LABEL_TEMPLATE, smack_rules_file_path);
1717         if (ret != PC_OPERATION_SUCCESS ) {
1718                 C_LOGE("perm_to_smack_from_file failed: %d", ret);
1719         }
1720
1721         if (have_smack() && smack_accesses_apply(smack)) {
1722                 C_LOGE("smack_accesses_apply failed");
1723                 return PC_ERR_INVALID_OPERATION;
1724         }
1725
1726         if (smack_accesses_save(smack, fd)) {
1727                 C_LOGE("smack_accesses_save failed");
1728                 return PC_ERR_INVALID_OPERATION;
1729         }
1730
1731         return PC_OPERATION_SUCCESS;
1732 }
1733
1734 /* FIXME: remove this pragma once deprecated API is deleted */
1735 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1736 static int perm_app_setup_path_internal(const char* pkg_id, const char* path, app_path_type_t app_path_type, va_list ap)
1737 {
1738         C_LOGD("Enter function: %s", __func__);
1739
1740         if(path == NULL) {
1741                 C_LOGE("Invalid argument path.");
1742                 return PC_ERR_INVALID_PARAM;
1743         }
1744
1745         if (!smack_label_is_valid(pkg_id)) {
1746                 SECURE_SLOGE("Invalid app_id %s", pkg_id);
1747                 return PC_ERR_INVALID_PARAM;
1748         }
1749
1750         switch (app_path_type) {
1751         case APP_PATH_PRIVATE:
1752                 return app_label_dir(pkg_id, path);
1753
1754         case APP_PATH_GROUP_RW: {
1755                 const char *shared_label;
1756                 int ret;
1757
1758                 shared_label = va_arg(ap, const char *);
1759
1760                 if (!smack_label_is_valid(shared_label)) {
1761                         C_LOGE("Invalid shared_label %s", shared_label);
1762                         return PC_ERR_INVALID_PARAM;
1763                 }
1764
1765                 if (strcmp(pkg_id, shared_label) == 0) {
1766                         C_LOGE("app_id equals shared_label");
1767                         return PC_ERR_INVALID_PARAM;
1768                 }
1769
1770                 ret = app_label_shared_dir(pkg_id, shared_label, path);
1771                 if (ret != PC_OPERATION_SUCCESS) {
1772                         C_LOGE("app_label_shared_dir failed: %d", ret);
1773                         return ret;
1774                 }
1775
1776                 return add_other_apps_rules_for_shared_dir(pkg_id, PATH_RULES_GROUP_RW, shared_label);
1777         }
1778
1779         case APP_PATH_PUBLIC_RO: {
1780                 char **app_ids AUTO_FREE;
1781                 int app_ids_cnt = 0;
1782                 const char *label;
1783                 int i, ret;
1784
1785                 C_LOGD("New public RO path %s", path);
1786                 label = smack_label_for_path(pkg_id, path);
1787                 if (label == NULL)
1788                         return PC_ERR_INVALID_OPERATION;
1789
1790                 C_LOGD("Generated label '%s' for public RO path %s", label, path);
1791                 ret = app_label_shared_dir(pkg_id, label, path);
1792                 if (ret != PC_OPERATION_SUCCESS)
1793                         return ret;
1794
1795                 /* FIXME: This should be in some kind of transaction/lock */
1796                 ret = db_add_public_dir(label);
1797                 if (ret != PC_OPERATION_SUCCESS)
1798                         return ret;
1799
1800                 ret = get_all_apps_ids(&app_ids, &app_ids_cnt);
1801                 if (ret != PC_OPERATION_SUCCESS)
1802                         return ret;
1803
1804                 for (i = 0; i < app_ids_cnt; ++i) {
1805                         SECURE_SLOGD("Allowing app %s to access public path %s", app_ids[i], path);
1806                         ret = app_add_rule(app_ids[i], label, "rx");
1807                         if (ret != PC_OPERATION_SUCCESS) {
1808                                 C_LOGE("smack_accesses_new failed");
1809                                 while (i < app_ids_cnt)
1810                                         free(app_ids[i++]);
1811                                 return ret;
1812                         }
1813                         free(app_ids[i]);
1814                 }
1815
1816                 return add_other_apps_rules_for_shared_dir(pkg_id, PATH_RULES_PUBLIC_RO, label);
1817         }
1818
1819         case APP_PATH_SETTINGS_RW:
1820         {
1821                 char **app_ids AUTO_FREE;
1822                 int app_ids_cnt = 0;
1823                 const char *label;
1824                 int i;
1825                 int ret;
1826
1827                 /*get path id*/
1828                 label = smack_label_for_path(pkg_id, path);
1829                 if (label == NULL)
1830                         return PC_ERR_INVALID_OPERATION;
1831
1832                 /*set id for path and all subfolders*/
1833                 C_LOGD("Appsetting: generated label '%s' for setting path %s", label, path);
1834                 ret = app_label_shared_dir(pkg_id, label, path);
1835                 if (ret != PC_OPERATION_SUCCESS) {
1836                         C_LOGE("Appsetting: app_label_shared_dir failed (%d)", ret);
1837                         return ret;
1838                 }
1839
1840                 /* add path to database */
1841                 /* FIXME: This should be in some kind of transaction/lock */
1842                 ret = add_setting_dir_id_to_databse(label);
1843                 if (ret != PC_OPERATION_SUCCESS) {
1844                         C_LOGE("Appsetting: add_setting_dir_id_to_databse failed");
1845                         return ret;
1846                 }
1847
1848                 /*read all apps with appsetting privilege*/
1849                 ret = get_all_appsetting_ids(&app_ids, &app_ids_cnt);
1850                 if (ret != PC_OPERATION_SUCCESS) {
1851                         C_LOGE("Appsetting: get_all_appsetting_ids failed");
1852                         return ret;
1853                 }
1854                 C_LOGD("Appsetting: %d appsetting privileged apps registered",
1855                                 app_ids_cnt);
1856
1857                 /*give RWX rights to all apps that have appsetting privilege*/
1858                 for (i = 0; i < app_ids_cnt; ++i) {
1859                         C_LOGD("Appsetting: allowing app %s to access setting path %s",
1860                                         app_ids[i], label);
1861                         ret = app_add_rule(app_ids[i], label, "rwx");
1862                         if (ret != PC_OPERATION_SUCCESS) {
1863                                 C_LOGE("app_add_rule failed");
1864                                 while (i < app_ids_cnt)
1865                                         free(app_ids[i++]);
1866                                 return ret;
1867                         }
1868                         free(app_ids[i]);
1869                 }
1870
1871                 return PC_OPERATION_SUCCESS;
1872         }
1873
1874         case APP_PATH_ANY_LABEL: {
1875                 const char *label = NULL;
1876                 label = va_arg(ap, const char *);
1877                 return app_label_dir(label, path);
1878         }
1879
1880         default:
1881                 return PC_ERR_INVALID_PARAM;
1882         }
1883
1884         return PC_OPERATION_SUCCESS;
1885 }
1886 /* FIXME: remove this pragma once deprecated API is deleted */
1887 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
1888
1889 API int app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)//deprecated
1890 {
1891     va_list ap;
1892     int ret;
1893     va_start( ap, app_path_type );
1894     ret = perm_app_setup_path_internal( pkg_id, path, app_path_type, ap );
1895     va_end( ap );
1896     return ret;
1897 }
1898
1899
1900 API int perm_app_setup_path(const char* pkg_id, const char* path, app_path_type_t app_path_type, ...)
1901 {
1902         va_list ap;
1903         int ret;
1904         va_start( ap, app_path_type );
1905         ret = perm_app_setup_path_internal( pkg_id, path, app_path_type, ap );
1906         va_end( ap );
1907         return ret;
1908 }
1909
1910
1911
1912 API int app_add_friend(const char* pkg_id1, const char* pkg_id2)//deprecated
1913 {
1914     return perm_app_add_friend(pkg_id1, pkg_id2);
1915 }
1916
1917 API int perm_app_add_friend(const char* pkg_id1, const char* pkg_id2)
1918 {
1919         C_LOGD("Enter function: %s", __func__);
1920         int ret;
1921
1922         if (!smack_label_is_valid(pkg_id1) || !smack_label_is_valid(pkg_id2))
1923                 return PC_ERR_INVALID_PARAM;
1924
1925         ret = app_add_rule(pkg_id1, pkg_id2, "rwxat");
1926         if (ret != PC_OPERATION_SUCCESS) {
1927                 C_LOGE("app_add_rule failed");
1928                 return ret;
1929         }
1930
1931         ret = app_add_rule(pkg_id2, pkg_id1, "rwxat");
1932         if (ret != PC_OPERATION_SUCCESS) {
1933                 C_LOGE("app_add_rule failed");
1934                 return ret;
1935         }
1936
1937         return PC_OPERATION_SUCCESS;
1938 }
1939
1940 API int app_install(const char* pkg_id)//deprecated
1941 {
1942     return perm_app_install(pkg_id);
1943 }
1944
1945 API int perm_app_install(const char* pkg_id)
1946 {
1947         C_LOGD("Enter function: %s", __func__);
1948         int ret;
1949         int fd AUTO_CLOSE;
1950         char* smack_path AUTO_FREE;
1951         struct smack_accesses *smack AUTO_SMACK_FREE;
1952
1953         if (!smack_label_is_valid(pkg_id))
1954                 return PC_ERR_INVALID_PARAM;
1955
1956         ret = smack_file_name(pkg_id, &smack_path);
1957         if (ret != PC_OPERATION_SUCCESS)
1958                 return ret;
1959
1960         ret = load_smack_from_file(pkg_id, &smack, &fd, &smack_path);
1961         if (ret != PC_OPERATION_SUCCESS) {
1962                 C_LOGE("load_smack_from_file failed");
1963                 return ret;
1964         }
1965
1966         ret = add_app_id_to_databse(pkg_id);
1967         if (ret != PC_OPERATION_SUCCESS ) {
1968                 SECURE_SLOGE("Error while adding app %s to database: %s ", pkg_id, strerror(errno));
1969                 return ret;
1970         }
1971
1972         ret = register_app_for_av(pkg_id);
1973         if (ret != PC_OPERATION_SUCCESS) {
1974                 SECURE_SLOGE("Error while adding rules for anti viruses to app %s: %s ", pkg_id, strerror(errno));
1975                 return ret;
1976         }
1977
1978         ret = register_app_for_appsetting(pkg_id);
1979         if (ret != PC_OPERATION_SUCCESS) {
1980                 SECURE_SLOGE("Error while adding rules for setting managers to app %s: %s ", pkg_id, strerror(errno));
1981                 return ret;
1982         }
1983
1984         ret = register_app_for_public_dirs(pkg_id, smack);
1985         if (ret != PC_OPERATION_SUCCESS) {
1986                 SECURE_SLOGE("Error while adding rules for access to public dirs for app %s: %s ", pkg_id, strerror(errno));
1987                 return ret;
1988         }
1989
1990         if (have_smack() && smack_accesses_apply(smack)) {
1991                 C_LOGE("smack_accesses_apply failed");
1992                 return PC_ERR_INVALID_OPERATION;
1993         }
1994
1995         if (smack_accesses_save(smack, fd)) {
1996                 C_LOGE("smack_accesses_save failed");
1997                 return PC_ERR_INVALID_OPERATION;
1998         }
1999
2000         return PC_OPERATION_SUCCESS;
2001 }
2002
2003 API int app_uninstall(const char* pkg_id)//deprecated
2004 {
2005     return perm_app_uninstall(pkg_id);
2006 }
2007
2008 API int perm_app_uninstall(const char* pkg_id)
2009 {
2010         // TODO: When real database will be used, then this function should remove app_id
2011         //       from database.
2012         //       It also should remove rules like: "anti_virus_label app_id rwx".
2013         C_LOGD("Enter function: %s", __func__);
2014         char* smack_path AUTO_FREE;
2015         int ret;
2016
2017         if (!smack_label_is_valid(pkg_id))
2018                 return PC_ERR_INVALID_PARAM;
2019
2020         ret = smack_file_name(pkg_id, &smack_path);
2021         if (ret != PC_OPERATION_SUCCESS)
2022                 return ret;
2023
2024         if (unlink(smack_path)) {
2025                 C_LOGE("unlink failed: ", strerror(errno));
2026                 return PC_OPERATION_SUCCESS;
2027         }
2028
2029         ret = app_uninstall_remove_early_rules(pkg_id);
2030         if (ret != PC_OPERATION_SUCCESS)
2031                 return ret;
2032
2033
2034         return PC_OPERATION_SUCCESS;
2035 }
2036
2037 static int save_rules(int fd, struct smack_accesses* accesses) {
2038         if (flock(fd, LOCK_EX)) {
2039                 C_LOGE("flock failed, error %s", strerror(errno));
2040                 return PC_ERR_FILE_OPERATION;
2041         }
2042
2043         if (smack_accesses_save(accesses, fd)) {
2044                 C_LOGE("smack_accesses_save failed");
2045                 return PC_ERR_FILE_OPERATION;
2046         }
2047         return PC_OPERATION_SUCCESS ;
2048 }
2049
2050 static int validate_and_add_rule(char* rule, struct smack_accesses* accesses) {
2051         const char* subject = NULL;
2052         const char* object = NULL;
2053         const char* access = NULL;
2054         char* saveptr = NULL;
2055
2056         subject = strtok_r(rule, " \t\n", &saveptr);
2057         object = strtok_r(NULL, " \t\n", &saveptr);
2058         access = strtok_r(NULL, " \t\n", &saveptr);
2059
2060         // check rule validity
2061         if (subject == NULL ||
2062                 object == NULL ||
2063                 access == NULL ||
2064                 strtok_r(NULL, " \t\n", &saveptr) != NULL ||
2065                 !smack_label_is_valid(subject) ||
2066                 !smack_label_is_valid(object))
2067         {
2068                 C_LOGE("Incorrect rule format: %s", rule);
2069                 return PC_ERR_INVALID_PARAM;
2070         }
2071
2072         if (smack_accesses_add_modify(accesses, subject, object, access, "")) {
2073                 C_LOGE("smack_accesses_add_modify failed");
2074                 return PC_ERR_INVALID_OPERATION;
2075         }
2076         return PC_OPERATION_SUCCESS ;
2077 }
2078
2079 static int parse_and_save_rules(const char** smack_rules,
2080                 struct smack_accesses* accesses, const char* feature_file) {
2081         size_t i = 0;
2082         int fd = 0;
2083         int ret = PC_OPERATION_SUCCESS;
2084         char* tmp = NULL;
2085
2086         for (i = 0; smack_rules[i] != NULL ; i++) {
2087                 // ignore empty lines
2088                 if (strspn(smack_rules[i], " \t\n") == strlen(smack_rules[i]))
2089                         continue;
2090
2091                 tmp = strdup(smack_rules[i]);
2092                 ret = validate_and_add_rule(tmp, accesses);
2093                 free(tmp);
2094                 if (ret != PC_OPERATION_SUCCESS )
2095                         return ret;
2096         }
2097
2098         // save to file
2099         fd = open(feature_file, O_CREAT | O_WRONLY, 0644);
2100         if (fd == -1) {
2101                 C_LOGE("Unable to create file %s. Error: %s", feature_file, strerror(errno));
2102                 return PC_ERR_FILE_OPERATION;
2103         }
2104
2105         ret = save_rules(fd, accesses);
2106         close(fd);
2107         return ret;
2108 }
2109
2110 static int save_gids(FILE* file, const gid_t* list_of_db_gids, size_t list_size) {
2111         int ret = PC_OPERATION_SUCCESS;
2112         int written = 0;
2113         size_t i = 0;
2114
2115         if (file == NULL) {
2116                 C_LOGE("Unable to create file. Error: %s", strerror(errno));
2117                 return PC_ERR_FILE_OPERATION;   // TODO remove smack accesses?
2118         }
2119
2120         if(-1 == fchmod(fileno(file), 0644)) {
2121                 C_LOGE("Unable to chmod file. Error: %s", strerror(errno));
2122                 return PC_ERR_FILE_OPERATION;
2123         }
2124
2125         for (i = 0; i < list_size ; ++i) {
2126                 written = fprintf(file, "%u\n", list_of_db_gids[i]);
2127                 if (written <= 0) {
2128                         C_LOGE("fprintf failed for file. Error: %s", strerror(errno));
2129                         ret = PC_ERR_FILE_OPERATION;
2130                         break;
2131                 }
2132         }
2133         return ret;
2134 }
2135
2136 API int add_api_feature(app_type_t app_type,
2137                         const char* api_feature_name,
2138                         const char** smack_rules,
2139                         const gid_t* list_of_db_gids,
2140                         size_t list_size)//deprecated
2141 {
2142     return perm_add_api_feature(app_type, api_feature_name, smack_rules, list_of_db_gids, list_size);
2143 }
2144
2145 API int perm_add_api_feature(app_type_t app_type,
2146                                                 const char* api_feature_name,
2147                                                 const char** smack_rules,
2148                                                 const gid_t* list_of_db_gids,
2149                                                 size_t list_size) {
2150         C_LOGD("Enter function: %s", __func__);
2151
2152         int ret = PC_OPERATION_SUCCESS;
2153         char* smack_file AUTO_FREE;
2154         char* dac_file AUTO_FREE;
2155         struct smack_accesses* accesses = NULL;
2156         FILE* file = NULL;
2157
2158         // TODO check process capabilities
2159
2160         // get feature SMACK file name
2161         ret = perm_file_path(&smack_file, app_type, api_feature_name, ".smack", 0);
2162         if (ret != PC_OPERATION_SUCCESS || !smack_file ) {
2163                 return ret;
2164         }
2165
2166         // check if feature exists
2167         if (file_exists(smack_file)) {
2168                 C_LOGE("Feature file %s already exists", smack_file);
2169                 return PC_ERR_INVALID_PARAM;
2170         }
2171
2172         // check .dac existence only if gids are supported
2173         if (list_of_db_gids && list_size > 0) {
2174                 // get feature DAC file name
2175                 ret = perm_file_path(&dac_file, app_type, api_feature_name, ".dac", 0);
2176                 if (ret != PC_OPERATION_SUCCESS || !dac_file ) {
2177                         return ret;
2178                 }
2179
2180                 // check if feature exists
2181                 if (file_exists(dac_file)) {
2182                         C_LOGE("Feature file %s already exists", dac_file);
2183                         return PC_ERR_INVALID_PARAM;
2184                 }
2185         }
2186
2187         // parse & save rules
2188         if (smack_rules) {
2189                 if (smack_accesses_new(&accesses)) {
2190                         C_LOGE("smack_acceses_new failed");
2191                         return PC_ERR_MEM_OPERATION;
2192                 }
2193
2194                 ret = parse_and_save_rules(smack_rules, accesses, smack_file);
2195                 smack_accesses_free(accesses);
2196         }
2197
2198         // go through gid list
2199         if (ret == PC_OPERATION_SUCCESS && list_of_db_gids && list_size > 0) {
2200                 // save to file
2201                 file = fopen(dac_file, "w+");
2202                 ret = save_gids(file, list_of_db_gids, list_size);
2203                 fclose(file);
2204         }
2205
2206         // remove both files in case of failure
2207         if (ret != PC_OPERATION_SUCCESS) {
2208                 unlink(smack_file);
2209                 if (dac_file) {
2210                         unlink(dac_file);
2211                 }
2212         }
2213
2214         return ret;
2215 }
2216
2217 /**
2218  * This function is marked as deprecated and will be removed
2219  */
2220 API int app_register_av(const char* app_av_id)//deprecated
2221 {
2222         int ret;
2223         int fd AUTO_CLOSE;
2224         char* smack_path AUTO_FREE;
2225         struct smack_accesses* smack AUTO_SMACK_FREE;
2226
2227         if(app_av_id == NULL) {
2228                 C_LOGE("Invalid param app_av_id.");
2229                 return PC_ERR_INVALID_PARAM;
2230         }
2231
2232         ret = load_smack_from_file(app_av_id, &smack, &fd, &smack_path);
2233         if (ret != PC_OPERATION_SUCCESS ) {
2234                 C_LOGE("load_smack_from_file failed");
2235                 return ret;
2236         }
2237
2238         ret = app_register_av_internal(app_av_id, smack);
2239         if (PC_OPERATION_SUCCESS != ret) {
2240                 C_LOGE("app_register_av_internal failed");
2241                 return ret;
2242         }
2243
2244         // Add permisions from OSP_antivirus.smack file
2245         ret = perm_to_smack(smack, app_av_id, APP_TYPE_OSP, TIZEN_PRIVILEGE_ANTIVIRUS);
2246         if (PC_OPERATION_SUCCESS != ret) {
2247                 C_LOGE("perm_to_smack failed");
2248                 return ret;
2249         }
2250
2251         // Add permisions from OSP_antivirus.dac file
2252         ret = perm_to_dac(app_av_id, APP_TYPE_OSP, TIZEN_PRIVILEGE_ANTIVIRUS);
2253         if (ret != PC_OPERATION_SUCCESS) {
2254                 C_LOGE("perm_to_dac failed");
2255                 return ret;
2256         }
2257
2258         if (have_smack() && smack_accesses_apply(smack)) {
2259                 C_LOGE("smack_accesses_apply failed");
2260                 ret = PC_ERR_INVALID_OPERATION;
2261                 return ret;
2262         }
2263
2264         if (smack_accesses_save(smack, fd)) {
2265                 C_LOGE("smack_accesses_save failed");
2266                 ret = PC_ERR_INVALID_OPERATION;
2267                 return ret;
2268         }
2269
2270     return ret;
2271 }