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