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