Implement perm_app_get_paths() API in libprivilege-control.
[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_get_app_paths(const char *const s_app_label_name,
294                       const char *const s_app_path_type_name,
295                       char ***ppp_paths)
296 {
297         RDB_LOG_ENTRY_PARAM("%s %s", s_app_label_name, s_app_path_type_name);
298
299         int ret;
300         int i_num_paths;
301         sqlite3 *p_db = NULL;
302
303         ret = rdb_begin(&p_db, RDB_TRANSACTION_SHARED_READ);
304         if (ret != PC_OPERATION_SUCCESS) goto finish;
305
306         ret = get_app_paths_count_internal(p_db,
307                                            s_app_label_name,
308                                            s_app_path_type_name,
309                                            &i_num_paths);
310         if (ret != PC_OPERATION_SUCCESS) goto finish;
311
312         ret = get_app_paths_internal(p_db, s_app_label_name,
313                                      s_app_path_type_name,
314                                      i_num_paths,
315                                      ppp_paths);
316
317 finish:
318         return rdb_finish(p_db, ret);
319 }
320
321
322 int rdb_add_permission_rules(const char *const s_permission_name,
323                              const char *const s_permission_type_name,
324                              const char *const *const pp_smack_rules)
325 {
326         RDB_LOG_ENTRY_PARAM("%s %s", s_permission_name, s_permission_type_name);
327
328         int ret = PC_ERR_DB_OPERATION;
329         sqlite3 *p_db = NULL;
330         sqlite3_int64 permission_id = -1;
331
332         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
333         if(ret != PC_OPERATION_SUCCESS) goto finish;
334
335         ret = add_permission_internal(p_db,
336                                       s_permission_name,
337                                       s_permission_type_name);
338         if(ret != PC_OPERATION_SUCCESS) goto finish;
339
340         ret = get_permission_id_internal(p_db,
341                                          s_permission_name,
342                                          s_permission_type_name,
343                                          &permission_id);
344         if(ret != PC_OPERATION_SUCCESS) goto finish;
345
346         ret = add_modified_permission_internal(p_db, permission_id);
347         if(ret != PC_OPERATION_SUCCESS) goto finish;
348
349         if(pp_smack_rules != NULL) {
350                 ret = add_permission_rules_internal(p_db,
351                                                     permission_id,
352                                                     pp_smack_rules);
353         }
354
355 finish:
356         return rdb_finish(p_db, ret);
357 }
358
359
360 int rdb_enable_app_permissions(const char *const s_app_label_name,
361                                const app_type_t i_permission_type,
362                                const char *const *const pp_permissions_list,
363                                const bool   b_is_volatile)
364 {
365         RDB_LOG_ENTRY_PARAM("%s %d %d", s_app_label_name, i_permission_type, (int)b_is_volatile);
366
367         int ret = PC_ERR_DB_OPERATION;
368         sqlite3 *p_db = NULL;
369         char *s_permission_name = NULL;
370         int i;
371         int i_app_id = 0;
372
373         const char *s_permission_type_name = app_type_name(i_permission_type);
374         const char *s_permission_group_type_name = app_type_group_name(i_permission_type);
375
376         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
377         if(ret != PC_OPERATION_SUCCESS) goto finish;
378
379         ret = get_app_id_internal(p_db, &i_app_id, s_app_label_name);
380         if(ret != PC_OPERATION_SUCCESS) goto finish;
381
382         // Add permissions specific for the permission type:
383         ret = change_app_permission_internal(p_db,
384                                              i_app_id,
385                                              s_permission_type_name,
386                                              s_permission_type_name,
387                                              b_is_volatile,
388                                              RDB_ENABLE);
389         if(ret != PC_OPERATION_SUCCESS) goto finish;
390
391         // Add permissions from the list:
392         for(i = 0; pp_permissions_list[i] != NULL; ++i) {
393                 // Ignore empty lines
394                 if(strspn(pp_permissions_list[i], " \t\n")
395                     == strlen(pp_permissions_list[i]))
396                         continue;
397
398                 ret = base_name_from_perm(pp_permissions_list[i], &s_permission_name);
399                 if(ret != PC_OPERATION_SUCCESS) goto finish;
400
401                 ret = change_app_permission_internal(p_db,
402                                                      i_app_id,
403                                                      s_permission_name,
404                                                      s_permission_group_type_name,
405                                                      b_is_volatile,
406                                                      RDB_ENABLE);
407                 free(s_permission_name);
408                 if(ret != PC_OPERATION_SUCCESS) goto finish;
409         }
410
411         ret = add_modified_label_internal(p_db, s_app_label_name);
412
413 finish:
414         return rdb_finish(p_db, ret);
415 }
416
417
418 int rdb_disable_app_permissions(const char *const s_app_label_name,
419                                 const app_type_t i_permission_type,
420                                 const char *const *const pp_permissions_list)
421 {
422         RDB_LOG_ENTRY_PARAM("%s %d", s_app_label_name, i_permission_type);
423
424         int ret = PC_ERR_DB_OPERATION;
425         sqlite3 *p_db = NULL;
426         char *s_permission_name = NULL;
427         int i, i_app_id;
428         const char *s_permission_group_type_name = app_type_group_name(i_permission_type);
429
430         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
431         if(ret != PC_OPERATION_SUCCESS) goto finish;
432
433         ret = get_app_id_internal(p_db, &i_app_id, s_app_label_name);
434         if(ret != PC_OPERATION_SUCCESS) goto finish;
435
436         for(i = 0; pp_permissions_list[i] != NULL ; ++i) {
437                 // Ignore empty lines
438                 if(strspn(pp_permissions_list[i], " \t\n")
439                     == strlen(pp_permissions_list[i]))
440                         continue;
441
442                 ret = base_name_from_perm(pp_permissions_list[i], &s_permission_name);
443                 if(ret != PC_OPERATION_SUCCESS) goto finish;
444
445                 ret = switch_app_permission_internal(p_db,
446                                                      i_app_id,
447                                                      s_permission_name,
448                                                      s_permission_group_type_name,
449                                                      RDB_DISABLE);
450                 free(s_permission_name);
451                 if(ret != PC_OPERATION_SUCCESS) goto finish;
452         }
453
454         ret = add_modified_label_internal(p_db, s_app_label_name);
455
456 finish:
457         return rdb_finish(p_db, ret);
458 }
459
460
461 int rdb_revoke_app_permissions(const char *const s_app_label_name)
462 {
463         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
464
465         int ret = PC_ERR_DB_OPERATION;
466         sqlite3 *p_db = NULL;
467
468         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
469         if(ret != PC_OPERATION_SUCCESS) goto finish;
470
471         ret = add_modified_label_internal(p_db, s_app_label_name);
472         if(ret != PC_OPERATION_SUCCESS) goto finish;
473
474         ret = add_modified_apps_path_internal(p_db, s_app_label_name);
475         if(ret != PC_OPERATION_SUCCESS) goto finish;
476
477         ret = revoke_app_permissions_internal(p_db, s_app_label_name);
478
479 finish:
480         return rdb_finish(p_db, ret);
481 }
482
483
484 int rdb_reset_app_permissions(const char *const s_app_label_name)
485 {
486         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
487
488         int ret = PC_ERR_DB_OPERATION;
489         sqlite3 *p_db = NULL;
490
491         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
492         if(ret != PC_OPERATION_SUCCESS) goto finish;
493
494         ret = reset_app_permissions_internal(p_db, s_app_label_name);
495         if(ret != PC_OPERATION_SUCCESS) goto finish;
496
497         ret = add_modified_label_internal(p_db, s_app_label_name);
498
499 finish:
500         return rdb_finish(p_db, ret);
501 }
502
503
504 int rdb_add_additional_rules(const char *const *const pp_smack_rules)
505 {
506         RDB_LOG_ENTRY;
507
508         int ret = PC_ERR_DB_OPERATION;
509         sqlite3 *p_db = NULL;
510
511         ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
512         if(ret != PC_OPERATION_SUCCESS) goto finish;
513
514         // Old rules may disappear, so mark as modified
515         ret = add_modified_additional_rules_internal(p_db);
516         if(ret != PC_OPERATION_SUCCESS) goto finish;
517
518         ret = add_additional_rules_internal(p_db, pp_smack_rules);
519         if(ret != PC_OPERATION_SUCCESS) goto finish;
520
521         // New rules appear, so also mark as modified
522         ret = add_modified_additional_rules_internal(p_db);
523
524 finish:
525         return rdb_finish(p_db, ret);
526 }
527
528 int rdb_app_has_permission(const char *const s_app_label_name,
529                            const char *const s_permission_type_name,
530                            const char *const s_permission_name,
531                            bool *const p_is_enabled)
532 {
533         RDB_LOG_ENTRY_PARAM("%s %s %s", s_app_label_name,
534                             s_permission_type_name, s_permission_name);
535         int ret = PC_ERR_DB_OPERATION;
536         sqlite3 *p_db = NULL;
537
538         ret = rdb_begin(&p_db, RDB_TRANSACTION_SHARED_READ); //shared readonly transaction
539         if(ret != PC_OPERATION_SUCCESS) goto finish;
540
541         ret = check_app_has_permission_internal(p_db,
542                                                 s_app_label_name,
543                                                 s_permission_name,
544                                                 s_permission_type_name,
545                                                 p_is_enabled);
546
547 finish:
548         return rdb_finish(p_db, ret);
549 }