Implement perm_app_get_permissions() API in libprivilege-control.
[platform/core/security/libprivilege-control.git] / src / rules-db.c
index 2da074a..26e84e5 100644 (file)
 static sqlite3 *p_db__          = NULL;
 static int i_session_ret_code__ = PC_OPERATION_SUCCESS;
 
+typedef enum {
+       RDB_TRANSACTION_EXCLUSIVE,
+       RDB_TRANSACTION_SHARED_READ
+} rdb_transaction_type_t;
+
 /**
  * Prepare to modify the database.
  *
  * @ingroup RDB internal functions
  *
- * @param  pp_db pointer to a pointer to a SQLite3 database object
- * @return       PC_OPERATION_SUCCESS on success,
- *               error code otherwise
+ * @param   pp_db             pointer to a pointer to a SQLite3 database object
+ * @param   transaction_type  indicates whether the transaction is exclusive or shared
+ * @return                    PC_OPERATION_SUCCESS on success, error code otherwise
  */
-static int rdb_begin(sqlite3 **pp_db)
+static int rdb_begin(sqlite3 **pp_db, rdb_transaction_type_t transaction_type)
 {
        RDB_LOG_ENTRY;
 
@@ -56,73 +61,123 @@ static int rdb_begin(sqlite3 **pp_db)
        int ret = open_rdb_connection(pp_db);
        if(ret != PC_OPERATION_SUCCESS) return ret;
 
-       if(sqlite3_exec(*pp_db, "BEGIN EXCLUSIVE TRANSACTION", 0, 0, 0)
-           != SQLITE_OK) {
+       if(transaction_type == RDB_TRANSACTION_EXCLUSIVE) {
+               ret = sqlite3_exec(*pp_db, "BEGIN EXCLUSIVE TRANSACTION", 0, 0, 0);
+       }
+       else if(transaction_type == RDB_TRANSACTION_SHARED_READ) {
+               ret = sqlite3_exec(*pp_db, "BEGIN DEFERRED TRANSACTION", 0, 0, 0);
+       }
+       else {
+               C_LOGE("RDB: Bad transaction type specified: %d",
+                      (int)transaction_type);
+               return PC_ERR_INVALID_PARAM;
+       }
+
+       if(ret != SQLITE_OK) {
                C_LOGE("RDB: Error during transaction begin: %s",
                       sqlite3_errmsg(*pp_db));
                return PC_ERR_DB_CONNECTION;
        }
 
-       ret = save_smack_rules(*pp_db);
-       if(ret != PC_OPERATION_SUCCESS) return ret;
-
-       return PC_OPERATION_SUCCESS;
+       return ret;
 }
 
 
 /**
- * Finish database modification.
+ * Commit database modification.
  * If previous operation returned an error try to rollback changes.
  *
  * @ingroup RDB internal functions
  *
- * @param  p_db pointer to a SQLite3 database object
- * @param  ret  previous return code
+ * @param  p_db           pointer to a SQLite3 database object
+ * @param  i_session_ret  session return code
+ * @return                PC_OPERATION_SUCCESS on success,
+ *                        error code otherwise
  */
-static void rdb_end(sqlite3 *p_db, int ret)
+static int rdb_end(sqlite3 *p_db, int i_session_ret)
 {
        RDB_LOG_ENTRY;
 
-       if(ret == PC_OPERATION_SUCCESS &&
-           (ret = update_rules_in_db(p_db))
-           != PC_OPERATION_SUCCESS) {
-               C_LOGE("RDB: Error during updating rules in the database: %d", ret);;
-       }
+       int ret = PC_OPERATION_SUCCESS;
+
+       // No error during the session, make updates
+       if(i_session_ret == PC_OPERATION_SUCCESS) {
+               ret = update_rules_in_db(p_db);
+               if(ret != PC_OPERATION_SUCCESS) {
+                       C_LOGE("RDB: Error during updating rules in the database: %d", ret);
+                       goto finish;
+               }
 
-       if(have_smack()) {
-               if(ret == PC_OPERATION_SUCCESS &&
-                   (ret = update_smack_rules(p_db))
-                   != PC_OPERATION_SUCCESS) {
-                       C_LOGE("RDB: Error updating smack rules: %d", ret);
+               if(have_smack()) {
+                       ret = update_smack_rules(p_db);
+                       if(ret != PC_OPERATION_SUCCESS) {
+                               C_LOGE("RDB: Error updating smack rules: %d", ret);
+                               goto finish;
+                       }
                }
        }
 
-       // Finish transaction
-       C_LOGD("RDB: Closing connection.");
-       if(ret == PC_OPERATION_SUCCESS) {
+finish:
+       // End transaction in a way
+       // that depends on the ret and i_session_ret code.
+       if(i_session_ret == PC_OPERATION_SUCCESS &&
+           ret == PC_OPERATION_SUCCESS) {
                if(sqlite3_exec(p_db, "COMMIT TRANSACTION", 0, 0, 0)
                    != SQLITE_OK) {
                        C_LOGE("RDB: Error during transaction commit: %s",
                               sqlite3_errmsg(p_db));
+                       ret = PC_ERR_DB_CONNECTION;
                }
-       } else if(ret == PC_ERR_DB_CONNECTION) {
-               /* Life is pointless. I can't even rollback...*/
+
+       } else if(i_session_ret == PC_ERR_DB_CONNECTION ||
+                 ret == PC_ERR_DB_CONNECTION) {
+               // Life is pointless. I can't even rollback...
                C_LOGE("RDB: No rollback nor commit.");
-       } else if(sqlite3_exec(p_db, "ROLLBACK TRANSACTION", 0, 0, 0)
-                 != SQLITE_OK) {
-               C_LOGE("RDB: Error during transaction rollback: %s",
-                      sqlite3_errmsg(p_db));
+               ret = PC_ERR_DB_CONNECTION;
+
+       } else {
+               // Some other error code
+               if(sqlite3_exec(p_db, "ROLLBACK TRANSACTION", 0, 0, 0)
+                   != SQLITE_OK) {
+                       C_LOGE("RDB: Error during transaction rollback: %s",
+                              sqlite3_errmsg(p_db));
+                       if(ret == PC_OPERATION_SUCCESS)
+                               ret = PC_ERR_DB_CONNECTION;
+               }
        }
 
        if(sqlite3_close(p_db)) {
-               C_LOGE("RDB: Error during closing the database.");
+               C_LOGE("RDB: Error during closing the database. Error: %s",
+                      sqlite3_errmsg(p_db));
+               if(ret == PC_OPERATION_SUCCESS)
+                       ret = PC_ERR_DB_CONNECTION;
        }
-}
 
+       return ret;
+}
 
-static void update_ret_code(int i_ret)
+/**
+ * Finish database modification.
+ * If global transaction is opened update session return code,
+ * otherwise end the transaction.
+ *
+ * @ingroup RDB internal functions
+ *
+ * @param  p_db           pointer to a SQLite3 database object
+ * @param  i_session_ret  session return code
+ * @return                PC_OPERATION_SUCCESS on success,
+ *                        error code otherwise
+ */
+static int rdb_finish(sqlite3 *p_db, int i_session_ret)
 {
-       i_session_ret_code__ = i_session_ret_code__ ? i_session_ret_code__ : i_ret;
+       if(p_db__) {
+               if(i_session_ret_code__ == PC_OPERATION_SUCCESS)
+                       i_session_ret_code__ = i_session_ret;
+               return i_session_ret;
+       } else {
+               int ret = rdb_end(p_db, i_session_ret);
+               return i_session_ret != PC_OPERATION_SUCCESS ? i_session_ret : ret;
+       }
 }
 
 
@@ -134,16 +189,19 @@ int rdb_modification_start(void)
                rdb_modification_finish();
        }
 
-       return rdb_begin(&p_db__);
+       return rdb_begin(&p_db__, RDB_TRANSACTION_EXCLUSIVE);
 }
 
 
-void rdb_modification_finish(void)
+int rdb_modification_finish(void)
 {
        if(p_db__) {
-               rdb_end(p_db__, i_session_ret_code__);
+               int ret = rdb_end(p_db__, i_session_ret_code__);
                p_db__ = NULL;
                i_session_ret_code__ = PC_OPERATION_SUCCESS;
+               return ret;
+       } else {
+               return PC_OPERATION_SUCCESS;
        }
 }
 
@@ -155,7 +213,7 @@ int rdb_add_application(const char *const s_label_name)
        int ret = PC_ERR_DB_OPERATION;
        sqlite3 *p_db = NULL;
 
-       ret = rdb_begin(&p_db);
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        ret = check_app_label_internal(p_db, s_label_name);
@@ -170,9 +228,9 @@ int rdb_add_application(const char *const s_label_name)
        }
 
        ret = add_modified_label_internal(p_db, s_label_name);
