Made marking labels as modified beautiful.
[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         ret = add_modified_label_internal(p_db, s_label_name);
166 finish:
167         if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
168         return ret;
169 }
170
171
172 int rdb_remove_application(const char *const s_label_name)
173 {
174         RDB_LOG_ENTRY_PARAM("%s", s_label_name);
175
176         int ret = PC_ERR_DB_OPERATION;
177         sqlite3 *p_db = NULL;
178
179         ret = rdb_begin(&p_db);
180         if(ret != PC_OPERATION_SUCCESS) goto finish;
181
182         ret = remove_app_internal(p_db, s_label_name);
183         if(ret != PC_OPERATION_SUCCESS) goto finish;
184
185         ret = add_modified_label_internal(p_db, s_label_name);
186         if(ret != PC_OPERATION_SUCCESS) goto finish;
187
188         ret = add_modified_apps_path_internal(p_db, s_label_name);
189 finish:
190         if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
191         return ret;
192 }
193
194
195 int rdb_add_path(const char *const s_owner_label_name,
196                  const char *const s_path_label_name,
197                  const char *const s_path,
198                  const char *const s_access,
199                  const char *const s_type)
200 {
201         RDB_LOG_ENTRY_PARAM("%s %s %s %s %s",
202                             s_owner_label_name, s_path_label_name,
203                             s_path, s_access, s_type);
204
205         int ret = PC_ERR_DB_OPERATION;
206         sqlite3 *p_db = NULL;
207
208         ret = rdb_begin(&p_db);
209         if(ret != PC_OPERATION_SUCCESS) goto finish;
210
211         ret = add_path_internal(p_db,
212                                 s_owner_label_name,
213                                 s_path_label_name,
214                                 s_path,
215                                 s_access,
216                                 s_type);
217         if(ret != PC_OPERATION_SUCCESS) goto finish;
218
219         ret = add_modified_label_internal(p_db, s_path_label_name);
220 finish:
221         if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
222         return ret;
223 }
224
225
226 int rdb_add_permission_rules(const char *const s_permission_name,
227                              const char *const s_permission_type_name,
228                              const char *const *const pp_smack_rules)
229 {
230         RDB_LOG_ENTRY_PARAM("%s %s", s_permission_name, s_permission_type_name);
231
232         int ret = PC_ERR_DB_OPERATION;
233         sqlite3 *p_db = NULL;
234         sqlite3_int64 permission_id = -1;
235
236         ret = rdb_begin(&p_db);
237         if(ret != PC_OPERATION_SUCCESS) goto finish;
238
239         ret = add_permission_internal(p_db,
240                                       s_permission_name,
241                                       s_permission_type_name);
242         if(ret != PC_OPERATION_SUCCESS) goto finish;
243
244         ret = get_permission_id_internal(p_db,
245                                          s_permission_name,
246                                          s_permission_type_name,
247                                          &permission_id);
248         if(ret != PC_OPERATION_SUCCESS) goto finish;
249
250         ret = add_modified_permission_internal(p_db, permission_id);
251         if(ret != PC_OPERATION_SUCCESS) goto finish;
252
253         if(pp_smack_rules != NULL) {
254                 ret = add_permission_rules_internal(p_db,
255                                                     permission_id,
256                                                     pp_smack_rules);
257         }
258
259 finish:
260         if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
261         return ret;
262 }
263
264
265 int rdb_enable_app_permissions(const char *const s_app_label_name,
266                                const char *const s_permission_type_name,
267                                const char *const *const pp_permissions_list,
268                                const bool   b_is_volatile)
269 {
270         RDB_LOG_ENTRY_PARAM("%s %s %d", s_app_label_name, s_permission_type_name, b_is_volatile);
271
272         int ret = PC_ERR_DB_OPERATION;
273         sqlite3 *p_db = NULL;
274         int i;
275         int i_app_id = 0;
276         C_LOGD("RDB: Enabling permissions START");
277
278         ret = rdb_begin(&p_db);
279         if(ret != PC_OPERATION_SUCCESS) goto finish;
280
281         ret = get_app_id_internal(p_db, &i_app_id, s_app_label_name);
282         if(ret != PC_OPERATION_SUCCESS) goto finish;
283
284         // Add permissions specific for the permission type:
285         ret = change_app_permission_internal(p_db,
286                                              i_app_id,
287                                              s_permission_type_name,
288                                              s_permission_type_name,
289                                              b_is_volatile,
290                                              RDB_ENABLE);
291         if(ret != PC_OPERATION_SUCCESS) goto finish;
292
293         // Add permissions from the list:
294         for(i = 0; pp_permissions_list[i] != NULL ; ++i) {
295                 // Ignore empty lines
296                 if(strspn(pp_permissions_list[i], " \t\n")
297                     == strlen(pp_permissions_list[i]))
298                         continue;
299
300                 ret = change_app_permission_internal(p_db,
301                                                      i_app_id,
302                                                      pp_permissions_list[i],
303                                                      s_permission_type_name,
304                                                      b_is_volatile,
305                                                      RDB_ENABLE);
306                 if(ret != PC_OPERATION_SUCCESS) goto finish;
307         }
308
309         ret = add_modified_label_internal(p_db, s_app_label_name);
310 finish:
311         if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
312         return ret;
313 }
314
315
316 int rdb_disable_app_permissions(const char *const s_app_label_name,
317                                 const char *const s_permission_type_name,
318                                 const char *const *const pp_permissions_list)
319 {
320         RDB_LOG_ENTRY_PARAM("%s %s", s_app_label_name, s_permission_type_name);
321
322         int ret = PC_ERR_DB_OPERATION;
323         sqlite3 *p_db = NULL;
324         int i, i_app_id;
325
326         ret = rdb_begin(&p_db);
327         if(ret != PC_OPERATION_SUCCESS) goto finish;
328
329         ret = get_app_id_internal(p_db, &i_app_id, s_app_label_name);
330         if(ret != PC_OPERATION_SUCCESS) goto finish;
331
332         for(i = 0; pp_permissions_list[i] != NULL ; ++i) {
333                 // Ignore empty lines
334                 if(strspn(pp_permissions_list[i], " \t\n")
335                     == strlen(pp_permissions_list[i]))
336                         continue;
337
338                 ret = switch_app_permission_internal(p_db,
339                                                      i_app_id,
340                                                      pp_permissions_list[i],
341                                                      s_permission_type_name,
342                                                      RDB_DISABLE);
343                 if(ret != PC_OPERATION_SUCCESS) goto finish;
344         }
345
346         ret = add_modified_label_internal(p_db, s_app_label_name);
347 finish:
348         if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
349         return ret;
350 }
351
352
353 int rdb_revoke_app_permissions(const char *const s_app_label_name)
354 {
355         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
356
357         int ret = PC_ERR_DB_OPERATION;
358         sqlite3 *p_db = NULL;
359
360         ret = rdb_begin(&p_db);
361         if(ret != PC_OPERATION_SUCCESS) goto finish;
362
363         ret = revoke_app_permissions_internal(p_db, s_app_label_name);
364         if(ret != PC_OPERATION_SUCCESS) goto finish;
365
366         ret = add_modified_label_internal(p_db, s_app_label_name);
367 finish:
368         if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
369         return ret;
370 }
371
372
373 int rdb_reset_app_permissions(const char *const s_app_label_name)
374 {
375         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
376
377         int ret = PC_ERR_DB_OPERATION;
378         sqlite3 *p_db = NULL;
379
380         ret = rdb_begin(&p_db);
381         if(ret != PC_OPERATION_SUCCESS) goto finish;
382
383         ret = reset_app_permissions_internal(p_db, s_app_label_name);
384         if(ret != PC_OPERATION_SUCCESS) goto finish;
385
386         ret = add_modified_label_internal(p_db, s_app_label_name);
387 finish:
388         if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
389         return ret;
390 }
391
392
393 int validate_all_rules(const char *const *const pp_permissions_list)
394 {
395         RDB_LOG_ENTRY;
396
397         int i;
398         char s_subject[SMACK_LABEL_LEN + 1];
399         char s_object[SMACK_LABEL_LEN + 1];
400         char s_access[ACC_LEN + 1];
401
402         // Parse and check rules.
403         for(i = 0; pp_permissions_list[i] != NULL; ++i) {
404                 // C_LOGE("RDB: Validating rules: %s", pp_permissions_list[i]);
405
406                 // Ignore empty lines
407                 if(strspn(pp_permissions_list[i], " \t\n")
408                     == strlen(pp_permissions_list[i]))
409                         continue;
410
411                 if(parse_rule(pp_permissions_list[i], s_subject, s_object, s_access)
412                     != PC_OPERATION_SUCCESS) {
413                         C_LOGE("RDB: Invalid parameter");
414                         return PC_ERR_INVALID_PARAM;
415                 }
416
417                 if(strcmp(s_subject, SMACK_APP_LABEL_TEMPLATE) != 0 &&
418                     strcmp(s_object, SMACK_APP_LABEL_TEMPLATE) != 0) {
419                         C_LOGE("RDB: There is no " SMACK_APP_LABEL_TEMPLATE " argument in template rule.");
420                         return PC_ERR_INVALID_PARAM;
421                 }
422
423                 if(strcmp(s_subject, SMACK_APP_LABEL_TEMPLATE) == 0 &&
424                     strcmp(s_object, SMACK_APP_LABEL_TEMPLATE) == 0) {
425                         C_LOGE("RDB: Rule with two " SMACK_APP_LABEL_TEMPLATE " has no sense.");
426                         return PC_ERR_INVALID_PARAM;
427                 }
428
429                 // Check the other label
430                 if(strcmp(s_subject, SMACK_APP_LABEL_TEMPLATE) == 0 &&
431                     !smack_label_is_valid(s_object)) {
432                         C_LOGE("RDB: Incorrect object label: %s", s_object);
433                         return PC_ERR_INVALID_PARAM;
434                 } else if(strcmp(s_object, SMACK_APP_LABEL_TEMPLATE) == 0 &&
435                           !smack_label_is_valid(s_subject)) {
436                         C_LOGE("RDB: Incorrect subject label: %s", s_subject);
437                         return PC_ERR_INVALID_PARAM;
438                 }
439         }
440
441         return PC_OPERATION_SUCCESS;
442 }