#define API_FEATURE_LOADER_VERSION "1.0"
-#define ACC_LEN 6
#define API_FEATURES_DIR "/usr/share/privilege-control/"
#define API_FEATURE_LOADER_LOG(format, ...) if(i_verbose_flag__) printf(format, ##__VA_ARGS__)
has_smack_ext(entry->d_name);
}
+int additional_rules_filter(const struct dirent *entry)
+{
+ return !strcmp(entry->d_name, "ADDITIONAL_RULES.smack");;
+}
+
void load_rules_from_file(const char *s_rules_file_path,
const char *s_permission_name,
const app_type_t app_type)
load_permission_family(osp_family_filter, "OSP_", APP_TYPE_OSP, s_dir);
load_permission_family(efl_family_filter, "EFL_", APP_TYPE_EFL, s_dir);
+
perm_end();
API_FEATURE_LOADER_LOG("Done.\n");
}
API_FEATURE_LOADER_LOG("Done.\n");
}
+void load_additional_rules(const char *const s_rules_file_path)
+{
+ FILE *p_file = NULL;
+ char *s_rule = NULL;
+ char **rules_array = NULL;
+ size_t i_num_rules = 0;
+ size_t i = 0;
+ int ret;
+ vector_t rules_vector;
+
+ API_FEATURE_LOADER_LOG("Loading additional rules from file...\n");
+
+ p_file = fopen(s_rules_file_path, "r");
+ if(!p_file) goto finish;
+
+
+ vector_init(rules_vector);
+ while(getline(&s_rule, &i, p_file) > 0) {
+ vector_push_back_ptr(rules_vector, s_rule);
+ API_FEATURE_LOADER_LOG("Loading rule: %s", s_rule);
+ ++i_num_rules;
+ s_rule = NULL;
+ }
+ vector_push_back_ptr(rules_vector, NULL);
+
+ rules_array = vector_finish(rules_vector);
+
+ ret = perm_add_additional_rules((const char **)rules_array);
+ if(ret != PC_OPERATION_SUCCESS)
+ API_FEATURE_LOADER_LOG("Error %d\n", ret);
+
+finish:
+ if(p_file != NULL) fclose(p_file);
+ if(rules_array != NULL) {
+ for(i = 0; i < i_num_rules; ++i) {
+ free(rules_array[i]);
+ }
+ vector_free(rules_vector);
+ }
+ API_FEATURE_LOADER_LOG("Done.\n");
+}
int main(int argc, char *argv[])
{
bool b_load_from_dir = false;
const char *s_dir_name = NULL;
+ bool b_load_additional_rules = false;
+ const char *s_additional_rules_file_name = NULL;
+
static struct option long_options[] = {
{"verbose", no_argument, &i_verbose_flag__, 1},
{"file", required_argument, 0, 'f'},
{"dir", required_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'v'},
+ {"rules", required_argument, 0, 'r'},
{0, 0, 0, 0}
};
s_dir_name = optarg;
break;
+ case 'r':
+ b_load_additional_rules = true;
+ s_additional_rules_file_name = optarg;
+ break;
+
case 'h':
printf("Api feature loader v." API_FEATURE_LOADER_VERSION "\n\n");
printf(" Options:\n");
printf(" -d,--dir=path load api-features from the directory\n");
printf(" -f,--file=file_name load api-feature from the file\n");
printf(" -h,--help print this help\n");
+ printf(" -r,--rules load additional rules from the file\n");
printf(" --verbose verbose output\n");
printf(" -v,--version show applcation version\n");
}
// Run task
- if(b_load_from_dir) load_from_dir(s_dir_name);
- if(b_load_from_file) load_from_file(s_file_name);
- if(!b_load_from_dir &&
- !b_load_from_file) load_from_dir(API_FEATURES_DIR);
+ if(b_load_additional_rules)
+ load_additional_rules(s_additional_rules_file_name);
+ if(b_load_from_dir)
+ load_from_dir(s_dir_name);
+ if(b_load_from_file)
+ load_from_file(s_file_name);
+ if(!b_load_additional_rules &&
+ !b_load_from_dir &&
+ !b_load_from_file)
+ load_from_dir(API_FEATURES_DIR);
return 0;
}
FOREIGN KEY(app_path_type_id) REFERENCES app_path_type(app_path_type_id)
);
+CREATE TABLE IF NOT EXISTS label_app_path_type_rule (
+ label_id INTEGER NOT NULL,
+ app_path_type_id INTEGER NOT NULL,
+ access INTEGER NOT NULL DEFAULT 0,
+ is_reverse INTEGER NOT NULL DEFAULT 0,
+
+ PRIMARY KEY (label_id, app_path_type_id, is_reverse),
+
+ FOREIGN KEY(label_id) REFERENCES label(label_id),
+ FOREIGN KEY(app_path_type_id) REFERENCES app_path_type(app_path_type_id)
+);
CREATE TABLE IF NOT EXISTS label (
label_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
END;
+-- LABEL TO APP PATH TYPE RULE VIEW --------------------------------------------
+DROP VIEW IF EXISTS label_app_path_type_rule_view;
+CREATE VIEW label_app_path_type_rule_view AS
+SELECT
+ label_app_path_type_rule.label_id AS label_id,
+ label.name AS label_name,
+ app_path_type.name AS app_path_type_name,
+ label_app_path_type_rule.access AS access,
+ label_app_path_type_rule.is_reverse AS is_reverse
+FROM label_app_path_type_rule
+LEFT JOIN label USING(label_id)
+LEFT JOIN app_path_type USING(app_path_type_id);
+
+
+DROP TRIGGER IF EXISTS label_app_path_type_rule_view_insert_trigger;
+CREATE TRIGGER label_app_path_type_rule_view_insert_trigger
+INSTEAD OF INSERT
+ON label_app_path_type_rule_view
+BEGIN
+ INSERT OR IGNORE INTO label(name) VALUES (NEW.label_name);
+
+ INSERT INTO label_app_path_type_rule(label_id,
+ app_path_type_id,
+ access,
+ is_reverse)
+ SELECT label.label_id,
+ app_path_type.app_path_type_id,
+ str_to_access(NEW.access),
+ NEW.is_reverse
+ FROM label, app_path_type
+ WHERE label.name = NEW.label_name AND
+ app_path_type.name = NEW.app_path_type_name;
+END;
+
+
+DROP TRIGGER IF EXISTS label_app_path_type_rule_view_delete_trigger;
+CREATE TRIGGER label_app_path_type_rule_view_delete_trigger
+INSTEAD OF DELETE
+ON label_app_path_type_rule_view
+BEGIN
+ -- Delete the rules with this label
+ DELETE FROM label_app_path_type_rule
+ WHERE label_app_path_type_rule.label_id
+ IN (SELECT label.label_id
+ FROM label
+ WHERE label.name = OLD.label_name);
+
+ -- Delete the label if it's not referenced
+ DELETE FROM label_view
+ WHERE label_view.name = OLD.label_name;
+END;
+
-- PERMISSION TO PERMISSION RULE VIEW ------------------------------------------
DROP VIEW IF EXISTS permission_permission_rule_view;
CREATE VIEW permission_permission_rule_view AS
CREATE TRIGGER label_view_delete_trigger
INSTEAD OF DELETE ON label_view
WHEN OLD.label_id NOT IN (SELECT app.label_id
- FROM app) AND
+ FROM app) AND
OLD.label_id NOT IN (SELECT permission_label_rule.label_id
- FROM permission_label_rule) AND
+ FROM permission_label_rule) AND
OLD.label_id NOT IN (SELECT app_path.label_id
- FROM app_path)
+ FROM app_path) AND
+ OLD.label_id NOT IN (SELECT label_app_path_type_rule.label_id
+ FROM label_app_path_type_rule)
BEGIN
DELETE FROM label WHERE label.name = OLD.name;
END;
WHERE app.name != label.name;
+-- LABEL TO PATH TYPE RULE VIEW -------------------------------------------
+-- ltl = label to label
+DROP VIEW IF EXISTS ltl_label_app_path_type_rule_view;
+CREATE VIEW ltl_label_app_path_type_rule_view AS
+SELECT (CASE WHEN is_reverse = 0 THEN label.name ELSE path_label.name END) AS subject,
+ (CASE WHEN is_reverse = 1 THEN label.name ELSE path_label.name END) AS object,
+ l.access AS access,
+ 0 AS is_volatile
+FROM label_app_path_type_rule AS l
+INNER JOIN label USING(label_id)
+INNER JOIN app_path USING(app_path_type_id)
+INNER JOIN label AS path_label ON app_path.label_id = path_label.label_id
+WHERE path_label.name != label.name;
+
+
-- PERMISSION TO APPLICATION'S OWN PATHS ---------------------------------------
-- ltl = label to label
DROP VIEW IF EXISTS ltl_app_path_view;
SELECT subject, object, access, is_volatile
FROM ltl_permission_app_path_type_rule_view
UNION ALL
+ SELECT subject, object, access, is_volatile
+ FROM ltl_label_app_path_type_rule_view
+ UNION ALL
SELECT subject, object, access, 0
FROM ltl_app_path_view
)
<datatype>INTEGER</datatype>
<relation table="app_path" row="app_path_type_id" />
<relation table="permission_app_path_type_rule" row="app_path_type_id" />
+<relation table="label_app_path_type_rule" row="app_path_type_id" />
</row>
<row name="name" null="0" autoincrement="0">
<datatype>MEDIUMTEXT</datatype>
<part>is_reverse</part>
</key>
</table>
+<table x="849" y="620" name="label_app_path_type_rule">
+<row name="label_id" null="0" autoincrement="0">
+<datatype>INTEGER</datatype>
+<relation table="label" row="label_id" />
+</row>
+<row name="app_path_type_id" null="0" autoincrement="0">
+<datatype>INTEGER</datatype>
+</row>
+<row name="access" null="0" autoincrement="0">
+<datatype>INTEGER</datatype>
+<default>0</default></row>
+<row name="is_reverse" null="1" autoincrement="0">
+<datatype>TINYINT</datatype>
+<default>NULL</default></row>
+<key type="PRIMARY" name="">
+<part>label_id</part>
+<part>app_path_type_id</part>
+<part>is_reverse</part>
+</key>
+</table>
</sql>
#define SMACK_APP_LABEL_TEMPLATE "~APP~"
#define SMACK_SHARED_DIR_LABEL_TEMPLATE "~APP_SHARED_DIR~"
+#define ACC_LEN 6
int smack_label_is_valid(const char* smack_label);
int smack_file_name(const char* app_id, char** path);
inline int have_smack(void);
+
+/**
+ * Divide a Smack rule into subject, object and access
+ *
+ * @ingroup RDB internal functions
+ *
+ * @param s_rule the rule
+ * @param s_subject buffer for the subject
+ * @param s_object buffer for the object
+ * @param s_access buffer for the access
+ * @return PC_OPERATION_SUCCESS on success,
+ * error code otherwise
+ */
+int tokenize_rule(const char *const s_rule,
+ char s_subject[],
+ char s_object[],
+ char s_access[]);
+
+/**
+ * Check if the label is a wildcard.
+ *
+ * @ingroup RDB internal functions
+ *
+ * @param s_label the label
+ * @return is the label a wildcard?
+ */
+bool is_wildcard(const char *const s_label);
+
+/**
+ * Divides the rule into subject, object and access strings.
+ *
+ * @ingroup RDB internal functions
+ *
+ * @param s_rule the string that we parse
+ * @param s_label buffer for the label
+ * @param s_access buffer for the access
+ * @param pi_is_reverse buffer for the is_reversed
+ * @return PC_OPERATION_SUCCESS on success,
+ * error code otherwise
+ */
+int parse_rule(const char *const s_rule,
+ char s_label[],
+ char s_access[],
+ int *pi_is_reverse);
+
+/**
+ * Validate if all rules in the array can be parsed.
+ *
+ * @param pp_permissions_list array of permissions to check
+ * @return PC_OPERATION_SUCCESS on success,
+ * error code otherwise
+ */
+int validate_all_rules(const char *const *const pp_permissions_list);
+
#endif /* COMMON_H_ */
*/
int perm_end(void);
+/**
+ * Add additional rules to libprivilege.
+ * The rules can use wild-cards and labels.
+ *
+ * @param set_smack_rule_set an array of rules, NULL terminated
+ * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
+ */
+int perm_add_additional_rules(const char** set_smack_rule_set);
+
+
int base_name_from_perm(const char *perm, char **name);
/**
- * Divides the rule into subject, object and access strings.
- *
- * @ingroup RDB internal functions
- *
- * @param s_rule the string that we parse
- * @param s_label buffer for the label
- * @param s_access buffer for the access
- * @param pi_is_reverse buffer for the is_reversed
- * @return PC_OPERATION_SUCCESS on success,
- * error code otherwise
- */
-int parse_rule(const char *const s_rule,
- char s_label[],
- char s_access[],
- int *pi_is_reverse);
-
-
-/**
* Add a new permission to an application.
*
* @ingroup RDB internal functions
int update_smack_rules(sqlite3 *p_db);
+/**
+ * Add additional rules to the database.
+ *
+ * @ingroup RDB internal functions
+ *
+ * @param p_db pointer to a SQLite3 database object
+ * @param pp_smack_rules a list of smack rules
+ * @return PC_OPERATION_SUCCESS on success, error code otherwise
+ */
+int add_additional_rules_internal(sqlite3 *p_db,
+ const char *const *const pp_smack_rules);
+
#endif // _RULES_DB_INTERNALS_H_
/**
- * Validate if all rules in the array can be parsed.
- *
- * @param pp_permissions_list array of permissions to check
- * @return PC_OPERATION_SUCCESS on success,
- * error code otherwise
- */
-int validate_all_rules(const char *const *const pp_permissions_list);
-
-
-/**
* Revokes all permissions from the application by.
* deleting all permissions from app_permission table.
*
*/
int rdb_reset_app_permissions(const char *const s_app_label_name);
+/**
+ * Add the additional rules to the database. Erase the previous rules.
+ *
+ * @ingroup RDB API functions
+ *
+ * @param pp_smack_rules NULL terminated table of rules
+ * @return PC_OPERATION_SUCCESS on success,
+ * error code otherwise
+ */
+int rdb_add_additional_rules(const char *const *const pp_smack_rules);
+
#endif /*_RULES_DB_H_*/
\ No newline at end of file
sqlite3 /opt/dbspace/.rules-db.db3 < /opt/dbspace/rules-db-data.sql
rm -f /opt/dbspace/rules-db-data.sql
-api_feature_loader --verbose
+api_feature_loader --verbose --dir=/usr/share/privilege-control/
+api_feature_loader --verbose --rules=/usr/share/privilege-control/ADDITIONAL_RULES.smack
%files
%{_libdir}/*.so.*
#include "privilege-control.h"
/* TODO: implement such function in libsmack instead */
-int smack_label_is_valid(const char* smack_label)
+int smack_label_is_valid(const char *smack_label)
{
SECURE_C_LOGD("Entering function: %s. Params: smack_label=%s",
- __func__, smack_label);
+ __func__, smack_label);
int i;
- if (!smack_label || smack_label[0] == '\0' || smack_label[0] == '-')
+ if(!smack_label || smack_label[0] == '\0' || smack_label[0] == '-')
goto err;
- for (i = 0; smack_label[i]; ++i) {
- if (i >= SMACK_LABEL_LEN)
+ for(i = 0; smack_label[i]; ++i) {
+ if(i >= SMACK_LABEL_LEN)
goto err;
- switch (smack_label[i]) {
+ switch(smack_label[i]) {
case '~':
case ' ':
case '/':
return 0;
}
+
+int tokenize_rule(const char *const s_rule,
+ char s_subject[],
+ char s_object[],
+ char s_access[])
+{
+ if(sscanf(s_rule, "%s %s %s", s_subject, s_object, s_access) < 3) {
+ C_LOGE("RDB: Failed to tokenize the rule: %s", s_rule);
+ return PC_ERR_INVALID_OPERATION;
+ }
+ return PC_OPERATION_SUCCESS;
+}
+
+
+bool is_wildcard(const char *const s_label)
+{
+ return !strcmp(s_label, "~ALL_APPS~") ||
+ !strcmp(s_label, "~ALL_APPS_WITH_SAME_PERMISSION~") ||
+ !strcmp(s_label, "~PUBLIC_PATH~") ||
+ !strcmp(s_label, "~GROUP_PATH~") ||
+ !strcmp(s_label, "~SETTINGS_PATH~");
+}
+
+
+int parse_rule(const char *const s_rule,
+ char s_label[],
+ char s_access[],
+ int *pi_is_reverse)
+{
+ int ret = PC_OPERATION_SUCCESS;
+ char tmp_s_subject[SMACK_LABEL_LEN + 1];
+ char tmp_s_object[SMACK_LABEL_LEN + 1];
+ char tmp_s_access[ACC_LEN + 1];
+
+ bool b_subject_is_template;
+ bool b_object_is_template;
+
+ // Tokenize
+ ret = tokenize_rule(s_rule, tmp_s_subject, tmp_s_object, tmp_s_access);
+ if(ret != PC_OPERATION_SUCCESS) return ret;
+
+ // Check SMACK_APP_LABEL_TEMPLATE
+ b_subject_is_template = (bool) !strcmp(tmp_s_subject, SMACK_APP_LABEL_TEMPLATE);
+ b_object_is_template = (bool) !strcmp(tmp_s_object, SMACK_APP_LABEL_TEMPLATE);
+ if((b_subject_is_template && b_object_is_template) ||
+ (!b_subject_is_template && !b_object_is_template)) {
+ C_LOGE("RDB: Incorrect rule format in rule: %s", s_rule);
+ ret = PC_ERR_INVALID_PARAM;
+ return ret;
+ }
+
+ // Check label validity and copy rules
+ if(b_subject_is_template) {
+ // Not reversed
+ if(!smack_label_is_valid(tmp_s_object) &&
+ !is_wildcard(tmp_s_object)) {
+ C_LOGE("RDB: Incorrect subject label: %s", tmp_s_object);
+ return ret;
+ }
+ strcpy(s_label, tmp_s_object);
+ if(pi_is_reverse != NULL) *pi_is_reverse = 0;
+ } else if(b_object_is_template) {
+ // Reversed
+ if(!smack_label_is_valid(tmp_s_subject) &&
+ !is_wildcard(tmp_s_subject)) {
+ C_LOGE("RDB: Incorrect subject label: %s", tmp_s_subject);
+ return ret;
+ }
+ strcpy(s_label, tmp_s_subject);
+ if(pi_is_reverse != NULL) *pi_is_reverse = 1;
+ }
+ strcpy(s_access, tmp_s_access);
+
+ return PC_OPERATION_SUCCESS;
+}
+
+
+int validate_all_rules(const char *const *const pp_permissions_list)
+{
+ int i;
+ char s_label[SMACK_LABEL_LEN + 1];
+ char s_access[ACC_LEN + 1];
+
+ // Parse and check rules.
+ for(i = 0; pp_permissions_list[i] != NULL; ++i) {
+ // C_LOGE("RDB: Validating rules: %s", pp_permissions_list[i]);
+
+ // Ignore empty lines
+ if(strspn(pp_permissions_list[i], " \t\n")
+ == strlen(pp_permissions_list[i]))
+ continue;
+
+ if(parse_rule(pp_permissions_list[i], s_label, s_access, NULL)
+ != PC_OPERATION_SUCCESS) {
+ C_LOGE("RDB: Invalid parameter");
+ return PC_ERR_INVALID_PARAM;
+ }
+
+ // Check the other label
+ if(!is_wildcard(s_label) &&
+ !smack_label_is_valid(s_label)) {
+ C_LOGE("RDB: Incorrect object label: %s", s_label);
+ return PC_ERR_INVALID_PARAM;
+ }
+ }
+
+ return PC_OPERATION_SUCCESS;
+}
+
/* Auto cleanup stuff */
void freep(void *p)
{
- free(*(void**) p);
+ free(*(void **) p);
}
void closep(int *fd)
{
- if (*fd >= 0)
+ if(*fd >= 0)
close(*fd);
}
void fclosep(FILE **f)
{
- if (*f)
+ if(*f)
fclose(*f);
}
void fts_closep(FTS **f)
{
- if (*f)
+ if(*f)
fts_close(*f);
}
-static int load_smack_from_file_generic(const char* app_id, struct smack_accesses** smack, int *fd, char** path, bool is_early)
+static int load_smack_from_file_generic(const char *app_id, struct smack_accesses **smack, int *fd, char **path, bool is_early)
{
/* Notice that app_id is ignored when flag is_early is set.
* It's because all of the "early rules" (for all apps) should
* be in one common file: SMACK_STARTUP_RULES_FILE
*/
SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
- __func__, app_id);
+ __func__, app_id);
int ret;
- if (is_early) {
- if (0 > asprintf(path, "%s", SMACK_STARTUP_RULES_FILE)) {
+ if(is_early) {
+ if(0 > asprintf(path, "%s", SMACK_STARTUP_RULES_FILE)) {
*path = NULL;
C_LOGE("asprintf failed.");
return PC_ERR_MEM_OPERATION;
}
- }
- else {
+ } else {
ret = smack_file_name(app_id, path);
- if (ret != PC_OPERATION_SUCCESS)
+ if(ret != PC_OPERATION_SUCCESS)
return ret;
}
- if (smack_accesses_new(smack)) {
+ if(smack_accesses_new(smack)) {
C_LOGE("smack_accesses_new failed.");
return PC_ERR_MEM_OPERATION;
}
- *fd = open(*path, O_CREAT|O_RDWR, 0644);
- if (*fd == -1) {
+ *fd = open(*path, O_CREAT | O_RDWR, 0644);
+ if(*fd == -1) {
C_LOGE("file open failed (error: %s)", strerror(errno));
return PC_ERR_FILE_OPERATION;
}
- if (flock(*fd, LOCK_EX)) {
+ if(flock(*fd, LOCK_EX)) {
C_LOGE("flock failed");
return PC_ERR_INVALID_OPERATION;
}
- if (smack_accesses_add_from_file(*smack, *fd)) {
+ if(smack_accesses_add_from_file(*smack, *fd)) {
C_LOGE("smack_accesses_add_from_file failed.");
return PC_ERR_INVALID_OPERATION;
}
/* Rewind the file */
- if (lseek(*fd, 0, SEEK_SET) == -1) {
+ if(lseek(*fd, 0, SEEK_SET) == -1) {
C_LOGE("lseek failed.");
return PC_ERR_FILE_OPERATION;
}
return PC_OPERATION_SUCCESS;
}
-int load_smack_from_file(const char* app_id, struct smack_accesses** smack, int *fd, char** path)
+int load_smack_from_file(const char *app_id, struct smack_accesses **smack, int *fd, char **path)
{
SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
- __func__, app_id);
+ __func__, app_id);
return load_smack_from_file_generic(app_id, smack, fd, path, 0);
}
-int load_smack_from_file_early(const char* app_id, struct smack_accesses** smack, int *fd, char** path)
+int load_smack_from_file_early(const char *app_id, struct smack_accesses **smack, int *fd, char **path)
{
SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
- __func__, app_id);
+ __func__, app_id);
return load_smack_from_file_generic(app_id, smack, fd, path, 1);
}
int smack_mark_file_name(const char *app_id, char **path)
{
SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
- __func__, app_id);
+ __func__, app_id);
- if (asprintf(path, SMACK_LOADED_APP_RULES "/%s", app_id) == -1) {
+ if(asprintf(path, SMACK_LOADED_APP_RULES "/%s", app_id) == -1) {
C_LOGE("asprintf failed.");
*path = NULL;
return PC_ERR_MEM_OPERATION;
return PC_OPERATION_SUCCESS;
}
-bool file_exists(const char* path) {
+bool file_exists(const char *path)
+{
SECURE_C_LOGD("Entering function: %s. Params: path=%s",
- __func__, path);
+ __func__, path);
SECURE_C_LOGD("Opening file %s.", path);
- FILE* file = fopen(path, "r");
- if (file) {
+ FILE *file = fopen(path, "r");
+ if(file) {
fclose(file);
return true;
}
return false;
}
-int smack_file_name(const char* app_id, char** path)
+int smack_file_name(const char *app_id, char **path)
{
SECURE_C_LOGD("Entering function: %s. Params: app_id=%s",
- __func__, app_id);
+ __func__, app_id);
- if (asprintf(path, SMACK_RULES_DIR "/%s", app_id) == -1) {
+ if(asprintf(path, SMACK_RULES_DIR "/%s", app_id) == -1) {
C_LOGE("asprintf failed.");
*path = NULL;
return PC_ERR_MEM_OPERATION;
static int have_smack = -1;
- if (-1 == have_smack) {
- if (NULL == smack_smackfs_path()) {
+ if(-1 == have_smack) {
+ if(NULL == smack_smackfs_path()) {
C_LOGD("Libprivilege-control: no smack found on phone");
have_smack = 0;
} else {
// TODO: This function is not implemented with RDB.
return PC_ERR_INVALID_OPERATION;
}
+
+API int perm_add_additional_rules(const char** smack_rules){
+ SECURE_C_LOGD("Entering function: %s.", __func__);
+ int ret;
+ if (!smack_rules){
+ C_LOGE("smack_rules is NULL");
+ return PC_ERR_INVALID_PARAM;
+ }
+
+ ret = rdb_add_additional_rules(smack_rules);
+ if (ret != PC_OPERATION_SUCCESS) {
+ C_LOGE("RDB rdb_add_additional_rules failed with: %d", ret);
+ return ret;
+ }
+
+ return PC_OPERATION_SUCCESS;
+}
*/
static int reset_and_unbind_stmt(sqlite3_stmt *p_stmt)
{
- if(sqlite3_reset(p_stmt) != SQLITE_OK) {
- C_LOGE("RDB: Error reseting statement: %s",
+ if(sqlite3_clear_bindings(p_stmt) != SQLITE_OK) {
+ C_LOGE("RDB: Error unbinding statement: %s",
sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
return PC_ERR_DB_QUERY_STEP;
}
- if(sqlite3_clear_bindings(p_stmt) != SQLITE_OK) {
- C_LOGE("RDB: Error unbinding statement: %s",
+
+ if(sqlite3_reset(p_stmt) != SQLITE_OK) {
+ C_LOGE("RDB: Error reseting statement: %s",
sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
return PC_ERR_DB_QUERY_STEP;
}
}
-int parse_rule(const char *const s_rule,
- char s_label[],
- char s_access[],
- int *pi_is_reverse)
-{
- int ret = PC_OPERATION_SUCCESS;
- char *tmp_s_rule = NULL;
- const char *tmp_s_subject = NULL;
- const char *tmp_s_object = NULL;
- const char *tmp_s_access = NULL;
- char *saveptr = NULL;
- bool b_subject_is_template;
- bool b_object_is_template;
-
- // Parse subject, object and access:
- tmp_s_rule = strdup(s_rule);
- tmp_s_subject = strtok_r(tmp_s_rule, " \t\n", &saveptr);
- tmp_s_object = strtok_r(NULL, " \t\n", &saveptr);
- tmp_s_access = strtok_r(NULL, " \t\n", &saveptr);
-
- // Check rule validity:
- if(tmp_s_subject == NULL ||
- tmp_s_object == NULL ||
- tmp_s_access == NULL ||
- strtok_r(NULL, " \t\n", &saveptr) != NULL) {
- C_LOGE("RDB: Incorrect rule format: %s", s_rule);
- ret = PC_ERR_INVALID_PARAM;
- goto finish;
- }
-
- // Check if valid
- b_subject_is_template = (bool) !strcmp(tmp_s_subject, SMACK_APP_LABEL_TEMPLATE);
- b_object_is_template = (bool) !strcmp(tmp_s_object, SMACK_APP_LABEL_TEMPLATE);
- if((b_subject_is_template && b_object_is_template) ||
- (!b_subject_is_template && !b_object_is_template)) {
- C_LOGE("RDB: Incorrect rule format: %s", s_rule);
- ret = PC_ERR_INVALID_PARAM;
- goto finish;
- }
-
- // Copy rules
- if(b_subject_is_template) {
- // Not reversed
- if(pi_is_reverse != NULL) *pi_is_reverse = 0;
- strcpy(s_label, tmp_s_object);
- } else if(b_object_is_template) {
- // Reversed
- if(pi_is_reverse != NULL) *pi_is_reverse = 1;
- strcpy(s_label, tmp_s_subject);
- }
- strcpy(s_access, tmp_s_access);
-
-finish:
- free(tmp_s_rule);
- return ret;
-}
-
-
int prepare_stmts_for_bind(sqlite3 *p_db,
sqlite3_stmt **pp_stmt,
const char *const s_query)
}
-int add_permission_label_rule(sqlite3_stmt *p_stmt,
- const sqlite3_int64 i_permission_id,
- const char *const s_label_name,
- const char *const s_access,
- const int i_is_reverse)
+static int add_permission_label_rule(sqlite3_stmt *p_stmt,
+ const sqlite3_int64 i_permission_id,
+ const char *const s_label_name,
+ const char *const s_access,
+ const int i_is_reverse)
{
int ret = PC_OPERATION_SUCCESS;
}
-int add_permission_permission_rule(sqlite3_stmt *p_stmt,
- const sqlite3_int64 i_permission_id,
- const sqlite3_int64 i_target_permission_id,
- const char *const s_access,
- const int i_is_reverse)
+static int add_permission_permission_rule(sqlite3_stmt *p_stmt,
+ const sqlite3_int64 i_permission_id,
+ const sqlite3_int64 i_target_permission_id,
+ const char *const s_access,
+ const int i_is_reverse)
{
int ret = PC_OPERATION_SUCCESS;
}
-int add_permission_app_path_type_stmt(sqlite3_stmt *p_stmt,
- const sqlite3_int64 i_permission_id,
- const char *const s_path_type_name,
- const char *const s_access,
- const int i_is_reverse)
+static int add_permission_app_path_type_rule(sqlite3_stmt *p_stmt,
+ const sqlite3_int64 i_permission_id,
+ const char *const s_path_type_name,
+ const char *const s_access,
+ const int i_is_reverse)
{
int ret = PC_OPERATION_SUCCESS;
"INSERT INTO permission_label_rule_view( \
permission_id, access, label_name, is_reverse) \
VALUES(?,?,?,?)");
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
ret = prepare_stmts_for_bind(p_db, &p_perm_to_perm_stmt,
"INSERT OR REPLACE INTO permission_permission_rule( \
permission_id, target_permission_id, \
access, is_reverse) \
VALUES(?,?,str_to_access(?),?)");
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
ret = prepare_stmts_for_bind(p_db, &p_perm_to_app_path_type_stmt,
"INSERT INTO permission_app_path_type_rule_view( \
permission_id, app_path_type_name, access, is_reverse) \
VALUES(?,?,?,?)");
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
for(i = 0; pp_smack_rules[i] != NULL ; ++i) {
continue;
ret = parse_rule(pp_smack_rules[i], s_label, s_access, &i_is_reverse);
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
// Interpret wildcards
if(s_label[0] != '~' &&
s_label,
s_access,
i_is_reverse);
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
} else if(!strcmp(s_label, "~ALL_APPS~")) {
ret = get_permission_id_internal(p_db,
"ALL_APPS",
"ALL_APPS",
&i_all_apps_permission_id);
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
ret = add_permission_permission_rule(p_perm_to_perm_stmt,
i_permission_id,
i_all_apps_permission_id,
s_access,
i_is_reverse);
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
} else if(!strcmp(s_label, "~ALL_APPS_WITH_SAME_PERMISSION~")) {
ret = add_permission_permission_rule(p_perm_to_perm_stmt,
i_permission_id,
s_access,
i_is_reverse);
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
} else if(!strcmp(s_label, "~PUBLIC_PATH~")) {
- ret = add_permission_app_path_type_stmt(p_perm_to_app_path_type_stmt,
+ ret = add_permission_app_path_type_rule(p_perm_to_app_path_type_stmt,
i_permission_id,
"PUBLIC_PATH",
s_access,
i_is_reverse);
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
} else if(!strcmp(s_label, "~GROUP_PATH~")) {
- ret = add_permission_app_path_type_stmt(p_perm_to_app_path_type_stmt,
+ ret = add_permission_app_path_type_rule(p_perm_to_app_path_type_stmt,
i_permission_id,
"GROUP_PATH",
s_access,
i_is_reverse);
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
} else if(!strcmp(s_label, "~SETTINGS_PATH~")) {
- ret = add_permission_app_path_type_stmt(p_perm_to_app_path_type_stmt,
+ ret = add_permission_app_path_type_rule(p_perm_to_app_path_type_stmt,
i_permission_id,
"SETTINGS_PATH",
s_access,
i_is_reverse);
- if(ret != PC_OPERATION_SUCCESS) return ret;
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
}
}
- return PC_OPERATION_SUCCESS;
+
+ ret = PC_OPERATION_SUCCESS;
+
+finish:
+ if(p_perm_to_label_stmt &&
+ sqlite3_finalize(p_perm_to_label_stmt) < 0) {
+ C_LOGE("RDB: Error during finalizing statement: %s",
+ sqlite3_errmsg(p_db));
+ }
+
+ if(p_perm_to_perm_stmt &&
+ sqlite3_finalize(p_perm_to_perm_stmt) < 0) {
+ C_LOGE("RDB: Error during finalizing statement: %s",
+ sqlite3_errmsg(p_db));
+ }
+
+ if(p_perm_to_app_path_type_stmt &&
+ sqlite3_finalize(p_perm_to_app_path_type_stmt) < 0) {
+ C_LOGE("RDB: Error during finalizing statement: %s",
+ sqlite3_errmsg(p_db));
+ }
+ return ret;
+}
+
+static int add_label_app_path_type_rule(sqlite3_stmt *p_stmt,
+ const char *const s_label_name,
+ const char *const s_path_type_name,
+ const char *const s_access,
+ const int i_is_reverse)
+{
+ int ret = PC_OPERATION_SUCCESS;
+
+ if(sqlite3_bind_text(p_stmt, 1, s_label_name, RDB_AUTO_DETERM_SIZE, 0) ||
+ sqlite3_bind_text(p_stmt, 2, s_path_type_name, RDB_AUTO_DETERM_SIZE, 0) ||
+ sqlite3_bind_text(p_stmt, 3, s_access, RDB_AUTO_DETERM_SIZE, 0) ||
+ sqlite3_bind_int(p_stmt, 4, i_is_reverse)) {
+ C_LOGE("RDB: Error during binding to statement: %s",
+ sqlite3_errmsg(sqlite3_db_handle(p_stmt)));
+ ret = PC_ERR_DB_QUERY_BIND;
+ goto finish;
+ }
+
+ ret = step_and_convert_returned_value(p_stmt);
+
+finish:
+ reset_and_unbind_stmt(p_stmt);
+ return ret;
+}
+
+
+int add_additional_rules_internal(sqlite3 *p_db, const char *const *const pp_smack_rules)
+{
+ RDB_LOG_ENTRY;
+ int ret = PC_OPERATION_SUCCESS;
+ size_t i;
+ char s_subject[SMACK_LABEL_LEN + 1];
+ char s_object[SMACK_LABEL_LEN + 1];
+ char s_access[ACC_LEN + 1];
+ sqlite3_stmt *p_label_to_app_path_type_stmt = NULL;
+
+ // Clear the label_app_path_type_rule table
+ if(sqlite3_exec(p_db, "DELETE FROM label_app_path_type_rule_view;", 0, 0, 0) != SQLITE_OK) {
+ C_LOGE("RDB: Error during clearing additional rules: %s", sqlite3_errmsg(p_db));
+ ret = PC_ERR_DB_OPERATION;
+ goto finish;
+ }
+
+ ret = prepare_stmts_for_bind(p_db, &p_label_to_app_path_type_stmt,
+ "INSERT INTO label_app_path_type_rule_view( \
+ label_name, app_path_type_name, access, is_reverse) \
+ VALUES(?,?,?,?)");
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
+
+ // Add rules to the database
+ for(i = 0; pp_smack_rules[i] != NULL ; ++i) {
+
+ // Ignore empty lines
+ if(strspn(pp_smack_rules[i], " \t\n") == strlen(pp_smack_rules[i]))
+ continue;
+
+ // Tokenize
+ ret = tokenize_rule(pp_smack_rules[i], s_subject , s_object, s_access);
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
+
+
+ // Check validity
+ if(!smack_label_is_valid(s_subject)) {
+ C_LOGE("Subject is not a valid label");
+ ret = PC_ERR_INVALID_PARAM;
+ goto finish;
+ }
+
+ // Add access to paths
+ if(!strcmp(s_object, "~PUBLIC_PATH~")) {
+ ret = add_label_app_path_type_rule(p_label_to_app_path_type_stmt,
+ s_subject,
+ "PUBLIC_PATH",
+ s_access,
+ 0);
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
+
+ } else if(!strcmp(s_object, "~GROUP_PATH~")) {
+ ret = add_label_app_path_type_rule(p_label_to_app_path_type_stmt,
+ s_subject,
+ "GROUP_PATH",
+ s_access,
+ 0);
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
+
+ } else if(!strcmp(s_object, "~SETTINGS_PATH~")) {
+ ret = add_label_app_path_type_rule(p_label_to_app_path_type_stmt,
+ s_subject,
+ "SETTINGS_PATH",
+ s_access,
+ 0);
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
+ }
+
+ // Mark label as modified
+ ret = add_modified_label_internal(p_db, s_subject);
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
+ }
+
+finish:
+ if(p_label_to_app_path_type_stmt &&
+ sqlite3_finalize(p_label_to_app_path_type_stmt) < 0)
+ C_LOGE("RDB: Error during finalizing statement: %s",
+ sqlite3_errmsg(p_db));
+ return ret;
}
}
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));
}
}
return ret;
}
-static bool is_wildcard(const char *const s_label)
-{
- return !strcmp(s_label, "~ALL_APPS~") ||
- !strcmp(s_label, "~ALL_APPS_WITH_SAME_PERMISSION~") ||
- !strcmp(s_label, "~PUBLIC_PATH~") ||
- !strcmp(s_label, "~GROUP_PATH~") ||
- !strcmp(s_label, "~SETTINGS_PATH~");
-}
-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_label[SMACK_LABEL_LEN + 1];
- char s_access[ACC_LEN + 1];
-
- // Parse and check rules.
- for(i = 0; pp_permissions_list[i] != NULL; ++i) {
- // C_LOGE("RDB: Validating rules: %s", pp_permissions_list[i]);
-
- // Ignore empty lines
- if(strspn(pp_permissions_list[i], " \t\n")
- == strlen(pp_permissions_list[i]))
- continue;
+ int ret = PC_ERR_DB_OPERATION;
+ sqlite3 *p_db = NULL;
- if(parse_rule(pp_permissions_list[i], s_label, s_access, NULL)
- != PC_OPERATION_SUCCESS) {
- C_LOGE("RDB: Invalid parameter");
- return PC_ERR_INVALID_PARAM;
- }
+ ret = rdb_begin(&p_db);
+ if(ret != PC_OPERATION_SUCCESS) goto finish;
- // Check the other label
- if(!is_wildcard(s_label) &&
- !smack_label_is_valid(s_label)) {
- C_LOGE("RDB: Incorrect object label: %s", s_label);
- return PC_ERR_INVALID_PARAM;
- }
- }
+ ret = add_additional_rules_internal(p_db,
+ pp_smack_rules);
- return PC_OPERATION_SUCCESS;
+finish:
+ if(p_db__) update_ret_code(ret); else rdb_end(p_db, ret);
+ return ret;
}