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