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