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