+
 finish:
-       if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
-       return ret;
+       return rdb_finish(p_db, ret);
 }
 
 
@@ -183,19 +241,19 @@ int rdb_remove_application(const char *const s_label_name)
        int ret = PC_ERR_DB_OPERATION;
        sqlite3 *p_db = NULL;
 
-       ret = rdb_begin(&p_db);
-       if(ret != PC_OPERATION_SUCCESS) goto finish;
-
-       ret = remove_app_internal(p_db, s_label_name);
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        ret = add_modified_label_internal(p_db, s_label_name);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        ret = add_modified_apps_path_internal(p_db, s_label_name);
+       if(ret != PC_OPERATION_SUCCESS) goto finish;
+
+       ret = remove_app_internal(p_db, s_label_name);
+
 finish:
-       if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
-       return ret;
+       return rdb_finish(p_db, ret);
 }
 
 
@@ -203,16 +261,17 @@ int rdb_add_path(const char *const s_owner_label_name,
                 const char *const s_path_label_name,
                 const char *const s_path,
                 const char *const s_access,
+                const char *const s_access_reverse,
                 const char *const s_type)
 {
-       RDB_LOG_ENTRY_PARAM("%s %s %s %s %s",
+       RDB_LOG_ENTRY_PARAM("%s %s %s %s %s %s",
                            s_owner_label_name, s_path_label_name,
-                           s_path, s_access, s_type);
+                           s_path, s_access, s_access_reverse, s_type);
 
        int ret = PC_ERR_DB_OPERATION;
        sqlite3 *p_db = NULL;
 
-       ret = rdb_begin(&p_db);
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        ret = add_path_internal(p_db,
@@ -220,13 +279,43 @@ int rdb_add_path(const char *const s_owner_label_name,
                                s_path_label_name,
                                s_path,
                                s_access,
+                               s_access_reverse,
                                s_type);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        ret = add_modified_label_internal(p_db, s_path_label_name);
+
 finish:
-       if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
-       return ret;
+       return rdb_finish(p_db, ret);
+}
+
+
+int rdb_get_app_paths(const char *const s_app_label_name,
+                     const char *const s_app_path_type_name,
+                     char ***ppp_paths)
+{
+       RDB_LOG_ENTRY_PARAM("%s %s", s_app_label_name, s_app_path_type_name);
+
+       int ret;
+       int i_num_paths;
+       sqlite3 *p_db = NULL;
+
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_SHARED_READ);
+       if (ret != PC_OPERATION_SUCCESS) goto finish;
+
+       ret = get_app_paths_count_internal(p_db,
+                                          s_app_label_name,
+                                          s_app_path_type_name,
+                                          &i_num_paths);
+       if (ret != PC_OPERATION_SUCCESS) goto finish;
+
+       ret = get_app_paths_internal(p_db, s_app_label_name,
+                                    s_app_path_type_name,
+                                    i_num_paths,
+                                    ppp_paths);
+
+finish:
+       return rdb_finish(p_db, ret);
 }
 
 
