Fix boot-time smack rule loading
[platform/core/security/libprivilege-control.git] / src / rules-db.c
1 /*
2  * libprivilege control, rules database
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact: Jan Olszak <j.olszak@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 /*
23 * @file        rules-db.c
24 * @author      Jan Olszak (j.olszak@samsung.com)
25 * @version     1.0
26 * @brief       This file contains declaration of the API to rules database.
27 */
28
29 #include <stdlib.h>
30
31 #include "privilege-control.h"
32 #include "rules-db-internals.h"
33
34 static sqlite3 *p_db__          = NULL;
35 static int i_session_ret_code__ = PC_OPERATION_SUCCESS;
36 static bool b_shared_transaction__ = false;
37
38 typedef enum {
39         RDB_TRANSACTION_EXCLUSIVE,
40         RDB_TRANSACTION_SHARED_READ
41 } rdb_transaction_type_t;
42
43 /**
44  * Prepare to modify the database.
45  *
46  * @ingroup RDB internal functions
47  *
48  * @param   pp_db             pointer to a pointer to a SQLite3 database object
49  * @param   transaction_type  indicates whether the transaction is exclusive or shared
50  * @return                    PC_OPERATION_SUCCESS on success, error code otherwise
51  */
52 static int rdb_begin(sqlite3 **pp_db, rdb_transaction_type_t transaction_type)
53 {
54         RDB_LOG_ENTRY;
55
56         // If rdb_modification_start was called we use a global connection.
57         // Since global connection is always opened only for exclusive transactions, temporary
58         // tables are already created and b_shared_transaction is set to false.
59         if(p_db__) {
60                 *pp_db = p_db__;
61                 return PC_OPERATION_SUCCESS;
62         }
63
64         // Shared transaction doesn't need temporary tables because SMACK labels won't be modified.
65         bool b_create_temporary_tables = transaction_type != RDB_TRANSACTION_SHARED_READ;
66         int ret = open_rdb_connection(pp_db, b_create_temporary_tables);
67         if(ret != PC_OPERATION_SUCCESS) return ret;
68
69         if(transaction_type == RDB_TRANSACTION_EXCLUSIVE) {
70                 b_shared_transaction__ = false;
71                 ret = sqlite3_exec(*pp_db, "BEGIN EXCLUSIVE TRANSACTION", 0, 0, 0);
72         }
73         else if(transaction_type == RDB_TRANSACTION_SHARED_READ) {
74                 b_shared_transaction__ = true;
75                 ret = sqlite3_exec(*pp_db, "BEGIN DEFERRED TRANSACTION", 0, 0, 0);
76         }
77         else {
78                 C_LOGE("RDB: Bad transaction type specified: %d",
79                        (int)transaction_type);
80                 return PC_ERR_INVALID_PARAM;
81         }
82
83         if(ret != SQLITE_OK) {
84                 C_LOGE("RDB: Error during transaction begin: %s",
85                        sqlite3_errmsg(*pp_db));
86                 b_shared_transaction__ = false;
87                 return PC_ERR_DB_CONNECTION;
88         }
89
90         return ret;
91 }
92
93
94 /**
95  * Commit database modification.
96  * If previous operation returned an error try to rollback changes.
97  *
98  * @ingroup RDB internal functions
99  *
100  * @param  p_db           pointer to a SQLite3 database object
101  * @param  i_session_ret  session return code
102  * @return                PC_OPERATION_SUCCESS on success,
103  *                        error code otherwise
104  */
105 static int rdb_end(sqlite3 *p_db, int i_session_ret)
106 {
107         RDB_LOG_ENTRY;
108
109         int ret = PC_OPERATION_SUCCESS;
110
111         // No error during the session, make updates
112         if(i_session_ret == PC_OPERATION_SUCCESS && !b_shared_transaction__) {
113                 ret = update_rules_in_db(p_db);
114                 if(ret != PC_OPERATION_SUCCESS) {
115                         C_LOGE("RDB: Error during updating rules in the database: %d", ret);
116                         goto finish;
117                 }
118
119                 if(have_smack()) {
120                         ret = update_smack_rules(p_db);
121                         if(ret != PC_OPERATION_SUCCESS) {
122                                 C_LOGE("RDB: Error updating smack rules: %d", ret);
123                                 goto finish;
124                         }
125                 }
126         }
127
128 finish:
129         // End transaction in a way
130         // that depends on the ret and i_session_ret code.
131         if(i_session_ret == PC_OPERATION_SUCCESS &&
132             ret == PC_OPERATION_SUCCESS) {
133                 if(sqlite3_exec(p_db, "COMMIT TRANSACTION", 0, 0, 0)
134                     != SQLITE_OK) {
135                         C_LOGE("RDB: Error during transaction commit: %s",
136                                sqlite3_errmsg(p_db));
137                         ret = PC_ERR_DB_CONNECTION;
138                 }
139
140         } else if(i_session_ret == PC_ERR_DB_CONNECTION ||
141                   ret == PC_ERR_DB_CONNECTION) {
142                 // Life is pointless. I can't even rollback...
143                 C_LOGE("RDB: No rollback nor commit.");
144                 ret = PC_ERR_DB_CONNECTION;
145
146         } else {
147                 // Some other error code
148                 if(sqlite3_exec(p_db, "ROLLBACK TRANSACTION", 0, 0, 0)
149                     != SQLITE_OK) {
150                         C_LOGE("RDB: Error during transaction rollback: %s",
151                                sqlite3_errmsg(p_db));
152                         if(ret == PC_OPERATION_SUCCESS)
153                                 ret = PC_ERR_DB_CONNECTION;
154                 }
155         }
156
157         if(sqlite3_close(p_db)) {
158                 C_LOGE("RDB: Error during closing the database. Error: %s",
159                        sqlite3_errmsg(p_db));
160                 if(ret == PC_OPERATION_SUCCESS)
161                         ret = PC_ERR_DB_CONNECTION;
162         }
163
164         return ret;
165 }
166
167 /**
168  * Finish database modification.
169  * If global transaction is opened update session return code,
170  * otherwise end the transaction.
171  *
172  * @ingroup RDB internal functions
173  *
174  * @param  p_db           pointer to a SQLite3 database object
175  * @param  i_session_ret  session return code
176  * @return                PC_OPERATION_SUCCESS on success,
177  *                        error code otherwise
178  */
179 static int rdb_finish(sqlite3 *p_db, int i_session_ret)
180 {
181         if(p_db__) {
182                 if(i_session_ret_code__ == PC_OPERATION_SUCCESS)
183                         i_session_ret_code__ = i_session_ret;
184                 return i_session_ret;
185         } else {
186                 int ret = rdb_end(p_db, i_session_ret);
187                 return i_session_ret != PC_OPERATION_SUCCESS ? i_session_ret : ret;
188         }
189 }
190
191
192 int rdb_modification_start(void)
193 {
194         if(p_db__) {
195                 // We have to finish the previous session:
196                 C_LOGW("RDB: rdb_modification_finish was not called!");
197                 rdb_modification_finish();
198         }
199
200         return rdb_begin(&p_db__, RDB_TRANSACTION_EXCLUSIVE);
201 }
202
203
204 int rdb_modification_finish(void)
205 {
206         if(p_db__) {
207                 int ret = rdb_end(p_db__, i_session_ret_code__);
208                 p_db__ = NULL;
209                 i_session_ret_code__ = PC_OPERATION_SUCCESS;
210                 return ret;
211         } else {
212                 return PC_OPERATION_SUCCESS;
213         }
214 }
215
216 int rdb_modification_rollback(void)
217 {
218         if(p_db__) {
219                 if(i_session_ret_code__ == PC_OPERATION_SUCCESS) {
220                         // Trigger rollback
221                         i_session_ret_code__ = PC_ERR_INVALID_OPERATION;
222                 }
223                 return rdb_modification_finish();
224         } else {
225                 C_LOGE("RDB: Error nothing to rollback");
226                 return PC_ERR_INVALID_OPERATION;
227         }
228 }
229
230 int rdb_add_application(const char *const s_label_name)
231 {
232         RDB_LOG_ENTRY_PARAM("%s", s_label_name);
233
234         int ret = PC_ERR_DB_OPERATION;
235         sqlite3 *p_db = NULL;
236
237         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
238         if(ret != PC_OPERATION_SUCCESS) goto finish;
239
240         ret = check_app_label_internal(p_db, s_label_name);
241         if(ret == PC_ERR_DB_LABEL_TAKEN) {
242                 ret = PC_OPERATION_SUCCESS;
243                 C_LOGW("RDB: There is an application with label: %s", s_label_name);
244
245         } else if(ret == PC_OPERATION_SUCCESS) {
246                 // There is no such label yet.
247                 ret = add_app_internal(p_db, s_label_name);
248                 if(ret != PC_OPERATION_SUCCESS) goto finish;
249         }
250
251         ret = add_modified_label_internal(p_db, s_label_name);
252
253 finish:
254         return rdb_finish(p_db, ret);
255 }
256
257
258 int rdb_remove_application(const char *const s_label_name)
259 {
260         RDB_LOG_ENTRY_PARAM("%s", s_label_name);
261
262         int ret = PC_ERR_DB_OPERATION;
263         sqlite3 *p_db = NULL;
264
265         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
266         if(ret != PC_OPERATION_SUCCESS) goto finish;
267
268         ret = add_modified_label_internal(p_db, s_label_name);
269         if(ret != PC_OPERATION_SUCCESS) goto finish;
270
271         ret = add_modified_apps_path_internal(p_db, s_label_name);
272         if(ret != PC_OPERATION_SUCCESS) goto finish;
273
274         ret = remove_app_internal(p_db, s_label_name);
275
276 finish:
277         return rdb_finish(p_db, ret);
278 }
279
280
281 int rdb_add_path(const char *const s_owner_label_name,
282                  const char *const s_path_label_name,
283                  const char *const s_path,
284                  const char *const s_access,
285                  const char *const s_access_reverse,
286                  const char *const s_type)
287 {
288         RDB_LOG_ENTRY_PARAM("%s %s %s %s %s %s",
289                             s_owner_label_name, s_path_label_name,
290                             s_path, s_access, s_access_reverse, s_type);
291
292         int ret = PC_ERR_DB_OPERATION;
293         sqlite3 *p_db = NULL;
294
295         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
296         if(ret != PC_OPERATION_SUCCESS) goto finish;
297
298         ret = add_path_internal(p_db,
299                                 s_owner_label_name,
300                                 s_path_label_name,
301                                 s_path,
302                                 s_access,
303                                 s_access_reverse,
304                                 s_type);
305         if(ret != PC_OPERATION_SUCCESS) goto finish;
306
307         ret = add_modified_label_internal(p_db, s_path_label_name);
308
309 finish:
310         return rdb_finish(p_db, ret);
311 }
312
313
314 int rdb_add_permission_rules(const char *const s_permission_name,
315                              const char *const s_permission_type_name,
316                              const char *const *const pp_smack_rules)
317 {
318         RDB_LOG_ENTRY_PARAM("%s %s", s_permission_name, s_permission_type_name);
319
320         int ret = PC_ERR_DB_OPERATION;
321         sqlite3 *p_db = NULL;
322         sqlite3_int64 permission_id = -1;
323
324         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
325         if(ret != PC_OPERATION_SUCCESS) goto finish;
326
327         ret = add_permission_internal(p_db,
328                                       s_permission_name,
329                                       s_permission_type_name);
330         if(ret != PC_OPERATION_SUCCESS) goto finish;
331
332         ret = get_permission_id_internal(p_db,
333                                          s_permission_name,
334                                          s_permission_type_name,
335                                          &permission_id);
336         if(ret != PC_OPERATION_SUCCESS) goto finish;
337
338         ret = add_modified_permission_internal(p_db, permission_id);
339         if(ret != PC_OPERATION_SUCCESS) goto finish;
340
341         if(pp_smack_rules != NULL) {
342                 ret = add_permission_rules_internal(p_db,
343                                                     permission_id,
344                                                     pp_smack_rules);
345         }
346
347 finish:
348         return rdb_finish(p_db, ret);
349 }
350
351
352 int rdb_enable_app_permissions(const char *const s_app_label_name,
353                                const app_type_t i_permission_type,
354                                const char *const *const pp_permissions_list,
355                                const bool   b_is_volatile)
356 {
357         RDB_LOG_ENTRY_PARAM("%s %d %d", s_app_label_name, i_permission_type, (int)b_is_volatile);
358
359         int ret = PC_ERR_DB_OPERATION;
360         sqlite3 *p_db = NULL;
361         char *s_permission_name = NULL;
362         int i;
363         int i_app_id = 0;
364
365         const char *s_permission_type_name = app_type_name(i_permission_type);
366         const char *s_permission_group_type_name = app_type_group_name(i_permission_type);
367
368         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
369         if(ret != PC_OPERATION_SUCCESS) goto finish;
370
371         ret = get_app_id_internal(p_db, &i_app_id, s_app_label_name);
372         if(ret != PC_OPERATION_SUCCESS) goto finish;
373
374         // Add permissions specific for the permission type:
375         ret = change_app_permission_internal(p_db,
376                                              i_app_id,
377                                              s_permission_type_name,
378                                              s_permission_type_name,
379                                              b_is_volatile,
380                                              RDB_ENABLE);
381         if(ret != PC_OPERATION_SUCCESS) goto finish;
382
383         // Add permissions from the list:
384         for(i = 0; pp_permissions_list[i] != NULL; ++i) {
385                 // Ignore empty lines
386                 if(strspn(pp_permissions_list[i], " \t\n")
387                     == strlen(pp_permissions_list[i]))
388                         continue;
389
390                 ret = base_name_from_perm(pp_permissions_list[i], &s_permission_name);
391                 if(ret != PC_OPERATION_SUCCESS) goto finish;
392
393                 ret = change_app_permission_internal(p_db,
394                                                      i_app_id,
395                                                      s_permission_name,
396                                                      s_permission_group_type_name,
397                                                      b_is_volatile,
398                                                      RDB_ENABLE);
399                 free(s_permission_name);
400                 if(ret != PC_OPERATION_SUCCESS) goto finish;
401         }
402
403         ret = add_modified_label_internal(p_db, s_app_label_name);
404
405 finish:
406         return rdb_finish(p_db, ret);
407 }
408
409
410 int rdb_disable_app_permissions(const char *const s_app_label_name,
411                                 const app_type_t i_permission_type,
412                                 const char *const *const pp_permissions_list)
413 {
414         RDB_LOG_ENTRY_PARAM("%s %d", s_app_label_name, i_permission_type);
415
416         int ret = PC_ERR_DB_OPERATION;
417         sqlite3 *p_db = NULL;
418         char *s_permission_name = NULL;
419         int i, i_app_id;
420         const char *s_permission_group_type_name = app_type_group_name(i_permission_type);
421
422         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
423         if(ret != PC_OPERATION_SUCCESS) goto finish;
424
425         ret = get_app_id_internal(p_db, &i_app_id, s_app_label_name);
426         if(ret != PC_OPERATION_SUCCESS) goto finish;
427
428         for(i = 0; pp_permissions_list[i] != NULL ; ++i) {
429                 // Ignore empty lines
430                 if(strspn(pp_permissions_list[i], " \t\n")
431                     == strlen(pp_permissions_list[i]))
432                         continue;
433
434                 ret = base_name_from_perm(pp_permissions_list[i], &s_permission_name);
435                 if(ret != PC_OPERATION_SUCCESS) goto finish;
436
437                 ret = switch_app_permission_internal(p_db,
438                                                      i_app_id,
439                                                      s_permission_name,
440                                                      s_permission_group_type_name,
441                                                      RDB_DISABLE);
442                 free(s_permission_name);
443                 if(ret != PC_OPERATION_SUCCESS) goto finish;
444         }
445
446         ret = add_modified_label_internal(p_db, s_app_label_name);
447
448 finish:
449         return rdb_finish(p_db, ret);
450 }
451
452
453 int rdb_revoke_app_permissions(const char *const s_app_label_name)
454 {
455         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
456
457         int ret = PC_ERR_DB_OPERATION;
458         sqlite3 *p_db = NULL;
459
460         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
461         if(ret != PC_OPERATION_SUCCESS) goto finish;
462
463         ret = add_modified_label_internal(p_db, s_app_label_name);
464         if(ret != PC_OPERATION_SUCCESS) goto finish;
465
466         ret = add_modified_apps_path_internal(p_db, s_app_label_name);
467         if(ret != PC_OPERATION_SUCCESS) goto finish;
468
469         ret = revoke_app_permissions_internal(p_db, s_app_label_name);
470
471 finish:
472         return rdb_finish(p_db, ret);
473 }
474
475
476 int rdb_reset_app_permissions(const char *const s_app_label_name)
477 {
478         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
479
480         int ret = PC_ERR_DB_OPERATION;
481         sqlite3 *p_db = NULL;
482
483         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
484         if(ret != PC_OPERATION_SUCCESS) goto finish;
485
486         ret = reset_app_permissions_internal(p_db, s_app_label_name);
487         if(ret != PC_OPERATION_SUCCESS) goto finish;
488
489         ret = add_modified_label_internal(p_db, s_app_label_name);
490
491 finish:
492         return rdb_finish(p_db, ret);
493 }
494