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