Fix boot-time smack rule loading
[platform/core/security/libprivilege-control.git] / src / access-db.c
1 /*
2  * libprivilege control
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact: Janusz Kozerski <j.kozerski@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 <errno.h>
26 #include <string.h>
27 #include <sys/smack.h>
28 #include <dlog.h>
29 #include <ctype.h>
30
31 #include "access-db.h"
32 #include "privilege-control.h"
33 #include "common.h"
34
35 typedef enum {
36         DB_APP_TYPE_GROUPS,
37         DB_APP_TYPE_COUNT /* Dummy enum element to get number of elements */
38 } db_app_type_t;
39
40 const char* db_file_names[DB_APP_TYPE_COUNT] = {
41                 "/opt/dbspace/.privilege_control_app_gids.db"
42 };
43
44 typedef struct element_s {
45         struct element_s* next;
46         char* value;
47 } element_t;
48
49 static element_t* add_element (element_t* elem, const char* value)
50 {
51         SECURE_C_LOGD("Entering function: %s. Params: value=%s",
52                                 __func__, value);
53
54         if (NULL == elem)
55                 return NULL;
56
57         element_t* new_element = malloc(sizeof(element_t));
58         if (NULL == new_element)
59                 return NULL;
60
61         new_element->value = malloc(sizeof(char) * (SMACK_LABEL_LEN + 1) );
62         if (NULL == new_element->value) {
63                 free(new_element);
64                 return NULL;
65         }
66
67         strncpy(new_element->value, value, SMACK_LABEL_LEN);
68         new_element->value[SMACK_LABEL_LEN] = '\0';
69         new_element->next = NULL;
70         elem->next = new_element;
71
72         return new_element;
73 }
74
75
76 static int remove_list(element_t* first_elem)
77 {
78         SECURE_C_LOGD("Entering function: %s.", __func__);
79
80         element_t* current = NULL;
81
82         while (NULL != first_elem) {
83                 current = first_elem;
84                 first_elem = first_elem->next;
85                 if (current->value)
86                         free(current->value);
87                 free(current);
88         }
89         return 0;
90 }
91
92
93 static int add_id_to_database_internal(const char * id, db_app_type_t app_type)
94 {
95         SECURE_C_LOGD("Entering function: %s. Params: id=%s",
96                                 __func__, id);
97
98         FILE* file_db AUTO_FCLOSE;
99         const char* db_file_name = db_file_names[app_type];
100
101         SECURE_C_LOGD("Opening database file %s.", db_file_name);
102         file_db = fopen(db_file_name, "a");
103         if (NULL == file_db) {
104                 SECURE_C_LOGD("Error while opening database file: %s", db_file_name);
105                 return PC_ERR_FILE_OPERATION;
106         }
107
108         if (0 > fprintf(file_db, "%s\n", id)) {
109                 SECURE_C_LOGE("Write label %s to database failed (error: %s)", id, strerror(errno));
110                 return PC_ERR_FILE_OPERATION;
111         }
112
113         return PC_OPERATION_SUCCESS;
114 }
115
116
117 static int get_all_ids_internal (char *** ids, int * len, db_app_type_t app_type)
118 {
119         SECURE_C_LOGD("Entering function: %s.", __func__);
120
121         int ret;
122         FILE* file_db AUTO_FCLOSE;
123         const char* db_file_name = db_file_names[app_type];
124         char smack_label[SMACK_LABEL_LEN + 1];
125         element_t* begin_of_list = NULL;
126
127         SECURE_C_LOGD("Opening database file %s.", db_file_name);
128         file_db = fopen(db_file_name, "r");
129         if (NULL == file_db) {
130                 SECURE_C_LOGE("Error while opening database file: %s", db_file_name);
131                 ret = PC_ERR_FILE_OPERATION;
132                 goto out;
133         }
134
135         // intialization of list of smack labels
136         *len = 0;
137         begin_of_list = malloc(sizeof(element_t));
138         if (begin_of_list == NULL ) {
139                 C_LOGE("Error while allocating memory");
140                 ret = PC_ERR_MEM_OPERATION;
141                 goto out;
142         }
143         begin_of_list->next  = NULL;
144         begin_of_list->value = NULL;
145         element_t* current = begin_of_list;
146
147         // reading from file ("database")
148         // notice that first element always stays with empty "value"
149         while (fscanf(file_db, "%" TOSTRING(SMACK_LABEL_LEN) "s\n", smack_label) == 1) {
150                 smack_label[SMACK_LABEL_LEN] = '\0';
151                 if (!smack_label_is_valid(smack_label)) {
152                         SECURE_C_LOGD("Found entry in database, but it's not correct SMACK label: \"%s\"", smack_label);
153                         continue;
154                 }
155                 SECURE_C_LOGD("Found installed label: \"%s\"", smack_label);
156                 ++(*len);
157                 current = add_element(current, smack_label);
158                 if (NULL == current) {
159                         *len = 0;
160                         C_LOGE("Error while adding smack label to the list.");
161                         ret = PC_ERR_MEM_OPERATION;
162                         goto out;
163                 }
164         }
165
166         if (*len > 0) {
167                 C_LOGD("Allocating memory for list of %d labels", *len);
168                 *ids = malloc((*len) * sizeof(char*));
169                 if (NULL == *ids) {
170                         *len = 0;
171                         C_LOGE("Error while allocating memory for list of labels.");
172                         ret = PC_ERR_MEM_OPERATION;
173                         goto out;
174                 }
175                 current = begin_of_list->next;
176                 int i;
177                 for (i=0; i < *len; ++i) {
178                         C_LOGD("Allocating memory for \"%s\" label", current->value);
179                         (*ids)[i] = malloc((SMACK_LABEL_LEN + 1) * sizeof(char));
180                         if (NULL == (*ids)[i]) {
181                                 ret = PC_ERR_MEM_OPERATION;
182                                 int j;
183                                 for (j = 0; j < i; ++j)
184                                         free((*ids)[j]);
185                                 free(*ids);
186                                 *ids = NULL;
187                                 *len = 0;
188                                 C_LOGE("Error while allocating memory for \"%s\" label", current->value);
189                                 goto out;
190                         }
191                         strncpy((*ids)[i], current->value, SMACK_LABEL_LEN);
192                         (*ids)[i][SMACK_LABEL_LEN] = '\0';
193                         current = current->next;
194                 }
195         }
196         else {
197                 C_LOGD("No labels found!");
198                 *ids = NULL;
199         }
200
201         ret =  PC_OPERATION_SUCCESS;
202
203
204 out:
205         remove_list(begin_of_list);
206
207         return ret;
208 }
209
210
211 int add_app_gid(const char *app_id, unsigned gid)
212 {
213         SECURE_C_LOGD("Entering function: %s. Params: app_id=%s, gid=%u",
214                                 __func__, app_id, gid);
215
216         char *field = NULL;
217         int ret;
218
219         ret = asprintf(&field, "%u:%s", gid, app_id);
220         if (ret == -1)
221         {
222                 C_LOGE("asprintf failed.");
223                 return PC_ERR_MEM_OPERATION;
224         }
225
226         ret = add_id_to_database_internal(field, DB_APP_TYPE_GROUPS);
227         free(field);
228
229         return ret;
230 }
231
232
233 int get_app_gids(const char *app_id, unsigned **gids, int *len)
234 {
235         SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
236                                 __func__, app_id);
237
238         char** fields AUTO_FREE;
239         int len_tmp, ret, i;
240
241         ret = get_all_ids_internal(&fields, &len_tmp, DB_APP_TYPE_GROUPS);
242         if (ret != PC_OPERATION_SUCCESS)
243         {
244                 C_LOGE("get_all_ids_internal failed.");
245                 return ret;
246         }
247
248         *len = 0;
249         *gids = NULL;
250         for (i = 0; i < len_tmp; ++i) {
251                 const char *field = fields[i];
252                 const char *app_id_tmp = NULL;
253                 unsigned gid = 0;
254
255                 for (; *field; ++field) {
256                         if (*field == ':') {
257                                 app_id_tmp = field + 1;
258                                 break;
259                         }
260                         if (isdigit(*field)) {
261                                 gid = gid * 10 + *field - '0';
262                         } else {
263                                 C_LOGE("Invalid format of group id read from groups database: %s", fields[i]);
264                                 ret = PC_ERR_FILE_OPERATION;
265                                 goto out;
266                         }
267                 }
268
269                 if (!app_id_tmp) {
270                         C_LOGE("No group id found.");
271                         ret = PC_ERR_FILE_OPERATION;
272                         goto out;
273                 }
274
275                 if (NULL == app_id) {
276                         *len = 0;
277                         return PC_OPERATION_SUCCESS;
278                 }
279
280                 if (!strcmp(app_id, app_id_tmp)) {
281                         unsigned *gids_realloc = realloc(*gids, sizeof(unsigned) * (*len + 1));
282                         if (gids_realloc == NULL) {
283                                 C_LOGE("Memory allocation failed.");
284                                 ret = PC_ERR_MEM_OPERATION;
285                                 goto out;
286                         }
287                         *gids = gids_realloc;
288                         (*gids)[(*len)++] = gid;
289                 }
290         }
291
292         ret = PC_OPERATION_SUCCESS;
293 out:
294         for (i = 0; i < len_tmp; ++i)
295                 free(fields[i]);
296
297         if (ret != PC_OPERATION_SUCCESS) {
298                 free(*gids);
299                 *len = 0;
300         }
301
302         return ret;
303 }