a16c646a01183cb92fc48ced0816fb2e9f77d16c
[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) < 0)
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) < 0)
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) < 0)
139                 C_LOGE("RDB: Error during finalizing statement: %s",
140                        sqlite3_errmsg(p_db));
141         return ret;
142 }
143
144 /**
145  * Function called when the target database is busy.
146  * We attempt to access the database every
147  * RDB_TIME_BETWEEN_ATTEMPTS seconds
148  *
149  * @param  not_used  not used
150  * @param  i_attempt number of the attempt
151  * @return           0 when stops waiting
152  *                   1 when waiting
153  */
154 static int database_busy_handler(void *not_used UNUSED,
155                                  int i_attempt)
156 {
157         if(i_attempt > RDB_MAX_QUERY_ATTEMPTS) {
158                 // I ain't gonna wait for you forever!
159                 C_LOGE("RDB: Database busy for too long.");
160                 return 0;
161         }
162         C_LOGW("RDB: Database busy, waiting");
163         sleep(RDB_TIME_BETWEEN_ATTEMPTS);
164         return 1;
165 }
166
167
168 int open_rdb_connection(sqlite3 **p_db)
169 {
170         RDB_LOG_ENTRY;
171
172         char *p_err_msg;
173
174         // Open connection:
175         int ret = sqlite3_open_v2(RDB_PATH,
176                                   p_db,
177                                   RDB_READWRITE_FLAG,
178                                   NULL);
179         if(*p_db == NULL) {
180                 C_LOGE("RDB: Error opening the database: Unable to allocate memory.");
181                 return PC_ERR_DB_CONNECTION;
182         }
183         if(ret != SQLITE_OK) {
184                 C_LOGE("RDB: Error opening the database: %s", sqlite3_errmsg(*p_db));
185                 return PC_ERR_DB_CONNECTION;
186         }
187
188         //Register busy handler:
189         if(sqlite3_busy_handler(*p_db, database_busy_handler, NULL) != SQLITE_OK) {
190                 C_LOGE("RDB: Error opening the database: %s", sqlite3_errmsg(*p_db));
191                 return PC_ERR_DB_CONNECTION;
192         }
193
194         // Load extensions:
195         if(sqlite3_enable_load_extension(*p_db, 1)) {
196                 C_LOGE("RDB: Error enabling extensions: %s", sqlite3_errmsg(*p_db));
197                 return PC_ERR_DB_CONNECTION;
198         }
199
200         if(sqlite3_load_extension(*p_db,
201                                   "/usr/lib/librules-db-sql-udf.so", 0,
202                                   &p_err_msg) != SQLITE_OK) {
203
204                 C_LOGE("RDB: Error during loading librules-db-sql-udf.so: %s",
205                        p_err_msg);
206                 sqlite3_free(p_err_msg);
207                 return PC_ERR_DB_CONNECTION;
208         }
209         sqlite3_free(p_err_msg);
210
211
212         // Create the temporary tables:
213         if(sqlite3_exec(*p_db,
214                         "PRAGMA foreign_keys = ON;                                 \
215                                                                                    \
216                         CREATE TEMPORARY TABLE modified_label(                     \
217                                 name VARCHAR NOT NULL PRIMARY KEY);                \
218                                                                                    \
219                         CREATE TEMPORARY TABLE all_smack_binary_rules_modified(    \
220                                 subject TEXT NOT NULL,                             \
221                                 object  TEXT NOT NULL,                             \
222                                 access  INTEGER NOT NULL,                          \
223                                 is_volatile INTEGER NOT NULL);                     \
224                                                                                    \
225                         CREATE TEMPORARY TABLE current_smack_rule_modified(        \
226                                 subject VARCHAR NOT NULL,                          \
227                                 object  VARCHAR NOT NULL,                          \
228                                 access  INTEGER NOT NULL);                         \
229                                                                                    \
230                         CREATE TEMPORARY TABLE history_smack_rule_modified(        \
231                                 subject VARCHAR NOT NULL,                          \
232                                 object  VARCHAR NOT NULL,                          \
233                                 access  INTEGER NOT NULL);                         \
234                                                                                    \
235                         CREATE TEMPORARY VIEW modified_smack_rules AS              \
236                         SELECT  subject, object,                                   \
237                                 access_to_str(access_add) AS access_add,           \
238                                 access_to_str(access_del) AS access_del            \
239                         FROM    (                                                  \
240                                 SELECT     subject, object,                        \
241                                            s1.access & ~s2.access AS access_add,   \
242                                            s2.access & ~s1.access AS access_del    \
243                                 FROM       current_smack_rule_modified AS s1       \
244                                 INNER JOIN history_smack_rule_modified AS s2       \
245                                            USING (subject, object)                 \
246                                 WHERE      s1.access != s2.access                  \
247                                 UNION                                              \
248                                 SELECT     subject, object,                        \
249                                            s1.access AS access_add,                \
250                                            0 AS access_del                         \
251                                 FROM       current_smack_rule_modified s1          \
252                                 LEFT JOIN  history_smack_rule_modified s2          \
253                                            USING (subject, object)                 \
254                                 WHERE      s2.subject IS NULL AND                  \
255                                            s2.object  IS NULL                      \
256                                 UNION                                              \
257                                 SELECT     subject, object,                        \
258                                            0 AS access_add,                        \
259                                            s1.access AS access_del                 \
260                                 FROM       history_smack_rule_modified s1          \
261                                 LEFT JOIN  current_smack_rule_modified s2          \
262                                            USING (subject, object)                 \
263                                 WHERE      s2.subject IS NULL AND                  \
264                                            s2.object  IS NULL                      \
265                                 )                                                  \
266                         ORDER BY subject, object ASC;",
267                         0, 0, 0) != SQLITE_OK) {
268                 C_LOGE("RDB: Error during preparing script: %s", sqlite3_errmsg(*p_db));
269                 return PC_ERR_DB_OPERATION;
270         }
271
272         return PC_OPERATION_SUCCESS;
273 }
274
275
276 int prepare_stmt(sqlite3 *p_db,
277                  sqlite3_stmt **pp_stmt,
278                  const char *const s_sql,
279                  ...)
280 {
281         int ret = PC_ERR_DB_QUERY_PREP;
282         char *s_query = NULL;
283         va_list args;
284         va_start(args, s_sql);
285
286         s_query = sqlite3_vmprintf(s_sql, args);
287
288         if(s_query == NULL) {
289                 C_LOGE("RDB: Error during preparing statement: Unable to allocate enough memory.");
290                 ret = PC_ERR_DB_QUERY_PREP;
291                 goto finish;
292         }
293
294         if(sqlite3_prepare_v2(p_db,
295                               s_query,
296                               strlen(s_query) + 1,
297                               pp_stmt,
298                               NULL)) {
299                 C_LOGE("RDB: Error during preparing statement: %s", sqlite3_errmsg(p_db));
300                 ret = PC_ERR_DB_QUERY_PREP;
301                 goto finish;
302         }
303
304         if(*pp_stmt == NULL) {
305                 C_LOGE("RDB: Error during preparing statement: SQL statement is probably empty.");
306                 ret = PC_ERR_DB_QUERY_PREP;
307                 goto finish;
308         }
309
310         ret = PC_OPERATION_SUCCESS;
311
312 finish:
313         va_end(args);
314         sqlite3_free(s_query);
315         return ret;
316 }
317
318
319 int check_app_label_internal(sqlite3 *p_db,
320                              const char *const s_label_name)
321 {
322         RDB_LOG_ENTRY_PARAM("%s", s_label_name);
323
324         int ret = PC_ERR_DB_OPERATION;
325         sqlite3_stmt *p_stmt = NULL;
326
327         ret = prepare_stmt(p_db, &p_stmt,
328                            "SELECT 1                      \
329                             FROM application_view          \
330                             WHERE application_view.name=%Q \
331                             LIMIT 1",
332                            s_label_name);
333         if(ret != PC_OPERATION_SUCCESS) goto finish;
334
335         ret = sqlite3_step(p_stmt);
336         if(ret == SQLITE_ROW) {
337                 // There is such application label
338                 ret = PC_ERR_DB_LABEL_TAKEN;
339         } else if(ret == SQLITE_DONE) {
340                 // No such application label
341                 ret = PC_OPERATION_SUCCESS;
342         } else {
343                 C_LOGE("RDB: Error during stepping: %s", sqlite3_errmsg(p_db));
344                 ret = PC_ERR_DB_QUERY_STEP;
345         }
346 finish:
347         if(sqlite3_finalize(p_stmt) < 0)
348                 C_LOGE("RDB: Error during finalizing statement: %s",
349                        sqlite3_errmsg(p_db));
350         return ret;
351 }
352
353
354 int add_app_internal(sqlite3 *p_db,
355                      const char *const s_label_name)
356 {
357         RDB_LOG_ENTRY_PARAM("%s", s_label_name);
358
359         int ret = PC_ERR_DB_OPERATION;
360         sqlite3_stmt *p_stmt = NULL;
361
362         ret = prepare_stmt(p_db, &p_stmt,
363                            "INSERT into application_view(name) VALUES(%Q)",
364                            s_label_name);
365         if(ret != PC_OPERATION_SUCCESS) goto finish;
366
367         ret = step_and_convert_returned_value(p_stmt);
368 finish:
369         if(sqlite3_finalize(p_stmt) < 0)
370                 C_LOGE("RDB: Error during finalizing statement: %s",
371                        sqlite3_errmsg(p_db));
372         return ret;
373 }
374
375
376 int remove_app_internal(sqlite3 *p_db,
377                         const char *const s_label_name)
378 {
379         RDB_LOG_ENTRY_PARAM("%s", s_label_name);
380
381         int ret = PC_ERR_DB_OPERATION;
382         sqlite3_stmt *p_stmt = NULL;
383
384         ret = prepare_stmt(p_db, &p_stmt,
385                            "DELETE FROM application_view \
386                              WHERE application_view.name=%Q",
387                            s_label_name);
388
389         if(ret != PC_OPERATION_SUCCESS) goto finish;
390
391         ret = step_and_convert_returned_value(p_stmt);
392 finish:
393         if(sqlite3_finalize(p_stmt) < 0)
394                 C_LOGE("RDB: Error during finalizing statement: %s",
395                        sqlite3_errmsg(p_db));
396         return ret;
397 }
398
399
400 int add_path_internal(sqlite3 *p_db,
401                       const char *const s_owner_label_name,
402                       const char *const s_path_label_name,
403                       const char *const s_path,
404                       const char *const s_access,
405                       const char *const s_access_reverse,
406                       const char *const s_type)
407 {
408         RDB_LOG_ENTRY_PARAM("%s %s %s %s %s %s",
409                             s_owner_label_name, s_path_label_name,
410                             s_path, s_access, s_access_reverse, s_type);
411
412         int ret = PC_ERR_DB_OPERATION;
413         sqlite3_stmt *p_stmt = NULL;
414
415         ret = prepare_stmt(p_db, &p_stmt,
416                            "INSERT INTO path_view(owner_app_label_name, \
417                                                   path,                 \
418                                                   path_label_name,      \
419                                                   access,               \
420                                                   access_reverse,       \
421                                                   path_type_name)       \
422                              VALUES(%Q, %Q, %Q, %Q, %Q, %Q);",
423                            s_owner_label_name, s_path, s_path_label_name,
424                            s_access, s_access_reverse, s_type);
425         if(ret != PC_OPERATION_SUCCESS) goto finish;
426
427         ret = step_and_convert_returned_value(p_stmt);
428 finish:
429         if(sqlite3_finalize(p_stmt) < 0)
430                 C_LOGE("RDB: Error during finalizing statement: %s",
431                        sqlite3_errmsg(p_db));
432         return ret;
433 }
434
435
436 int add_permission_internal(sqlite3 *p_db,
437                             const char *const s_permission_name,
438                             const char *const s_permission_type_name)
439 {
440         RDB_LOG_ENTRY_PARAM("%s %s", s_permission_name, s_permission_type_name);
441
442         int ret = PC_ERR_DB_OPERATION;
443         sqlite3_stmt *p_stmt = NULL;
444
445         ret = prepare_stmt(p_db, &p_stmt,
446                            "INSERT INTO permission_view(name, type_name) \
447                            VALUES (%Q,%Q)",
448                            s_permission_name, s_permission_type_name);
449
450         if(ret != PC_OPERATION_SUCCESS) goto finish;
451
452         ret = step_and_convert_returned_value(p_stmt);
453 finish:
454         if(sqlite3_finalize(p_stmt) < 0)
455                 C_LOGE("RDB: Error during finalizing statement: %s",
456                        sqlite3_errmsg(p_db));
457         return ret;
458 }
459
460
461 int get_permission_id_internal(sqlite3 *p_db,
462                                const char *const s_permission_name,
463                                const char *const s_permission_type_name,
464                                sqlite3_int64 *p_permission_id)
465 {
466         RDB_LOG_ENTRY_PARAM("%s %s", s_permission_name, s_permission_type_name);
467
468         int ret = PC_ERR_DB_OPERATION;
469         sqlite3_stmt *p_stmt = NULL;
470
471         ret = prepare_stmt(p_db, &p_stmt,
472                            "SELECT permission_view.permission_id  \
473                             FROM   permission_view                \
474                             WHERE  permission_view.name = %Q AND  \
475                                    permission_view.type_name = %Q \
476                             LIMIT  1",
477                            s_permission_name, s_permission_type_name);
478         if(ret != PC_OPERATION_SUCCESS) goto finish;
479
480         ret = sqlite3_step(p_stmt);
481         if(ret == SQLITE_ROW) {
482                 ret = PC_OPERATION_SUCCESS;
483                 *p_permission_id = sqlite3_column_int(p_stmt, RDB_FIRST_COLUMN);
484         } else if(ret == SQLITE_DONE) {
485                 C_LOGW("RDB: There is no permission_id for %s %s", s_permission_name, s_permission_type_name);
486                 ret = PC_ERR_DB_OPERATION;
487
488         } else {
489                 C_LOGE("RDB: Error during stepping: %s", sqlite3_errmsg(p_db));
490                 ret = PC_ERR_DB_QUERY_STEP;
491         }
492
493 finish:
494         if(sqlite3_finalize(p_stmt) < 0)
495                 C_LOGE("RDB: Error during finalizing statement: %s",
496                        sqlite3_errmsg(p_db));
497
498         return ret;
499 }
500
501
502 int prepare_stmts_for_bind(sqlite3 *p_db,
503                            sqlite3_stmt **pp_stmt,
504                            const char *const s_query)
505 {
506         if(sqlite3_prepare_v2(p_db,
507                               s_query,
508                               strlen(s_query) + 1,
509                               pp_stmt,
510                               NULL)) {
511                 C_LOGE("RDB: Error during preparing statement: %s",
512                        sqlite3_errmsg(p_db));
513                 return PC_ERR_DB_QUERY_PREP;
514         }
515         return PC_OPERATION_SUCCESS;
516 }
517
518
519 static int add_permission_label_rule(sqlite3_stmt *p_stmt,
520                                      const sqlite3_int64 i_permission_id,
521                                      const char *const s_label_name,
522                                      const char *const s_access,
523                                      const int i_is_reverse)
524 {
525         int ret = PC_OPERATION_SUCCESS;
526
527         // Bind values to the statement and run it:
528         // Bind returns SQLITE_OK == 0 on success
529         if(sqlite3_bind_int(p_stmt, 1, i_permission_id) ||
530             sqlite3_bind_text(p_stmt, 2, s_access, RDB_AUTO_DETERM_SIZE, 0) ||
531             sqlite3_bind_text(p_stmt, 3, s_label_name, RDB_AUTO_DETERM_SIZE, 0) ||
532             sqlite3_bind_int(p_stmt, 4, i_is_reverse)) {
533                 C_LOGE("RDB: Error during binding to statement: %s",
534                        sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
535                 ret = PC_ERR_DB_QUERY_BIND;
536                 goto finish;
537         }
538
539         // Perform the insert
540         ret = step_and_convert_returned_value(p_stmt);
541
542 finish:
543         reset_and_unbind_stmt(p_stmt);
544         return ret;
545 }
546
547
548 static int add_permission_permission_rule(sqlite3_stmt *p_stmt,
549                 const sqlite3_int64 i_permission_id,
550                 const sqlite3_int64 i_target_permission_id,
551                 const char *const s_access,
552                 const int i_is_reverse)
553 {
554         int ret = PC_OPERATION_SUCCESS;
555
556         if(sqlite3_bind_int(p_stmt, 1, i_permission_id) ||
557             sqlite3_bind_int(p_stmt, 2, i_target_permission_id)  ||
558             sqlite3_bind_text(p_stmt, 3, s_access, RDB_AUTO_DETERM_SIZE, 0) ||
559             sqlite3_bind_int(p_stmt, 4, i_is_reverse)) {
560                 C_LOGE("RDB: Error during binding to statement: %s",
561                        sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
562                 ret = PC_ERR_DB_QUERY_BIND;
563                 goto finish;
564         }
565
566         ret = step_and_convert_returned_value(p_stmt);
567
568 finish:
569         reset_and_unbind_stmt(p_stmt);
570         return ret;
571 }
572
573
574 static int add_permission_app_path_type_rule(sqlite3_stmt *p_stmt,
575                 const sqlite3_int64 i_permission_id,
576                 const char *const s_path_type_name,
577                 const char *const s_access,
578                 const int i_is_reverse)
579 {
580         int ret = PC_OPERATION_SUCCESS;
581
582         if(sqlite3_bind_int(p_stmt, 1, i_permission_id) ||
583             sqlite3_bind_text(p_stmt, 2, s_path_type_name, RDB_AUTO_DETERM_SIZE, 0)  ||
584             sqlite3_bind_text(p_stmt, 3, s_access, RDB_AUTO_DETERM_SIZE, 0) ||
585             sqlite3_bind_int(p_stmt, 4, i_is_reverse)) {
586                 C_LOGE("RDB: Error during binding to statement: %s",
587                        sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
588                 ret = PC_ERR_DB_QUERY_BIND;
589                 goto finish;
590         }
591
592         ret = step_and_convert_returned_value(p_stmt);
593
594 finish:
595         reset_and_unbind_stmt(p_stmt);
596         return ret;
597 }
598
599 int add_permission_rules_internal(sqlite3 *p_db,
600                                   const sqlite3_int64 i_permission_id,
601                                   const char *const *const pp_smack_rules)
602 {
603         RDB_LOG_ENTRY;
604
605         int ret = PC_OPERATION_SUCCESS;
606         char s_label[SMACK_LABEL_LEN + 1];
607         char s_access[ACC_LEN + 1];
608         sqlite3_int64 i_all_apps_permission_id = 1;
609         int i_is_reverse = 0;
610         int i;
611         sqlite3_stmt *p_perm_to_label_stmt = NULL;
612         sqlite3_stmt *p_perm_to_perm_stmt = NULL;
613         sqlite3_stmt *p_perm_to_app_path_type_stmt = NULL;
614
615         // Prepare stmts. They are static, so we parse SQL only once per process and reuse it.
616         ret = prepare_stmts_for_bind(p_db, &p_perm_to_label_stmt,
617                                      "INSERT INTO permission_label_rule_view(        \
618                                       permission_id, access, label_name, is_reverse) \
619                                       VALUES(?,?,?,?)");
620         if(ret != PC_OPERATION_SUCCESS) goto finish;
621
622         ret = prepare_stmts_for_bind(p_db, &p_perm_to_perm_stmt,
623                                      "INSERT OR REPLACE INTO permission_permission_rule( \
624                                       permission_id, target_permission_id,               \
625                                       access, is_reverse)                                \
626                                       VALUES(?,?,str_to_access(?),?)");
627         if(ret != PC_OPERATION_SUCCESS) goto finish;
628
629
630         ret = prepare_stmts_for_bind(p_db, &p_perm_to_app_path_type_stmt,
631                                      "INSERT INTO permission_app_path_type_rule_view(        \
632                                       permission_id, app_path_type_name, access, is_reverse) \
633                                       VALUES(?,?,?,?)");
634         if(ret != PC_OPERATION_SUCCESS) goto finish;
635
636
637         for(i = 0; pp_smack_rules[i] != NULL ; ++i) {
638                 C_LOGD("RDB: Granting permission: %s", pp_smack_rules[i]);
639
640                 // Ignore empty lines
641                 if(strspn(pp_smack_rules[i], " \t\n") == strlen(pp_smack_rules[i]))
642                         continue;
643
644                 ret = parse_rule(pp_smack_rules[i], s_label, s_access, &i_is_reverse);
645                 if(ret != PC_OPERATION_SUCCESS) goto finish;
646
647                 // Interpret wildcards
648                 if(s_label[0] != '~' &&
649                     s_label[strlen(s_label) - 1] != '~') {
650                         // It's not a wildcard!
651                         ret = add_permission_label_rule(p_perm_to_label_stmt,
652                                                         i_permission_id,
653                                                         s_label,
654                                                         s_access,
655                                                         i_is_reverse);
656                         if(ret != PC_OPERATION_SUCCESS) goto finish;
657
658                 } else if(!strcmp(s_label, "~ALL_APPS~")) {
659                         ret = get_permission_id_internal(p_db,
660                                                          "ALL_APPS",
661                                                          "ALL_APPS",
662                                                          &i_all_apps_permission_id);
663                         if(ret != PC_OPERATION_SUCCESS) goto finish;
664
665                         ret = add_permission_permission_rule(p_perm_to_perm_stmt,
666                                                              i_permission_id,
667                                                              i_all_apps_permission_id,
668                                                              s_access,
669                                                              i_is_reverse);
670                         if(ret != PC_OPERATION_SUCCESS) goto finish;
671
672                 } else if(!strcmp(s_label, "~ALL_APPS_WITH_SAME_PERMISSION~")) {
673                         ret = add_permission_permission_rule(p_perm_to_perm_stmt,
674                                                              i_permission_id,
675                                                              i_permission_id,
676                                                              s_access,
677                                                              i_is_reverse);
678                         if(ret != PC_OPERATION_SUCCESS) goto finish;
679
680                 } else if(!strcmp(s_label, "~PUBLIC_PATH~")) {
681                         ret = add_permission_app_path_type_rule(p_perm_to_app_path_type_stmt,
682                                                                 i_permission_id,
683                                                                 "PUBLIC_PATH",
684                                                                 s_access,
685                                                                 i_is_reverse);
686                         if(ret != PC_OPERATION_SUCCESS) goto finish;
687
688                 } else if(!strcmp(s_label, "~GROUP_PATH~")) {
689                         ret = add_permission_app_path_type_rule(p_perm_to_app_path_type_stmt,
690                                                                 i_permission_id,
691                                                                 "GROUP_PATH",
692                                                                 s_access,
693                                                                 i_is_reverse);
694                         if(ret != PC_OPERATION_SUCCESS) goto finish;
695
696                 } else if(!strcmp(s_label, "~SETTINGS_PATH~")) {
697                         ret = add_permission_app_path_type_rule(p_perm_to_app_path_type_stmt,
698                                                                 i_permission_id,
699                                                                 "SETTINGS_PATH",
700                                                                 s_access,
701                                                                 i_is_reverse);
702                         if(ret != PC_OPERATION_SUCCESS) goto finish;
703                 }
704         }
705
706         ret = PC_OPERATION_SUCCESS;
707
708 finish:
709         if(p_perm_to_label_stmt &&
710             sqlite3_finalize(p_perm_to_label_stmt) < 0) {
711                 C_LOGE("RDB: Error during finalizing statement: %s",
712                        sqlite3_errmsg(p_db));
713         }
714
715         if(p_perm_to_perm_stmt &&
716             sqlite3_finalize(p_perm_to_perm_stmt) < 0) {
717                 C_LOGE("RDB: Error during finalizing statement: %s",
718                        sqlite3_errmsg(p_db));
719         }
720
721         if(p_perm_to_app_path_type_stmt &&
722             sqlite3_finalize(p_perm_to_app_path_type_stmt) < 0) {
723                 C_LOGE("RDB: Error during finalizing statement: %s",
724                        sqlite3_errmsg(p_db));
725         }
726         return ret;
727 }
728
729 static int add_label_app_path_type_rule(sqlite3_stmt *p_stmt,
730                                         const char *const s_label_name,
731                                         const char *const s_path_type_name,
732                                         const char *const s_access,
733                                         const int i_is_reverse)
734 {
735         int ret = PC_OPERATION_SUCCESS;
736
737         if(sqlite3_bind_text(p_stmt, 1, s_label_name, RDB_AUTO_DETERM_SIZE, 0) ||
738             sqlite3_bind_text(p_stmt, 2, s_path_type_name, RDB_AUTO_DETERM_SIZE, 0)  ||
739             sqlite3_bind_text(p_stmt, 3, s_access, RDB_AUTO_DETERM_SIZE, 0) ||
740             sqlite3_bind_int(p_stmt, 4, i_is_reverse)) {
741                 C_LOGE("RDB: Error during binding to statement: %s",
742                        sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
743                 ret = PC_ERR_DB_QUERY_BIND;
744                 goto finish;
745         }
746
747         ret = step_and_convert_returned_value(p_stmt);
748
749 finish:
750         reset_and_unbind_stmt(p_stmt);
751         return ret;
752 }
753
754
755 int add_additional_rules_internal(sqlite3 *p_db, const char *const *const pp_smack_rules)
756 {
757         RDB_LOG_ENTRY;
758         int ret = PC_OPERATION_SUCCESS;
759         size_t i;
760         char s_subject[SMACK_LABEL_LEN + 1];
761         char s_object[SMACK_LABEL_LEN + 1];
762         char s_access[ACC_LEN + 1];
763         sqlite3_stmt *p_label_to_app_path_type_stmt = NULL;
764         int is_reverse = 0;
765         char *ps_subject, *ps_object;
766
767         // Clear the label_app_path_type_rule table
768         if(sqlite3_exec(p_db, "DELETE FROM label_app_path_type_rule_view;", 0, 0, 0) != SQLITE_OK) {
769                 C_LOGE("RDB: Error during clearing additional rules: %s", sqlite3_errmsg(p_db));
770                 ret = PC_ERR_DB_OPERATION;
771                 goto finish;
772         }
773
774         ret = prepare_stmts_for_bind(p_db, &p_label_to_app_path_type_stmt,
775                                      "INSERT INTO label_app_path_type_rule_view(          \
776                                       label_name, app_path_type_name, access, is_reverse) \
777                                       VALUES(?,?,?,?)");
778         if(ret != PC_OPERATION_SUCCESS) goto finish;
779
780         // Add rules to the database
781         for(i = 0; pp_smack_rules[i] != NULL ; ++i) {
782
783                 // Ignore empty lines
784                 if(strspn(pp_smack_rules[i], " \t\n") == strlen(pp_smack_rules[i]))
785                         continue;
786
787                 // Tokenize
788                 ret = tokenize_rule(pp_smack_rules[i], s_subject , s_object, s_access);
789                 if(ret != PC_OPERATION_SUCCESS) goto finish;
790
791                 if(is_wildcard(s_subject)) {
792                         ps_subject = s_object;
793                         ps_object = s_subject;
794                         is_reverse = 1;
795                 } else {
796                         ps_subject = s_subject;
797                         ps_object = s_object;
798                         is_reverse = 0;
799                 }
800
801                 // Check validity
802                 if(!smack_label_is_valid(ps_subject)) {
803                         C_LOGE("Subject is not a valid label");
804                         ret = PC_ERR_INVALID_PARAM;
805                         goto finish;
806                 }
807
808                 // Add access to paths
809                 if(!strcmp(ps_object, "~PUBLIC_PATH~")) {
810                         ret = add_label_app_path_type_rule(p_label_to_app_path_type_stmt,
811                                                            ps_subject,
812                                                            "PUBLIC_PATH",
813                                                            s_access,
814                                                            is_reverse);
815                         if(ret != PC_OPERATION_SUCCESS) goto finish;
816
817                 } else if(!strcmp(ps_object, "~GROUP_PATH~")) {
818                         ret = add_label_app_path_type_rule(p_label_to_app_path_type_stmt,
819                                                            ps_subject,
820                                                            "GROUP_PATH",
821                                                            s_access,
822                                                            is_reverse);
823                         if(ret != PC_OPERATION_SUCCESS) goto finish;
824
825                 } else if(!strcmp(ps_object, "~SETTINGS_PATH~")) {
826                         ret = add_label_app_path_type_rule(p_label_to_app_path_type_stmt,
827                                                            ps_subject,
828                                                            "SETTINGS_PATH",
829                                                            s_access,
830                                                            is_reverse);
831                         if(ret != PC_OPERATION_SUCCESS) goto finish;
832                 } else if(!strcmp(ps_object, "~NPRUNTIME_PATH~")) {
833                         ret = add_label_app_path_type_rule(p_label_to_app_path_type_stmt,
834                                                            ps_subject,
835                                                            "NPRUNTIME_PATH",
836                                                            s_access,
837                                                            is_reverse);
838                         if(ret != PC_OPERATION_SUCCESS) goto finish;
839                 }
840
841
842                 // Mark label as modified
843                 ret = add_modified_label_internal(p_db, ps_subject);
844                 if(ret != PC_OPERATION_SUCCESS) goto finish;
845         }
846
847 finish:
848         if(p_label_to_app_path_type_stmt &&
849             sqlite3_finalize(p_label_to_app_path_type_stmt) < 0)
850                 C_LOGE("RDB: Error during finalizing statement: %s",
851                        sqlite3_errmsg(p_db));
852         return ret;
853 }
854
855 int check_app_has_permission_internal(sqlite3 *p_db,
856                                       const char *const s_app_label_name,
857                                       const char *const s_permission_name,
858                                       const char *const s_permission_type_name,
859                                       bool *const p_is_enabled)
860 {
861         RDB_LOG_ENTRY_PARAM("%s %s %s", s_app_label_name,
862                             s_permission_name, s_permission_type_name);
863
864         int ret = PC_ERR_DB_OPERATION;
865         sqlite3_stmt *p_stmt = NULL;
866
867         ret = prepare_stmt(p_db, &p_stmt,
868                            "SELECT is_enabled              \
869                             FROM   app_permission_view     \
870                             WHERE  app_name = %Q AND       \
871                                    name = %Q AND           \
872                                    type_name = %Q          \
873                             LIMIT  1",
874                            s_app_label_name, s_permission_name, s_permission_type_name);
875         if(ret != PC_OPERATION_SUCCESS) goto finish;
876
877         ret = sqlite3_step(p_stmt);
878         if(ret == SQLITE_ROW) {
879                 ret = PC_OPERATION_SUCCESS;
880                 //store the result
881                 *p_is_enabled = (bool)sqlite3_column_int(p_stmt, RDB_FIRST_COLUMN);
882         } else if(ret == SQLITE_DONE) {
883                 //no entry == permission not assigned
884                 C_LOGD("RDB: Permission: %s of type: %s is not assigned to app: %s",
885                        s_permission_name, s_permission_type_name, s_app_label_name);
886                 ret = PC_OPERATION_SUCCESS;
887                 *p_is_enabled = false;
888         } else if(ret == SQLITE_BUSY) {
889                 //base locked in exclusive mode for too long
890                 C_LOGE("RDB: Database is busy. RDB Connection Error returned.");
891                 ret = PC_ERR_DB_CONNECTION;
892         } else {
893                 C_LOGE("RDB: Error during stepping: %s", sqlite3_errmsg(p_db));
894                 ret = PC_ERR_DB_QUERY_STEP;
895         }
896
897 finish:
898         if(sqlite3_finalize(p_stmt) < 0)
899                 C_LOGE("RDB: Error during finalizing statement: %s",
900                        sqlite3_errmsg(p_db));
901         return ret;
902 }
903
904 int get_app_id_internal(sqlite3 *p_db,
905                         int *pi_app_id,
906                         const char *const s_app_label_name)
907 {
908         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
909
910         int ret = PC_ERR_DB_OPERATION;
911         sqlite3_stmt *p_stmt = NULL;
912
913         ret = prepare_stmt(p_db, &p_stmt,
914                            "SELECT application_view.app_id \
915                              FROM application_view \
916                              WHERE application_view.name = %Q",
917                            s_app_label_name);
918
919         if(ret != PC_OPERATION_SUCCESS) goto finish;
920
921         ret = sqlite3_step(p_stmt);
922         if(ret == SQLITE_ROW) {
923                 ret = PC_OPERATION_SUCCESS;
924                 *pi_app_id = sqlite3_column_int(p_stmt, RDB_FIRST_COLUMN);
925
926         } else if(ret == SQLITE_DONE) {
927                 C_LOGW("RDB: There is no app_id for %s", s_app_label_name);
928                 ret = PC_ERR_DB_OPERATION;
929
930         } else {
931                 C_LOGE("RDB: Error during stepping: %s", sqlite3_errmsg(p_db));
932                 ret = PC_ERR_DB_QUERY_STEP;
933         }
934
935 finish:
936         if(sqlite3_finalize(p_stmt) < 0)
937                 C_LOGE("RDB: Error during finalizing statement: %s",
938                        sqlite3_errmsg(p_db));
939         return ret;
940 }
941
942
943 int add_app_permission_internal(sqlite3 *p_db,
944                                 int i_app_id,
945                                 const char *const s_permission_name,
946                                 const char *const s_permission_type_name,
947                                 const bool b_is_volatile_new,
948                                 const bool b_is_enabled_new)
949 {
950         RDB_LOG_ENTRY_PARAM("%d %s %s %d %d", i_app_id,
951                             s_permission_name, s_permission_type_name,
952                             b_is_volatile_new, b_is_enabled_new);
953
954
955         int ret = PC_ERR_DB_OPERATION;
956         sqlite3_stmt *p_stmt = NULL;
957
958         ret = prepare_stmt(p_db, &p_stmt,
959                            "INSERT INTO                                  \
960                             app_permission_view(app_id, name, type_name, \
961                             is_volatile, is_enabled)                     \
962                             VALUES(%d,%Q,%Q,%d,%d)",
963                            i_app_id, s_permission_name, s_permission_type_name,
964                            (int)b_is_volatile_new, (int)b_is_enabled_new);
965
966         if(ret != PC_OPERATION_SUCCESS) goto finish;
967
968         ret = step_and_convert_returned_value(p_stmt);
969 finish:
970         if(sqlite3_finalize(p_stmt) < 0)
971                 C_LOGE("RDB: Error during finalizing statement: %s",
972                        sqlite3_errmsg(p_db));
973         return ret;
974 }
975
976
977 int switch_app_permission_internal(sqlite3 *p_db,
978                                    const int i_app_id,
979                                    const char *const s_permission_name,
980                                    const char *const s_permission_type_name,
981                                    const bool b_is_enabled_new)
982 {
983         RDB_LOG_ENTRY_PARAM("%d %s %s %d", i_app_id,
984                             s_permission_name, s_permission_type_name,
985                             b_is_enabled_new);
986
987         int ret = PC_ERR_DB_OPERATION;
988         sqlite3_stmt *p_stmt = NULL;
989
990         ret = prepare_stmt(p_db, &p_stmt,
991                            "UPDATE app_permission_view \
992                             SET    is_enabled=%d       \
993                             WHERE  app_id = %d  AND    \
994                                    name =%Q AND        \
995                                    type_name=%Q",
996                            b_is_enabled_new, i_app_id,
997                            s_permission_name, s_permission_type_name);
998
999         if(ret != PC_OPERATION_SUCCESS) goto finish;
1000         ret = step_and_convert_returned_value(p_stmt);
1001 finish:
1002         if(sqlite3_finalize(p_stmt) < 0)
1003                 C_LOGE("RDB: Error during finalizing statement: %s",
1004                        sqlite3_errmsg(p_db));
1005         return ret;
1006 }
1007
1008
1009 int update_app_permission_internal(sqlite3 *p_db,
1010                                    const int i_app_id,
1011                                    const int i_permission_id,
1012                                    const bool b_is_volatile_new,
1013                                    const bool b_is_enabled_new)
1014 {
1015         RDB_LOG_ENTRY_PARAM("%d %d %d %d",
1016                             i_app_id, i_permission_id,
1017                             b_is_volatile_new, b_is_enabled_new);
1018
1019         int ret = PC_ERR_DB_OPERATION;
1020         sqlite3_stmt *p_stmt = NULL;
1021
1022         ret = prepare_stmt(p_db, &p_stmt,
1023                            "UPDATE app_permission \
1024                              SET is_volatile = %d, is_enabled=%d \
1025                              WHERE app_id = %d AND permission_id = %d",
1026                            b_is_volatile_new, b_is_enabled_new,
1027                            i_app_id, i_permission_id);
1028
1029         if(ret != PC_OPERATION_SUCCESS) goto finish;
1030         ret = step_and_convert_returned_value(p_stmt);
1031 finish:
1032         if(sqlite3_finalize(p_stmt) < 0)
1033                 C_LOGE("RDB: Error during finalizing statement: %s",
1034                        sqlite3_errmsg(p_db));
1035         return ret;
1036 }
1037
1038
1039 int change_app_permission_internal(sqlite3 *p_db,
1040                                    int i_app_id,
1041                                    const char *const s_permission_name,
1042                                    const char *const s_permission_type_name,
1043                                    int i_is_volatile_new,
1044                                    int i_is_enabled_new)
1045 {
1046         RDB_LOG_ENTRY_PARAM("%d %s %s %d %d", i_app_id,
1047                             s_permission_name, s_permission_type_name,
1048                             i_is_volatile_new, i_is_enabled_new);
1049
1050         int ret = PC_ERR_DB_OPERATION;
1051         sqlite3_stmt *p_stmt = NULL;
1052         int i_is_volatile_old, i_is_enabled_old, i_permission_id;
1053
1054         ret = prepare_stmt(p_db, &p_stmt,
1055                            "SELECT is_volatile, is_enabled, permission_id      \
1056                              FROM    app_permission_list_view                   \
1057                              WHERE   app_id = %d AND                            \
1058                              permission_name=%Q AND                             \
1059                              permission_type_name=%Q LIMIT 1",
1060                            i_app_id, s_permission_name, s_permission_type_name);
1061         if(ret != PC_OPERATION_SUCCESS) goto finish;
1062
1063         ret = sqlite3_step(p_stmt);
1064         if(ret == SQLITE_ROW) {
1065                 // Phi, I already have this permission...
1066                 i_is_volatile_old = sqlite3_column_int(p_stmt, RDB_FIRST_COLUMN);
1067                 i_is_enabled_old = sqlite3_column_int(p_stmt, RDB_SECOND_COLUMN);
1068
1069                 if(i_is_volatile_old == 1 && i_is_volatile_new == 0) {
1070                         // Confucius say, No man can down-cast volatility.
1071                         C_LOGE("RDB: Down-casting volatility is forbidden.");
1072                         ret = PC_ERR_DB_PERM_FORBIDDEN;
1073                         goto finish;
1074                 }
1075
1076                 if(i_is_volatile_old == i_is_volatile_new &&
1077                     i_is_enabled_old == i_is_enabled_new) {
1078                         // There is no change. Nice.
1079                         C_LOGD("RDB: Permission %s %s already exists.", s_permission_name, s_permission_type_name);
1080                         ret = PC_OPERATION_SUCCESS;
1081                         goto finish;
1082                 }
1083
1084                 i_permission_id = sqlite3_column_int(p_stmt, RDB_THIRD_COLUMN);
1085
1086                 // Finalize statement
1087                 if(sqlite3_finalize(p_stmt) < 0)
1088                         C_LOGE("RDB: Error during finalizing statement: %s",
1089                                sqlite3_errmsg(p_db));
1090                 p_stmt = NULL;
1091
1092                 C_LOGD("RDB: Updating permission %s %s to application.", s_permission_name, s_permission_type_name);
1093                 ret = update_app_permission_internal(p_db,
1094                                                      i_app_id,
1095                                                      i_permission_id,
1096                                                      i_is_volatile_new,
1097                                                      i_is_enabled_new);
1098
1099         } else if(ret == SQLITE_DONE) {
1100                 // Wow! A brand new permission! Omnomnom...
1101
1102                 if(sqlite3_finalize(p_stmt) < 0)
1103                         C_LOGE("RDB: Error during finalizing statement: %s",
1104                                sqlite3_errmsg(p_db));
1105                 p_stmt = NULL;
1106
1107                 C_LOGD("RDB: Adding permission %s %s to application.", s_permission_name, s_permission_type_name);
1108                 ret = add_app_permission_internal(p_db,
1109                                                   i_app_id,
1110                                                   s_permission_name,
1111                                                   s_permission_type_name,
1112                                                   i_is_volatile_new,
1113                                                   i_is_enabled_new);
1114         } else {
1115                 C_LOGE("RDB: Error during stepping: %s", sqlite3_errmsg(p_db));
1116                 ret = PC_ERR_DB_QUERY_STEP;
1117         }
1118
1119 finish:
1120         if(p_stmt && sqlite3_finalize(p_stmt) < 0)
1121                 C_LOGE("RDB: Error during finalizing statement: %s",
1122                        sqlite3_errmsg(p_db));
1123         return ret;
1124 }
1125
1126
1127 int revoke_app_permissions_internal(sqlite3 *p_db,
1128                                     const char *const s_app_label_name)
1129 {
1130         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
1131
1132         int ret = PC_ERR_DB_OPERATION;
1133         sqlite3_stmt *p_stmt = NULL;
1134
1135         ret = prepare_stmt(p_db, &p_stmt,
1136                            "DELETE FROM app_permission_view \
1137                             WHERE app_permission_view.app_name=%Q;",
1138                            s_app_label_name);
1139
1140         if(ret != PC_OPERATION_SUCCESS) goto finish;
1141
1142         ret = step_and_convert_returned_value(p_stmt);
1143 finish:
1144         if(sqlite3_finalize(p_stmt) < 0)
1145                 C_LOGE("RDB: Error during finalizing statement: %s",
1146                        sqlite3_errmsg(p_db));
1147         return ret;
1148 }
1149
1150
1151 int reset_app_permissions_internal(sqlite3 *p_db,
1152                                    const char *const s_app_label_name)
1153 {
1154         RDB_LOG_ENTRY_PARAM("%s", s_app_label_name);
1155
1156         int ret = PC_ERR_DB_OPERATION;
1157         sqlite3_stmt *p_stmt = NULL;
1158
1159         ret = prepare_stmt(p_db, &p_stmt,
1160                            "DELETE FROM app_permission_volatile_view \
1161                              WHERE app_permission_volatile_view.app_name=%Q;",
1162                            s_app_label_name);
1163
1164         if(ret != PC_OPERATION_SUCCESS) goto finish;
1165
1166         ret = step_and_convert_returned_value(p_stmt);
1167 finish:
1168         if(sqlite3_finalize(p_stmt) < 0)
1169                 C_LOGE("RDB: Error during finalizing statement: %s",
1170                        sqlite3_errmsg(p_db));
1171         return ret;
1172 }
1173
1174 int update_rules_in_db(sqlite3 *p_db)
1175 {
1176         RDB_LOG_ENTRY;
1177
1178         if(sqlite3_exec(p_db,
1179                         "\
1180                         -- clean temporary tables\n                                             \
1181                         DELETE FROM all_smack_binary_rules_modified;                            \
1182                         DELETE FROM current_smack_rule_modified;                                \
1183                         DELETE FROM history_smack_rule_modified;                                \
1184                                                                                                 \
1185                         -- gather possibly modified rules\n                                     \
1186                         INSERT INTO all_smack_binary_rules_modified                             \
1187                         SELECT subject, object, access, is_volatile                             \
1188                         FROM   all_smack_binary_rules_view                                      \
1189                         WHERE  subject IN modified_label;                                       \
1190                                                                                                 \
1191                         INSERT INTO all_smack_binary_rules_modified                             \
1192                         SELECT subject, object, access, is_volatile                             \
1193                         FROM   all_smack_binary_rules_view                                      \
1194                         WHERE  object IN modified_label AND subject NOT IN modified_label;      \
1195                                                                                                 \
1196                         -- prepare aggregated rules for diff algorithm\n                        \
1197                         INSERT INTO current_smack_rule_modified                                 \
1198                         SELECT subject, object, bitwise_or(access)                              \
1199                         FROM   all_smack_binary_rules_modified                                  \
1200                         GROUP BY subject, object                                                \
1201                         ORDER BY subject, object ASC;                                           \
1202                                                                                                 \
1203                         INSERT INTO history_smack_rule_modified                                 \
1204                         SELECT subject, object, bitwise_or(access)                              \
1205                         FROM   all_smack_binary_rules                                           \
1206                         WHERE  subject IN modified_label OR object IN modified_label            \
1207                         GROUP BY subject, object                                                \
1208                         ORDER BY subject, object ASC;                                           \
1209                                                                                                 \
1210                         -- apply changes to all_smack_binary_rules\n                            \
1211                         DELETE FROM all_smack_binary_rules                                      \
1212                         WHERE  subject IN modified_label OR                                     \
1213                                object IN modified_label;                                        \
1214                                                                                                 \
1215                         INSERT INTO all_smack_binary_rules                                      \
1216                         SELECT subject, object, access, is_volatile                             \
1217                         FROM   all_smack_binary_rules_modified;                                 \
1218                                                                                                 \
1219                         -- cleanup\n                                                            \
1220                         DELETE FROM modified_label;                                             \
1221                         ",
1222                         0, 0, 0) != SQLITE_OK) {
1223                 C_LOGE("RDB: Error during updating rules: %s",
1224                        sqlite3_errmsg(p_db));
1225                 return PC_ERR_DB_OPERATION;
1226         }
1227         return PC_OPERATION_SUCCESS;
1228 }
1229
1230 int update_smack_rules(sqlite3 *p_db)
1231 {
1232         RDB_LOG_ENTRY;
1233
1234         int ret = PC_OPERATION_SUCCESS;
1235         sqlite3_stmt *p_stmt = NULL;
1236         const unsigned char *s_subject    = NULL;
1237         const unsigned char *s_object     = NULL;
1238         const unsigned char *s_access_add = NULL;
1239         const unsigned char *s_access_del = NULL;
1240         struct smack_accesses *smack = NULL;
1241
1242         if(smack_accesses_new(&smack)) {
1243                 C_LOGE("RDB: Error during updating smack rules: smack_accesses_new failed.");
1244                 ret = PC_ERR_MEM_OPERATION;
1245                 goto finish;
1246         }
1247
1248         ret = prepare_stmt(p_db, &p_stmt,
1249                            "SELECT * from modified_smack_rules;");
1250         if(ret != PC_OPERATION_SUCCESS) goto finish;
1251
1252         while((ret = sqlite3_step(p_stmt)) == SQLITE_ROW) {
1253                 s_subject    = sqlite3_column_text(p_stmt, RDB_FIRST_COLUMN);
1254                 s_object     = sqlite3_column_text(p_stmt, RDB_SECOND_COLUMN);
1255                 s_access_add = sqlite3_column_text(p_stmt, RDB_THIRD_COLUMN);
1256                 s_access_del = sqlite3_column_text(p_stmt, RDB_FOURTH_COLUMN);
1257
1258                 C_LOGD("RDB: Added rule to smack:: %s %s %s %s",
1259                        s_subject, s_object, s_access_add, s_access_del);
1260
1261                 if(smack_accesses_add_modify(smack,
1262                                              (const char *) s_subject,
1263                                              (const char *) s_object,
1264                                              (const char *) s_access_add,
1265                                              (const char *) s_access_del)) {
1266                         C_LOGE("RDB: Error during updating smack rules: %s",
1267                                sqlite3_errmsg(p_db));
1268                         ret = PC_ERR_INVALID_OPERATION;
1269                         goto finish;
1270                 }
1271         }
1272         if(ret == SQLITE_DONE) {
1273                 ret = PC_OPERATION_SUCCESS;
1274         } else {
1275                 C_LOGE("RDB: Error during updating smack rules [%d]: %s",
1276                        ret, sqlite3_errmsg(p_db));
1277                 ret = PC_ERR_DB_OPERATION;
1278         }
1279
1280         if(smack_accesses_apply(smack)) {
1281                 C_LOGE("RDB: Error in smack_accesses_apply");
1282                 ret = PC_ERR_INVALID_OPERATION;
1283         }
1284
1285 finish:
1286         if(sqlite3_finalize(p_stmt) < 0)
1287                 C_LOGE("RDB: Error during finalizing statement: %s",
1288                        sqlite3_errmsg(p_db));
1289
1290         smack_accesses_free(smack);
1291         return ret;
1292 }