Fix boot-time smack rule loading
[platform/core/security/libprivilege-control.git] / src / rules-db-internals.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-internals.c
24 * @author      Jan Olszak (j.olszak@samsung.com)
25 * @version     1.0
26 * @brief       Definition of internal functions of the rules-db API.
27 */
28
29 #include <errno.h>      // For error logging
30 #include <stdarg.h>     // For handling multiple arguments
31 #include <stdlib.h>     // For free
32 #include <stdio.h>      // For file manipulation
33 #include "common.h"     // For smack_label_is_valid
34 #include <unistd.h>     // For sleep
35
36 #include "rules-db-internals.h"
37 #include "rules-db.h"
38
39 #define RDB_MAX_QUERY_ATTEMPTS    50
40 #define RDB_TIME_BETWEEN_ATTEMPTS 1 // sec
41
42 /**
43  * Reset and unbind statement. Used in functions that use bindings.
44  * @param  p_stmt SQLite3 statement
45  * @return        PC_OPERATION_SUCCESS on success, error code otherwise
46  */
47 static int reset_and_unbind_stmt(sqlite3_stmt *p_stmt)
48 {
49         if(sqlite3_clear_bindings(p_stmt) != SQLITE_OK) {
50                 C_LOGE("RDB: Error unbinding statement: %s",
51                        sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
52                 return PC_ERR_DB_QUERY_STEP;
53         }
54
55         if(sqlite3_reset(p_stmt) != SQLITE_OK) {
56                 C_LOGE("RDB: Error reseting statement: %s",
57                        sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
58                 return PC_ERR_DB_QUERY_STEP;
59         }
60         return PC_OPERATION_SUCCESS;
61 }
62
63
64
65 /**
66  * Helper function. Use on INSERT or DELETE or UPDATE, when not interested in returned value
67  *
68  * @ingroup RDB: internal functions
69  *
70  * @param  p_stmt SQLite3 statement
71  * @return        PC_OPERATION_SUCCESS on success, error code otherwise
72  */
73 static int step_and_convert_returned_value(sqlite3_stmt *p_stmt)
74 {
75         if(sqlite3_step(p_stmt) == SQLITE_DONE) {
76                 return PC_OPERATION_SUCCESS;
77         } else {
78                 C_LOGE("RDB: Error during stepping: %s",
79                        sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
80                 return PC_ERR_DB_QUERY_STEP;
81         }
82 }
83
84 int add_modified_label_internal(sqlite3 *p_db, const char *const s_label_name)
85 {
86         int ret = PC_OPERATION_SUCCESS;
87         sqlite3_stmt *p_stmt = NULL;
88         ret = prepare_stmt(p_db, &p_stmt,
89                            "INSERT OR IGNORE INTO modified_label(name) VALUES(%Q)",
90                            s_label_name);
91         if(ret != PC_OPERATION_SUCCESS) goto finish;
92
93         ret = step_and_convert_returned_value(p_stmt);
94 finish:
95         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
96                 C_LOGE("RDB: Error during finalizing statement: %s",
97                        sqlite3_errmsg(p_db));
98         return ret;
99 }
100
101
102 int add_modified_permission_internal(sqlite3 *p_db, sqlite3_int64 i_permission_id)
103 {
104         int ret = PC_OPERATION_SUCCESS;
105         sqlite3_stmt *p_stmt = NULL;
106         ret = prepare_stmt(p_db, &p_stmt,
107                            "INSERT OR IGNORE INTO modified_label(name) \
108                             SELECT app_permission_view.app_name        \
109                             FROM   app_permission_view                 \
110                             WHERE  app_permission_view.permission_id = %d",
111                            i_permission_id);
112         if(ret != PC_OPERATION_SUCCESS) goto finish;
113
114         ret = step_and_convert_returned_value(p_stmt);
115 finish:
116         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
117                 C_LOGE("RDB: Error during finalizing statement: %s",
118                        sqlite3_errmsg(p_db));
119         return ret;
120 }
121
122
123 int add_modified_apps_path_internal(sqlite3 *p_db,
124                                     const char *const s_app_label_name)
125 {
126         int ret = PC_OPERATION_SUCCESS;
127         sqlite3_stmt *p_stmt = NULL;
128         ret = prepare_stmt(p_db, &p_stmt,
129                            "INSERT OR IGNORE INTO modified_label(name) \
130                             SELECT path_view.path_label_name           \
131                             FROM   path_view                           \
132                             WHERE  path_view.owner_app_label_name = %Q",
133                            s_app_label_name);
134         if(ret != PC_OPERATION_SUCCESS) goto finish;
135
136         ret = step_and_convert_returned_value(p_stmt);
137 finish:
138         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
139                 C_LOGE("RDB: Error during finalizing statement: %s",
140                        sqlite3_errmsg(p_db));
141         return ret;
142 }
143
144
145 /**
146  * Function called when the target database is busy.
147  * We attempt to access the database every
148  * RDB_TIME_BETWEEN_ATTEMPTS seconds
149  *
150  * @param  not_used  not used
151  * @param  i_attempt number of the attempt
152  * @return           0 when stops waiting
153  *                   1 when waiting
154  */
155 static int database_busy_handler(void *not_used UNUSED,
156                                  int i_attempt)
157 {
158         if(i_attempt > RDB_MAX_QUERY_ATTEMPTS) {
159                 // I ain't gonna wait for you forever!
160                 C_LOGE("RDB: Database busy for too long.");
161                 return 0;
162         }
163         C_LOGW("RDB: Database busy, waiting");
164         sleep(RDB_TIME_BETWEEN_ATTEMPTS);
165         return 1;
166 }
167
168
169 int open_rdb_connection(sqlite3 **p_db, bool b_create_temporary_tables)
170 {
171         RDB_LOG_ENTRY;
172
173         char *p_err_msg;
174
175         // Open connection:
176         int ret = sqlite3_open_v2(RDB_PATH,
177                                   p_db,
178                                   RDB_READWRITE_FLAG,
179                                   NULL);
180         if(*p_db == NULL) {
181                 C_LOGE("RDB: Error opening the database: Unable to allocate memory.");
182                 return PC_ERR_DB_CONNECTION;
183         }
184         if(ret != SQLITE_OK) {
185                 C_LOGE("RDB: Error opening the database: %s", sqlite3_errmsg(*p_db));
186                 return PC_ERR_DB_CONNECTION;
187         }
188
189         //Register busy handler:
190         if(sqlite3_busy_handler(*p_db, database_busy_handler, NULL) != SQLITE_OK) {
191                 C_LOGE("RDB: Error opening the database: %s", sqlite3_errmsg(*p_db));
192                 return PC_ERR_DB_CONNECTION;
193         }
194
195         // Load extensions:
196         if(sqlite3_enable_load_extension(*p_db, 1) != SQLITE_OK) {
197                 C_LOGE("RDB: Error enabling extensions: %s", sqlite3_errmsg(*p_db));
198                 return PC_ERR_DB_CONNECTION;
199         }
200
201         if(sqlite3_load_extension(*p_db,
202                                   "/usr/lib/librules-db-sql-udf.so", 0,
203                                   &p_err_msg) != SQLITE_OK) {
204
205                 C_LOGE("RDB: Error during loading librules-db-sql-udf.so: %s",
206                        p_err_msg);
207                 sqlite3_free(p_err_msg);
208                 return PC_ERR_DB_CONNECTION;
209         }
210         sqlite3_free(p_err_msg);
211
212
213         if (b_create_temporary_tables) {
214                 // Create the temporary tables:
215                 if(sqlite3_exec(*p_db,
216                                 "PRAGMA foreign_keys = ON;                                 \
217                                                                                            \
218                                 PRAGMA temp_store = MEMORY;                                \
219                                                                                            \
220                                 CREATE TEMPORARY TABLE modified_label(                     \
221                                         name VARCHAR NOT NULL PRIMARY KEY);                \
222                                                                                            \
223                                 CREATE TEMPORARY TABLE all_smack_binary_rules_modified(    \
224                                         subject TEXT NOT NULL,                             \
225                                         object  TEXT NOT NULL,                             \
226                                         access  INTEGER NOT NULL,                          \
227                                         is_volatile INTEGER NOT NULL);                     \
228                                                                                            \
229                                 CREATE TEMPORARY TABLE current_smack_rule_modified(        \
230                                         subject VARCHAR NOT NULL,                          \
231                                         object  VARCHAR NOT NULL,                          \
232                                         access  INTEGER NOT NULL);                         \
233                                                                                            \
234                                 CREATE TEMPORARY TABLE history_smack_rule_modified(        \
235                                         subject VARCHAR NOT NULL,                          \
236                                         object  VARCHAR NOT NULL,                          \
237                                         access  INTEGER NOT NULL);                         \
238                                                                                            \
239                                 CREATE TEMPORARY VIEW modified_smack_rules AS              \
240                                 SELECT  subject, object,                                   \
241                                         access_to_str(access_add) AS access_add,           \
242                                         access_to_str(access_del) AS access_del            \
243                                 FROM    (                                                  \
244                                         SELECT     subject, object,                        \
245                                                    s1.access & ~s2.access AS access_add,   \
246                                                    s2.access & ~s1.access AS access_del    \
247                                         FROM       current_smack_rule_modified AS s1       \
248                                         INNER JOIN history_smack_rule_modified AS s2       \
249                                                    USING (subject, object)                 \
250                                         WHERE      s1.access != s2.access                  \
251                                         UNION                                              \
252                                         SELECT     subject, object,                        \
253                                                    s1.access AS access_add,                \
254                                                    0 AS access_del                         \
255                                         FROM       current_smack_rule_modified s1          \
256                                         LEFT JOIN  history_smack_rule_modified s2          \
257                                                    USING (subject, object)                 \
258                                         WHERE      s2.subject IS NULL AND                  \
259                                                    s2.object  IS NULL                      \
260                                         UNION                                              \
261                                         SELECT     subject, object,                        \
262                                                    0 AS access_add,                        \
263                                                    s1.access AS access_del                 \
264                                         FROM       history_smack_rule_modified s1          \
265                                         LEFT JOIN  current_smack_rule_modified s2          \
266                                                    USING (subject, object)                 \
267                                         WHERE      s2.subject IS NULL AND                  \
268                                                    s2.object  IS NULL                      \
269                                         )                                                  \
270                                 ORDER BY subject, object ASC;",
271                                 0, 0, 0) != SQLITE_OK) {
272                         C_LOGE("RDB: Error during preparing script: %s", sqlite3_errmsg(*p_db));
273                         return PC_ERR_DB_CONNECTION;
274                 }
275         } else {
276                 // Just enable foreign keys:
277                 if(sqlite3_exec(*p_db, "PRAGMA foreign_keys = ON", 0, 0, 0) != SQLITE_OK) {
278                         C_LOGE("RDB: Error during preparing script: %s", sqlite3_errmsg(*p_db));
279                         return PC_ERR_DB_CONNECTION;
280                 }
281         }
282
283         return PC_OPERATION_SUCCESS;
284 }
285
286
287 int prepare_stmt(sqlite3 *p_db,
288                  sqlite3_stmt **pp_stmt,
289                  const char *const s_sql,
290                  ...)
291 {
292         int ret = PC_ERR_DB_QUERY_PREP;
293         char *s_query = NULL;
294         va_list args;
295         va_start(args, s_sql);
296
297         s_query = sqlite3_vmprintf(s_sql, args);
298
299         if(s_query == NULL) {
300                 C_LOGE("RDB: Error during preparing statement: Unable to allocate enough memory.");
301                 ret = PC_ERR_DB_QUERY_PREP;
302                 goto finish;
303         }
304
305         if(sqlite3_prepare_v2(p_db,
306                               s_query,
307                               strlen(s_query) + 1,
308                               pp_stmt,
309                               NULL) != SQLITE_OK) {
310                 C_LOGE("RDB: Error during preparing statement: %s", sqlite3_errmsg(p_db));
311                 ret = PC_ERR_DB_QUERY_PREP;
312                 goto finish;
313         }
314
315         if(*pp_stmt == NULL) {
316                 C_LOGE("RDB: Error during preparing statement: SQL statement is probably empty.");
317                 ret = PC_ERR_DB_QUERY_PREP;
318                 goto finish;
319         }
320
321         ret = PC_OPERATION_SUCCESS;
322
323 finish:
324         va_end(args);
325         sqlite3_free(s_query);
326         return ret;
327 }
328
329
330 int check_app_label_internal(sqlite3 *p_db,
331                              const char *const s_label_name)
332 {
333         RDB_LOG_ENTRY_PARAM("%s", s_label_name);
334
335         int ret = PC_ERR_DB_OPERATION;
336         sqlite3_stmt *p_stmt = NULL;
337
338         ret = prepare_stmt(p_db, &p_stmt,
339                            "SELECT 1                      \
340                             FROM application_view          \
341                             WHERE application_view.name=%Q \
342                             LIMIT 1",
343                            s_label_name);
344         if(ret != PC_OPERATION_SUCCESS) goto finish;
345
346         ret = sqlite3_step(p_stmt);
347         if(ret == SQLITE_ROW) {
348                 // There is such application label
349                 ret = PC_ERR_DB_LABEL_TAKEN;
350         } else if(ret == SQLITE_DONE) {
351                 // No such application label
352                 ret = PC_OPERATION_SUCCESS;
353         } else {
354                 C_LOGE("RDB: Error during stepping: %s", sqlite3_errmsg(p_db));
355                 ret = PC_ERR_DB_QUERY_STEP;
356         }
357 finish:
358         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
359                 C_LOGE("RDB: Error during finalizing statement: %s",
360                        sqlite3_errmsg(p_db));
361         return ret;
362 }
363
364
365 int add_app_internal(sqlite3 *p_db,
366                      const char *const s_label_name)
367 {
368         RDB_LOG_ENTRY_PARAM("%s", s_label_name);
369
370         int ret = PC_ERR_DB_OPERATION;
371         sqlite3_stmt *p_stmt = NULL;
372
373         ret = prepare_stmt(p_db, &p_stmt,
374                            "INSERT into application_view(name) VALUES(%Q)",
375                            s_label_name);
376         if(ret != PC_OPERATION_SUCCESS) goto finish;
377
378         ret = step_and_convert_returned_value(p_stmt);
379 finish:
380         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
381                 C_LOGE("RDB: Error during finalizing statement: %s",
382                        sqlite3_errmsg(p_db));
383         return ret;
384 }
385
386
387 int remove_app_internal(sqlite3 *p_db,
388                         const char *const s_label_name)
389 {
390         RDB_LOG_ENTRY_PARAM("%s", s_label_name);
391
392         int ret = PC_ERR_DB_OPERATION;
393         sqlite3_stmt *p_stmt = NULL;
394
395         ret = prepare_stmt(p_db, &p_stmt,
396                            "DELETE FROM application_view \
397                              WHERE application_view.name=%Q",
398                            s_label_name);
399
400         if(ret != PC_OPERATION_SUCCESS) goto finish;
401
402         ret = step_and_convert_returned_value(p_stmt);
403 finish:
404         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
405                 C_LOGE("RDB: Error during finalizing statement: %s",
406                        sqlite3_errmsg(p_db));
407         return ret;
408 }
409
410
411 int add_path_internal(sqlite3 *p_db,
412                       const char *const s_owner_label_name,
413                       const char *const s_path_label_name,
414                       const char *const s_path,
415                       const char *const s_access,
416                       const char *const s_access_reverse,
417                       const char *const s_type)
418 {
419         RDB_LOG_ENTRY_PARAM("%s %s %s %s %s %s",
420                             s_owner_label_name, s_path_label_name,
421                             s_path, s_access, s_access_reverse, s_type);
422
423         int ret = PC_ERR_DB_OPERATION;
424         sqlite3_stmt *p_stmt = NULL;
425
426         ret = prepare_stmt(p_db, &p_stmt,
427                            "INSERT INTO path_view(owner_app_label_name, \
428                                                   path,                 \
429                                                   path_label_name,      \
430                                                   access,               \
431                                                   access_reverse,       \
432                                                   path_type_name)       \
433                              VALUES(%Q, %Q, %Q, %Q, %Q, %Q);",
434                            s_owner_label_name, s_path, s_path_label_name,
435                            s_access, s_access_reverse, s_type);
436         if(ret != PC_OPERATION_SUCCESS) goto finish;
437
438         ret = step_and_convert_returned_value(p_stmt);
439 finish:
440         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
441                 C_LOGE("RDB: Error during finalizing statement: %s",
442                        sqlite3_errmsg(p_db));
443         return ret;
444 }
445
446
447 int add_permission_internal(sqlite3 *p_db,
448                             const char *const s_permission_name,
449                             const char *const s_permission_type_name)
450 {
451         RDB_LOG_ENTRY_PARAM("%s %s", s_permission_name, s_permission_type_name);
452
453         int ret = PC_ERR_DB_OPERATION;
454         sqlite3_stmt *p_stmt = NULL;
455
456         ret = prepare_stmt(p_db, &p_stmt,
457                            "INSERT INTO permission_view(name, type_name) \
458                            VALUES (%Q,%Q)",
459                            s_permission_name, s_permission_type_name);
460
461         if(ret != PC_OPERATION_SUCCESS) goto finish;
462
463         ret = step_and_convert_returned_value(p_stmt);
464 finish:
465         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
466                 C_LOGE("RDB: Error during finalizing statement: %s",
467                        sqlite3_errmsg(p_db));
468         return ret;
469 }
470
471
472 int get_permission_id_internal(sqlite3 *p_db,
473                                const char *const s_permission_name,
474                                const char *const s_permission_type_name,
475                                sqlite3_int64 *p_permission_id)
476 {
477         RDB_LOG_ENTRY_PARAM("%s %s", s_permission_name, s_permission_type_name);
478
479         int ret = PC_ERR_DB_OPERATION;
480         sqlite3_stmt *p_stmt = NULL;
481
482         ret = prepare_stmt(p_db, &p_stmt,
483                            "SELECT permission_view.permission_id  \
484                             FROM   permission_view                \
485                             WHERE  permission_view.name = %Q AND  \
486                                    permission_view.type_name = %Q \
487                             LIMIT  1",
488                            s_permission_name, s_permission_type_name);
489         if(ret != PC_OPERATION_SUCCESS) goto finish;
490
491         ret = sqlite3_step(p_stmt);
492         if(ret == SQLITE_ROW) {
493                 ret = PC_OPERATION_SUCCESS;
494                 *p_permission_id = sqlite3_column_int(p_stmt, RDB_FIRST_COLUMN);
495         } else if(ret == SQLITE_DONE) {
496                 C_LOGW("RDB: There is no permission_id for %s %s", s_permission_name, s_permission_type_name);
497                 ret = PC_ERR_DB_OPERATION;
498
499         } else {
500                 C_LOGE("RDB: Error during stepping: %s", sqlite3_errmsg(p_db));
501                 ret = PC_ERR_DB_QUERY_STEP;
502         }
503
504 finish:
505         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
506                 C_LOGE("RDB: Error during finalizing statement: %s",
507                        sqlite3_errmsg(p_db));
508
509         return ret;
510 }
511
512
513 int prepare_stmts_for_bind(sqlite3 *p_db,
514                            sqlite3_stmt **pp_stmt,
515                            const char *const s_query)
516 {
517         if(sqlite3_prepare_v2(p_db,
518                               s_query,
519                               strlen(s_query) + 1,
520                               pp_stmt,
521                               NULL) != SQLITE_OK) {
522                 C_LOGE("RDB: Error during preparing statement: %s",
523                        sqlite3_errmsg(p_db));
524                 return PC_ERR_DB_QUERY_PREP;
525         }
526         return PC_OPERATION_SUCCESS;
527 }
528
529
530 static int add_permission_label_rule(sqlite3_stmt *p_stmt,
531                                      const sqlite3_int64 i_permission_id,
532                                      const char *const s_label_name,
533                                      const char *const s_access,
534                                      const int i_is_reverse)
535 {
536         int ret = PC_OPERATION_SUCCESS;
537
538         // Bind values to the statement and run it:
539         // Bind returns SQLITE_OK == 0 on success
540         if(sqlite3_bind_int(p_stmt, 1, i_permission_id) ||
541             sqlite3_bind_text(p_stmt, 2, s_access, RDB_AUTO_DETERM_SIZE, 0) ||
542             sqlite3_bind_text(p_stmt, 3, s_label_name, RDB_AUTO_DETERM_SIZE, 0) ||
543             sqlite3_bind_int(p_stmt, 4, i_is_reverse)) {
544                 C_LOGE("RDB: Error during binding to statement: %s",
545                        sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
546                 ret = PC_ERR_DB_QUERY_BIND;
547                 goto finish;
548         }
549
550         // Perform the insert
551         ret = step_and_convert_returned_value(p_stmt);
552
553 finish:
554         reset_and_unbind_stmt(p_stmt);
555         return ret;
556 }
557
558
559 static int add_permission_permission_rule(sqlite3_stmt *p_stmt,
560                 const sqlite3_int64 i_permission_id,
561                 const sqlite3_int64 i_target_permission_id,
562                 const char *const s_access,
563                 const int i_is_reverse)
564 {
565         int ret = PC_OPERATION_SUCCESS;
566
567         if(sqlite3_bind_int(p_stmt, 1, i_permission_id) ||
568             sqlite3_bind_int(p_stmt, 2, i_target_permission_id)  ||
569             sqlite3_bind_text(p_stmt, 3, s_access, RDB_AUTO_DETERM_SIZE, 0) ||
570             sqlite3_bind_int(p_stmt, 4, i_is_reverse)) {
571                 C_LOGE("RDB: Error during binding to statement: %s",
572                        sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
573                 ret = PC_ERR_DB_QUERY_BIND;
574                 goto finish;
575         }
576
577         ret = step_and_convert_returned_value(p_stmt);
578
579 finish:
580         reset_and_unbind_stmt(p_stmt);
581         return ret;
582 }
583
584
585 static int add_permission_app_path_type_rule(sqlite3_stmt *p_stmt,
586                 const sqlite3_int64 i_permission_id,
587                 const char *const s_path_type_name,
588                 const char *const s_access,
589                 const int i_is_reverse)
590 {
591         int ret = PC_OPERATION_SUCCESS;
592
593         if(sqlite3_bind_int(p_stmt, 1, i_permission_id) ||
594             sqlite3_bind_text(p_stmt, 2, s_path_type_name, RDB_AUTO_DETERM_SIZE, 0)  ||
595             sqlite3_bind_text(p_stmt, 3, s_access, RDB_AUTO_DETERM_SIZE, 0) ||
596             sqlite3_bind_int(p_stmt, 4, i_is_reverse)) {
597                 C_LOGE("RDB: Error during binding to statement: %s",
598                        sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
599                 ret = PC_ERR_DB_QUERY_BIND;
600                 goto finish;
601         }
602
603         ret = step_and_convert_returned_value(p_stmt);
604
605 finish:
606         reset_and_unbind_stmt(p_stmt);
607         return ret;
608 }
609
610 int add_permission_rules_internal(sqlite3 *p_db,
611                                   const sqlite3_int64 i_permission_id,
612                                   const char *const *const pp_smack_rules)
613 {
614         RDB_LOG_ENTRY;
615
616         int ret = PC_OPERATION_SUCCESS;
617         char s_label[SMACK_LABEL_LEN + 1];
618         char s_access[ACC_LEN + 1];
619         sqlite3_int64 i_all_apps_permission_id = 1;
620         int i_is_reverse = 0;
621         int i;
622         sqlite3_stmt *p_perm_to_label_stmt = NULL;
623         sqlite3_stmt *p_perm_to_perm_stmt = NULL;
624         sqlite3_stmt *p_perm_to_app_path_type_stmt = NULL;
625
626         // Prepare stmts. They are static, so we parse SQL only once per process and reuse it.
627         ret = prepare_stmts_for_bind(p_db, &p_perm_to_label_stmt,
628                                      "INSERT INTO permission_label_rule_view(        \
629                                       permission_id, access, label_name, is_reverse) \
630                                       VALUES(?,?,?,?)");
631         if(ret != PC_OPERATION_SUCCESS) goto finish;
632
633         ret = prepare_stmts_for_bind(p_db, &p_perm_to_perm_stmt,
634                                      "INSERT OR REPLACE INTO permission_permission_rule( \
635                                       permission_id, target_permission_id,               \
636                                       access, is_reverse)                                \
637                                       VALUES(?,?,str_to_access(?),?)");
638         if(ret != PC_OPERATION_SUCCESS) goto finish;
639
640
641         ret = prepare_stmts_for_bind(p_db, &p_perm_to_app_path_type_stmt,
642                                      "INSERT INTO permission_app_path_type_rule_view(        \
643                                       permission_id, app_path_type_name, access, is_reverse) \
644                                       VALUES(?,?,?,?)");
645         if(ret != PC_OPERATION_SUCCESS) goto finish;
646
647
648         for(i = 0; pp_smack_rules[i] != NULL ; ++i) {
649                 C_LOGD("RDB: Granting permission: %s", pp_smack_rules[i]);
650
651                 // Ignore empty lines
652                 if(strspn(pp_smack_rules[i], " \t\n") == strlen(pp_smack_rules[i]))
653                         continue;
654
655                 ret = parse_rule(pp_smack_rules[i], s_label, s_access, &i_is_reverse);
656                 if(ret != PC_OPERATION_SUCCESS) goto finish;
657
658                 // Interpret wildcards
659                 if(s_label[0] != '~' &&
660                     s_label[strlen(s_label) - 1] != '~') {
661                         // It's not a wildcard!
662                         ret = add_permission_label_rule(p_perm_to_label_stmt,
663                                                         i_permission_id,
664                                                         s_label,
665                                                         s_access,
666                                                         i_is_reverse);
667                         if(ret != PC_OPERATION_SUCCESS) goto finish;
668
669                 } else if(!strcmp(s_label, "~ALL_APPS~")) {
670                         ret = get_permission_id_internal(p_db,
671                                                          "ALL_APPS",
672                                                          "ALL_APPS",
673                                                          &i_all_apps_permission_id);
674                         if(ret != PC_OPERATION_SUCCESS) goto finish;
675
676                         ret = add_permission_permission_rule(p_perm_to_perm_stmt,
677                                                              i_permission_id,
678                                                              i_all_apps_permission_id,
679                                                              s_access,
680                                                              i_is_reverse);
681                         if(ret != PC_OPERATION_SUCCESS) goto finish;
682
683                 } else if(!strcmp(s_label, "~ALL_APPS_WITH_SAME_PERMISSION~")) {
684                         ret = add_permission_permission_rule(p_perm_to_perm_stmt,
685                                                              i_permission_id,
686                                                              i_permission_id,
687                                                              s_access,
688                                                              i_is_reverse);
689                         if(ret != PC_OPERATION_SUCCESS) goto finish;
690
691                 } else if(!strcmp(s_label, "~PUBLIC_PATH~")) {
692                         ret = add_permission_app_path_type_rule(p_perm_to_app_path_type_stmt,
693                                                                 i_permission_id,
694                                                                 "PUBLIC_PATH",
695                                                                 s_access,
696                                                                 i_is_reverse);
697                         if(ret != PC_OPERATION_SUCCESS) goto finish;
698
699                 } else if(!strcmp(s_label, "~GROUP_PATH~")) {
700                         ret = add_permission_app_path_type_rule(p_perm_to_app_path_type_stmt,
701                                                                 i_permission_id,
702                                                                 "GROUP_PATH",
703                                                                 s_access,
704                                                                 i_is_reverse);
705                         if(ret != PC_OPERATION_SUCCESS) goto finish;
706
707                 } else if(!strcmp(s_label, "~SETTINGS_PATH~")) {
708                         ret = add_permission_app_path_type_rule(p_perm_to_app_path_type_stmt,
709                                                                 i_permission_id,
710                                                                 "SETTINGS_PATH",
711                                                                 s_access,
712                                                                 i_is_reverse);
713                         if(ret != PC_OPERATION_SUCCESS) goto finish;
714                 }
715         }
716
717         ret = PC_OPERATION_SUCCESS;
718
719 finish:
720         if(p_perm_to_label_stmt &&
721             sqlite3_finalize(p_perm_to_label_stmt) != SQLITE_OK) {
722                 C_LOGE("RDB: Error during finalizing statement: %s",
723                        sqlite3_errmsg(p_db));
724         }
725
726         if(p_perm_to_perm_stmt &&
727             sqlite3_finalize(p_perm_to_perm_stmt) != SQLITE_OK) {
728                 C_LOGE("RDB: Error during finalizing statement: %s",
729                        sqlite3_errmsg(p_db));
730         }
731
732         if(p_perm_to_app_path_type_stmt &&
733             sqlite3_finalize(p_perm_to_app_path_type_stmt) != SQLITE_OK) {
734                 C_LOGE("RDB: Error during finalizing statement: %s",
735                        sqlite3_errmsg(p_db));
736         }
737         return ret;
738 }
739
740
741 int get_app_id_internal(sqlite3 *p_db,
742                         int *pi_app_id,
743                         const char *const s_app_label_name)
744 {
745         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
746
747         int ret = PC_ERR_DB_OPERATION;
748         sqlite3_stmt *p_stmt = NULL;
749
750         ret = prepare_stmt(p_db, &p_stmt,
751                            "SELECT application_view.app_id \
752                              FROM application_view \
753                              WHERE application_view.name = %Q LIMIT 1",
754                            s_app_label_name);
755
756         if(ret != PC_OPERATION_SUCCESS) goto finish;
757
758         ret = sqlite3_step(p_stmt);
759         if(ret == SQLITE_ROW) {
760                 ret = PC_OPERATION_SUCCESS;
761                 *pi_app_id = sqlite3_column_int(p_stmt, RDB_FIRST_COLUMN);
762
763         } else if(ret == SQLITE_DONE) {
764                 C_LOGW("RDB: There is no app_id for %s", s_app_label_name);
765                 ret = PC_ERR_DB_OPERATION;
766
767         } else {
768                 C_LOGE("RDB: Error during stepping: %s", sqlite3_errmsg(p_db));
769                 ret = PC_ERR_DB_QUERY_STEP;
770         }
771
772 finish:
773         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
774                 C_LOGE("RDB: Error during finalizing statement: %s",
775                        sqlite3_errmsg(p_db));
776         return ret;
777 }
778
779
780 int add_app_permission_internal(sqlite3 *p_db,
781                                 int i_app_id,
782                                 const char *const s_permission_name,
783                                 const char *const s_permission_type_name,
784                                 const bool b_is_volatile_new,
785                                 const bool b_is_enabled_new)
786 {
787         RDB_LOG_ENTRY_PARAM("%d %s %s %d %d", i_app_id,
788                             s_permission_name, s_permission_type_name,
789                             b_is_volatile_new, b_is_enabled_new);
790
791
792         int ret = PC_ERR_DB_OPERATION;
793         sqlite3_stmt *p_stmt = NULL;
794
795         ret = prepare_stmt(p_db, &p_stmt,
796                            "INSERT INTO                                  \
797                             app_permission_view(app_id, name, type_name, \
798                             is_volatile, is_enabled)                     \
799                             VALUES(%d,%Q,%Q,%d,%d)",
800                            i_app_id, s_permission_name, s_permission_type_name,
801                            (int)b_is_volatile_new, (int)b_is_enabled_new);
802
803         if(ret != PC_OPERATION_SUCCESS) goto finish;
804
805         ret = step_and_convert_returned_value(p_stmt);
806 finish:
807         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
808                 C_LOGE("RDB: Error during finalizing statement: %s",
809                        sqlite3_errmsg(p_db));
810         return ret;
811 }
812
813
814 int switch_app_permission_internal(sqlite3 *p_db,
815                                    const int i_app_id,
816                                    const char *const s_permission_name,
817                                    const char *const s_permission_type_name,
818                                    const bool b_is_enabled_new)
819 {
820         RDB_LOG_ENTRY_PARAM("%d %s %s %d", i_app_id,
821                             s_permission_name, s_permission_type_name,
822                             b_is_enabled_new);
823
824         int ret = PC_ERR_DB_OPERATION;
825         sqlite3_stmt *p_stmt = NULL;
826
827         ret = prepare_stmt(p_db, &p_stmt,
828                            "UPDATE app_permission_view \
829                             SET    is_enabled=%d       \
830                             WHERE  app_id = %d  AND    \
831                                    name =%Q AND        \
832                                    type_name=%Q",
833                            b_is_enabled_new, i_app_id,
834                            s_permission_name, s_permission_type_name);
835
836         if(ret != PC_OPERATION_SUCCESS) goto finish;
837         ret = step_and_convert_returned_value(p_stmt);
838 finish:
839         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
840                 C_LOGE("RDB: Error during finalizing statement: %s",
841                        sqlite3_errmsg(p_db));
842         return ret;
843 }
844
845
846 int update_app_permission_internal(sqlite3 *p_db,
847                                    const int i_app_id,
848                                    const int i_permission_id,
849                                    const bool b_is_volatile_new,
850                                    const bool b_is_enabled_new)
851 {
852         RDB_LOG_ENTRY_PARAM("%d %d %d %d",
853                             i_app_id, i_permission_id,
854                             b_is_volatile_new, b_is_enabled_new);
855
856         int ret = PC_ERR_DB_OPERATION;
857         sqlite3_stmt *p_stmt = NULL;
858
859         ret = prepare_stmt(p_db, &p_stmt,
860                            "UPDATE app_permission \
861                              SET is_volatile = %d, is_enabled=%d \
862                              WHERE app_id = %d AND permission_id = %d",
863                            b_is_volatile_new, b_is_enabled_new,
864                            i_app_id, i_permission_id);
865
866         if(ret != PC_OPERATION_SUCCESS) goto finish;
867         ret = step_and_convert_returned_value(p_stmt);
868 finish:
869         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
870                 C_LOGE("RDB: Error during finalizing statement: %s",
871                        sqlite3_errmsg(p_db));
872         return ret;
873 }
874
875
876 int change_app_permission_internal(sqlite3 *p_db,
877                                    int i_app_id,
878                                    const char *const s_permission_name,
879                                    const char *const s_permission_type_name,
880                                    int i_is_volatile_new,
881                                    int i_is_enabled_new)
882 {
883         RDB_LOG_ENTRY_PARAM("%d %s %s %d %d", i_app_id,
884                             s_permission_name, s_permission_type_name,
885                             i_is_volatile_new, i_is_enabled_new);
886
887         int ret = PC_ERR_DB_OPERATION;
888         sqlite3_stmt *p_stmt = NULL;
889         int i_is_volatile_old, i_is_enabled_old, i_permission_id;
890
891         ret = prepare_stmt(p_db, &p_stmt,
892                            "SELECT is_volatile, is_enabled, permission_id      \
893                             FROM    app_permission_list_view                   \
894                             WHERE   app_id = %d AND                            \
895                             permission_name=%Q AND                             \
896                             permission_type_name=%Q LIMIT 1",
897                            i_app_id, s_permission_name, s_permission_type_name);
898         if(ret != PC_OPERATION_SUCCESS) goto finish;
899
900         ret = sqlite3_step(p_stmt);
901         if(ret == SQLITE_ROW) {
902                 // Phi, I already have this permission...
903                 i_is_volatile_old = sqlite3_column_int(p_stmt, RDB_FIRST_COLUMN);
904                 i_is_enabled_old = sqlite3_column_int(p_stmt, RDB_SECOND_COLUMN);
905
906                 if(i_is_volatile_old == 1 && i_is_volatile_new == 0) {
907                         // Confucius say, No man can down-cast volatility.
908                         C_LOGE("RDB: Down-casting volatility is forbidden.");
909                         ret = PC_ERR_DB_PERM_FORBIDDEN;
910                         goto finish;
911                 }
912
913                 if(i_is_volatile_old == i_is_volatile_new &&
914                     i_is_enabled_old == i_is_enabled_new) {
915                         // There is no change. Nice.
916                         C_LOGD("RDB: Permission %s %s already exists.", s_permission_name, s_permission_type_name);
917                         ret = PC_OPERATION_SUCCESS;
918                         goto finish;
919                 }
920
921                 i_permission_id = sqlite3_column_int(p_stmt, RDB_THIRD_COLUMN);
922
923                 // Finalize statement
924                 if(sqlite3_finalize(p_stmt) != SQLITE_OK)
925                         C_LOGE("RDB: Error during finalizing statement: %s",
926                                sqlite3_errmsg(p_db));
927                 p_stmt = NULL;
928
929                 C_LOGD("RDB: Updating permission %s %s to application.", s_permission_name, s_permission_type_name);
930                 ret = update_app_permission_internal(p_db,
931                                                      i_app_id,
932                                                      i_permission_id,
933                                                      i_is_volatile_new,
934                                                      i_is_enabled_new);
935
936         } else if(ret == SQLITE_DONE) {
937                 // Wow! A brand new permission! Omnomnom...
938
939                 if(sqlite3_finalize(p_stmt) != SQLITE_OK)
940                         C_LOGE("RDB: Error during finalizing statement: %s",
941                                sqlite3_errmsg(p_db));
942                 p_stmt = NULL;
943
944                 C_LOGD("RDB: Adding permission %s %s to application.", s_permission_name, s_permission_type_name);
945                 ret = add_app_permission_internal(p_db,
946                                                   i_app_id,
947                                                   s_permission_name,
948                                                   s_permission_type_name,
949                                                   i_is_volatile_new,
950                                                   i_is_enabled_new);
951         } else {
952                 C_LOGE("RDB: Error during stepping: %s", sqlite3_errmsg(p_db));
953                 ret = PC_ERR_DB_QUERY_STEP;
954         }
955
956 finish:
957         if(p_stmt && sqlite3_finalize(p_stmt) != SQLITE_OK)
958                 C_LOGE("RDB: Error during finalizing statement: %s",
959                        sqlite3_errmsg(p_db));
960         return ret;
961 }
962
963
964 int revoke_app_permissions_internal(sqlite3 *p_db,
965                                     const char *const s_app_label_name)
966 {
967         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
968
969         int ret = PC_ERR_DB_OPERATION;
970         sqlite3_stmt *p_stmt = NULL;
971
972         ret = prepare_stmt(p_db, &p_stmt,
973                            "DELETE FROM app_permission_view \
974                             WHERE app_permission_view.app_name=%Q;",
975                            s_app_label_name);
976
977         if(ret != PC_OPERATION_SUCCESS) goto finish;
978
979         ret = step_and_convert_returned_value(p_stmt);
980 finish:
981         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
982                 C_LOGE("RDB: Error during finalizing statement: %s",
983                        sqlite3_errmsg(p_db));
984         return ret;
985 }
986
987
988 int reset_app_permissions_internal(sqlite3 *p_db,
989                                    const char *const s_app_label_name)
990 {
991         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
992
993         int ret = PC_ERR_DB_OPERATION;
994         sqlite3_stmt *p_stmt = NULL;
995
996         ret = prepare_stmt(p_db, &p_stmt,
997                            "DELETE FROM app_permission_volatile_view \
998                              WHERE app_permission_volatile_view.app_name=%Q;",
999                            s_app_label_name);
1000
1001         if(ret != PC_OPERATION_SUCCESS) goto finish;
1002
1003         ret = step_and_convert_returned_value(p_stmt);
1004 finish:
1005         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
1006                 C_LOGE("RDB: Error during finalizing statement: %s",
1007                        sqlite3_errmsg(p_db));
1008         return ret;
1009 }
1010
1011 int update_rules_in_db(sqlite3 *p_db)
1012 {
1013         RDB_LOG_ENTRY;
1014
1015         if(sqlite3_exec(p_db,
1016                         "\
1017                         -- clean temporary tables\n                                             \
1018                         DELETE FROM all_smack_binary_rules_modified;                            \
1019                         DELETE FROM current_smack_rule_modified;                                \
1020                         DELETE FROM history_smack_rule_modified;                                \
1021                                                                                                 \
1022                         -- gather possibly modified rules\n                                     \
1023                         INSERT INTO all_smack_binary_rules_modified                             \
1024                         SELECT subject, object, access, is_volatile                             \
1025                         FROM   all_smack_binary_rules_view                                      \
1026                         WHERE  subject IN modified_label;                                       \
1027                                                                                                 \
1028                         INSERT INTO all_smack_binary_rules_modified                             \
1029                         SELECT subject, object, access, is_volatile                             \
1030                         FROM   all_smack_binary_rules_view                                      \
1031                         WHERE  object IN modified_label AND subject NOT IN modified_label;      \
1032                                                                                                 \
1033                         -- prepare aggregated rules for diff algorithm\n                        \
1034                         INSERT INTO current_smack_rule_modified                                 \
1035                         SELECT subject, object, bitwise_or(access)                              \
1036                         FROM   all_smack_binary_rules_modified                                  \
1037                         GROUP BY subject, object                                                \
1038                         ORDER BY subject, object ASC;                                           \
1039                                                                                                 \
1040                         INSERT INTO history_smack_rule_modified                                 \
1041                         SELECT subject, object, bitwise_or(access)                              \
1042                         FROM   all_smack_binary_rules                                           \
1043                         WHERE  subject IN modified_label OR object IN modified_label            \
1044                         GROUP BY subject, object                                                \
1045                         ORDER BY subject, object ASC;                                           \
1046                                                                                                 \
1047                         -- apply changes to all_smack_binary_rules\n                            \
1048                         DELETE FROM all_smack_binary_rules                                      \
1049                         WHERE  subject IN modified_label OR                                     \
1050                                object IN modified_label;                                        \
1051                                                                                                 \
1052                         INSERT INTO all_smack_binary_rules                                      \
1053                         SELECT subject, object, access, is_volatile                             \
1054                         FROM   all_smack_binary_rules_modified;                                 \
1055                                                                                                 \
1056                         -- cleanup\n                                                            \
1057                         DELETE FROM modified_label;                                             \
1058                         ",
1059                         0, 0, 0) != SQLITE_OK) {
1060                 C_LOGE("RDB: Error during updating rules: %s",
1061                        sqlite3_errmsg(p_db));
1062                 return PC_ERR_DB_OPERATION;
1063         }
1064         return PC_OPERATION_SUCCESS;
1065 }
1066
1067 int update_smack_rules(sqlite3 *p_db)
1068 {
1069         RDB_LOG_ENTRY;
1070
1071         int ret = PC_OPERATION_SUCCESS;
1072         sqlite3_stmt *p_stmt = NULL;
1073         const unsigned char *s_subject    = NULL;
1074         const unsigned char *s_object     = NULL;
1075         const unsigned char *s_access_add = NULL;
1076         const unsigned char *s_access_del = NULL;
1077         struct smack_accesses *smack = NULL;
1078
1079         if(smack_accesses_new(&smack)) {
1080                 C_LOGE("RDB: Error during updating smack rules: smack_accesses_new failed.");
1081                 ret = PC_ERR_MEM_OPERATION;
1082                 goto finish;
1083         }
1084
1085         ret = prepare_stmt(p_db, &p_stmt,
1086                            "SELECT * from modified_smack_rules;");
1087         if(ret != PC_OPERATION_SUCCESS) goto finish;
1088
1089         while((ret = sqlite3_step(p_stmt)) == SQLITE_ROW) {
1090                 s_subject    = sqlite3_column_text(p_stmt, RDB_FIRST_COLUMN);
1091                 s_object     = sqlite3_column_text(p_stmt, RDB_SECOND_COLUMN);
1092                 s_access_add = sqlite3_column_text(p_stmt, RDB_THIRD_COLUMN);
1093                 s_access_del = sqlite3_column_text(p_stmt, RDB_FOURTH_COLUMN);
1094
1095                 C_LOGD("RDB: Added rule to smack:: %s %s %s %s",
1096                        s_subject, s_object, s_access_add, s_access_del);
1097
1098                 if(smack_accesses_add_modify(smack,
1099                                              (const char *) s_subject,
1100                                              (const char *) s_object,
1101                                              (const char *) s_access_add,
1102                                              (const char *) s_access_del)) {
1103                         C_LOGE("RDB: Error during updating smack rules: %s",
1104                                sqlite3_errmsg(p_db));
1105                         ret = PC_ERR_INVALID_OPERATION;
1106                         goto finish;
1107                 }
1108         }
1109         if(ret == SQLITE_DONE) {
1110                 ret = PC_OPERATION_SUCCESS;
1111         } else {
1112                 C_LOGE("RDB: Error during updating smack rules [%d]: %s",
1113                        ret, sqlite3_errmsg(p_db));
1114                 ret = PC_ERR_DB_OPERATION;
1115         }
1116
1117         if(smack_accesses_apply(smack)) {
1118                 C_LOGE("RDB: Error in smack_accesses_apply");
1119                 ret = PC_ERR_INVALID_OPERATION;
1120         }
1121
1122 finish:
1123         if(sqlite3_finalize(p_stmt) != SQLITE_OK)
1124                 C_LOGE("RDB: Error during finalizing statement: %s",
1125                        sqlite3_errmsg(p_db));
1126
1127         smack_accesses_free(smack);
1128         return ret;
1129 }