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