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