@@ -240,7 +329,7 @@ int rdb_add_permission_rules(const char *const s_permission_name,
        sqlite3 *p_db = NULL;
        sqlite3_int64 permission_id = -1;
 
-       ret = rdb_begin(&p_db);
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        ret = add_permission_internal(p_db,
@@ -264,26 +353,27 @@ int rdb_add_permission_rules(const char *const s_permission_name,
        }
 
 finish:
-       if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
-       return ret;
+       return rdb_finish(p_db, ret);
 }
 
 
 int rdb_enable_app_permissions(const char *const s_app_label_name,
-                              const char *const s_permission_type_name,
+                              const app_type_t i_permission_type,
                               const char *const *const pp_permissions_list,
                               const bool   b_is_volatile)
 {
-       RDB_LOG_ENTRY_PARAM("%s %s %d", s_app_label_name, s_permission_type_name, b_is_volatile);
+       RDB_LOG_ENTRY_PARAM("%s %d %d", s_app_label_name, i_permission_type, (int)b_is_volatile);
 
        int ret = PC_ERR_DB_OPERATION;
        sqlite3 *p_db = NULL;
        char *s_permission_name = NULL;
        int i;
        int i_app_id = 0;
-       C_LOGD("RDB: Enabling permissions START");
 
-       ret = rdb_begin(&p_db);
+       const char *s_permission_type_name = app_type_name(i_permission_type);
+       const char *s_permission_group_type_name = app_type_group_name(i_permission_type);
+
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        ret = get_app_id_internal(p_db, &i_app_id, s_app_label_name);
@@ -299,7 +389,7 @@ int rdb_enable_app_permissions(const char *const s_app_label_name,
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        // Add permissions from the list:
-       for(i = 0; pp_permissions_list[i] != NULL ; ++i) {
+       for(i = 0; pp_permissions_list[i] != NULL; ++i) {
                // Ignore empty lines
                if(strspn(pp_permissions_list[i], " \t\n")
                    == strlen(pp_permissions_list[i]))
@@ -311,32 +401,33 @@ int rdb_enable_app_permissions(const char *const s_app_label_name,
                ret = change_app_permission_internal(p_db,
                                                     i_app_id,
                                                     s_permission_name,
-                                                    s_permission_type_name,
+                                                    s_permission_group_type_name,
                                                     b_is_volatile,
                                                     RDB_ENABLE);
-               if(ret != PC_OPERATION_SUCCESS) goto finish;
                free(s_permission_name);
+               if(ret != PC_OPERATION_SUCCESS) goto finish;
        }
 
        ret = add_modified_label_internal(p_db, s_app_label_name);
+
 finish:
-       if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
-       return ret;
+       return rdb_finish(p_db, ret);
 }
 
 
 int rdb_disable_app_permissions(const char *const s_app_label_name,
-                               const char *const s_permission_type_name,
+                               const app_type_t i_permission_type,
                                const char *const *const pp_permissions_list)
 {
-       RDB_LOG_ENTRY_PARAM("%s %s", s_app_label_name, s_permission_type_name);
+       RDB_LOG_ENTRY_PARAM("%s %d", s_app_label_name, i_permission_type);
 
        int ret = PC_ERR_DB_OPERATION;
        sqlite3 *p_db = NULL;
        char *s_permission_name = NULL;
        int i, i_app_id;
+       const char *s_permission_group_type_name = app_type_group_name(i_permission_type);
 
-       ret = rdb_begin(&p_db);
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        ret = get_app_id_internal(p_db, &i_app_id, s_app_label_name);
@@ -354,17 +445,16 @@ int rdb_disable_app_permissions(const char *const s_app_label_name,
                ret = switch_app_permission_internal(p_db,
                                                     i_app_id,
                                                     s_permission_name,
-                                                    s_permission_type_name,
+                                                    s_permission_group_type_name,
                                                     RDB_DISABLE);
-               if(ret != PC_OPERATION_SUCCESS) goto finish;
-
                free(s_permission_name);
+               if(ret != PC_OPERATION_SUCCESS) goto finish;
        }
 
        ret = add_modified_label_internal(p_db, s_app_label_name);
+
 finish:
-       if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
-       return ret;
+       return rdb_finish(p_db, ret);
 }
 
 
@@ -375,16 +465,19 @@ int rdb_revoke_app_permissions(const char *const s_app_label_name)
        int ret = PC_ERR_DB_OPERATION;
        sqlite3 *p_db = NULL;
 
-       ret = rdb_begin(&p_db);
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
-       ret = revoke_app_permissions_internal(p_db, s_app_label_name);
+       ret = add_modified_label_internal(p_db, s_app_label_name);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
-       ret = add_modified_label_internal(p_db, s_app_label_name);
+       ret = add_modified_apps_path_internal(p_db, s_app_label_name);
+       if(ret != PC_OPERATION_SUCCESS) goto finish;
+
+       ret = revoke_app_permissions_internal(p_db, s_app_label_name);
+
 finish:
-       if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
-       return ret;
+       return rdb_finish(p_db, ret);
 }
 
 
@@ -395,66 +488,91 @@ int rdb_reset_app_permissions(const char *const s_app_label_name)
        int ret = PC_ERR_DB_OPERATION;
        sqlite3 *p_db = NULL;
 
-       ret = rdb_begin(&p_db);
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        ret = reset_app_permissions_internal(p_db, s_app_label_name);
        if(ret != PC_OPERATION_SUCCESS) goto finish;
 
        ret = add_modified_label_internal(p_db, s_app_label_name);
+
 finish:
-       if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
-       return ret;
+       return rdb_finish(p_db, ret);
 }
 
 
-int validate_all_rules(const char *const *const pp_permissions_list)
+int rdb_add_additional_rules(const char *const *const pp_smack_rules)
 {
        RDB_LOG_ENTRY;
 
-       int i;
-       char s_subject[SMACK_LABEL_LEN + 1];
-       char s_object[SMACK_LABEL_LEN + 1];
-       char s_access[ACC_LEN + 1];
+       int ret = PC_ERR_DB_OPERATION;
+       sqlite3 *p_db = NULL;
 
-       // Parse and check rules.
-       for(i = 0; pp_permissions_list[i] != NULL; ++i) {
-               // C_LOGE("RDB: Validating rules: %s", pp_permissions_list[i]);
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_EXCLUSIVE);
+       if(ret != PC_OPERATION_SUCCESS) goto finish;
 
-               // Ignore empty lines
-               if(strspn(pp_permissions_list[i], " \t\n")
-                   == strlen(pp_permissions_list[i]))
-                       continue;
+       // Old rules may disappear, so mark as modified
+       ret = add_modified_additional_rules_internal(p_db);
+       if(ret != PC_OPERATION_SUCCESS) goto finish;
 
-               if(parse_rule(pp_permissions_list[i], s_subject, s_object, s_access)
-                   != PC_OPERATION_SUCCESS) {
-                       C_LOGE("RDB: Invalid parameter");
-                       return PC_ERR_INVALID_PARAM;
-               }
+       ret = add_additional_rules_internal(p_db, pp_smack_rules);
+       if(ret != PC_OPERATION_SUCCESS) goto finish;
 
-               if(strcmp(s_subject, SMACK_APP_LABEL_TEMPLATE) != 0 &&
-                   strcmp(s_object, SMACK_APP_LABEL_TEMPLATE) != 0) {
-                       C_LOGE("RDB: There is no " SMACK_APP_LABEL_TEMPLATE " argument in template rule.");
-                       return PC_ERR_INVALID_PARAM;
-               }
+       // New rules appear, so also mark as modified
+       ret = add_modified_additional_rules_internal(p_db);
 
-               if(strcmp(s_subject, SMACK_APP_LABEL_TEMPLATE) == 0 &&
-                   strcmp(s_object, SMACK_APP_LABEL_TEMPLATE) == 0) {
-                       C_LOGE("RDB: Rule with two " SMACK_APP_LABEL_TEMPLATE " has no sense.");
-                       return PC_ERR_INVALID_PARAM;
-               }
+finish:
+       return rdb_finish(p_db, ret);
+}
 
-               // Check the other label
-               if(strcmp(s_subject, SMACK_APP_LABEL_TEMPLATE) == 0 &&
-                   !smack_label_is_valid(s_object)) {
-                       C_LOGE("RDB: Incorrect object label: %s", s_object);
-                       return PC_ERR_INVALID_PARAM;
-               } else if(strcmp(s_object, SMACK_APP_LABEL_TEMPLATE) == 0 &&
-                         !smack_label_is_valid(s_subject)) {
-                       C_LOGE("RDB: Incorrect subject label: %s", s_subject);
-                       return PC_ERR_INVALID_PARAM;
-               }
-       }
+int rdb_app_has_permission(const char *const s_app_label_name,
+                          const char *const s_permission_type_name,
+                          const char *const s_permission_name,
+                          bool *const p_is_enabled)
+{
+       RDB_LOG_ENTRY_PARAM("%s %s %s", s_app_label_name,
+                           s_permission_type_name, s_permission_name);
+       int ret = PC_ERR_DB_OPERATION;
+       sqlite3 *p_db = NULL;
 
-       return PC_OPERATION_SUCCESS;
-}
\ No newline at end of file
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_SHARED_READ); //shared readonly transaction
+       if(ret != PC_OPERATION_SUCCESS) goto finish;
+
+       ret = check_app_has_permission_internal(p_db,
+                                               s_app_label_name,
+                                               s_permission_name,
+                                               s_permission_type_name,
+                                               p_is_enabled);
+
+finish:
+       return rdb_finish(p_db, ret);
+}
+
+int rdb_app_get_permissions(const char *const s_app_label_name,
+                           const char *const s_permission_type_name,
+                           char ***ppp_perm_list)
+{
+       RDB_LOG_ENTRY_PARAM("%s %s", s_app_label_name, s_permission_type_name);
+
+       int ret = PC_ERR_DB_OPERATION;
+       int i_num_permissions;
+       sqlite3 *p_db = NULL;
+
+       ret = rdb_begin(&p_db, RDB_TRANSACTION_SHARED_READ);
+       if(ret != PC_OPERATION_SUCCESS) goto finish;
+
+       ret = get_app_permissions_number_internal(p_db,
+                                                 s_app_label_name,
+                                                 s_permission_type_name,
+                                                 &i_num_permissions);
+       if (ret != PC_OPERATION_SUCCESS) goto finish;
+
+       ret = get_app_permissions_internal(p_db,
+                                          s_app_label_name,
+                                          s_permission_type_name,
+                                          i_num_permissions,
+                                          ppp_perm_list);
+
+finish:
+       return rdb_finish(p_db, ret);
+}