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