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