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