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