Added add_api_feature API
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Wed, 10 Apr 2013 10:12:59 +0000 (12:12 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Tue, 16 Apr 2013 13:53:47 +0000 (15:53 +0200)
[Issue#] N/A
[Feature] New API for adding custom features requested
[Problem] N/A
[Cause] N/A
[Solution] API implemented

[Verification] Run libprivilege-control-test --output=text
--regexp=add_api_feature

Change-Id: I75b60bed5b0af9d3c300e90f976c4fd8e5ba5f5a

include/privilege-control.h
src/privilege-control.c

index e96dd22..4a67829 100644 (file)
@@ -249,6 +249,23 @@ int app_give_access(const char* subject, const char* object, const char* permiss
  */
 int app_revoke_access(const char* subject, const char* object);
 
+/**
+ * Adds new api feature by installing new *.smack file.
+ * It must be called by privileged user.
+ *
+ * @param app_type application type
+ * @param api_feature_name name of newly added feature
+ * @param smack_rule_set set of rules required by the feature - NULL terminated
+ * list of NULL terminated rules.
+ * @param list_of_db_gids list of gids required to access databases controlled
+ * by the feature
+ * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
+ */
+int add_api_feature(app_type_t app_type,
+                                       const char* api_feature_name,
+                                       const char** set_smack_rule_set,
+                                       int** list_of_db_gids);
+
 #ifdef __cplusplus
 }
 #endif // __cplusplus
index 5c568dd..126f551 100644 (file)
@@ -575,6 +575,43 @@ static inline const char* app_type_name(app_type_t app_type)
        }
 }
 
+static int perm_file(app_type_t app_type, const char* devcap, char** path) {
+       const char* app_type_prefix = NULL;
+       const char* perm_suffix = NULL;
+       int ret = 0;
+
+       if (devcap == NULL || strlen(devcap) == 0) {
+               C_LOGE("empty devcap");
+               return PC_ERR_INVALID_PARAM;
+       }
+
+       app_type_prefix = app_type_name(app_type);
+
+       perm_suffix = strrchr(devcap, '/');
+       if (perm_suffix)
+               ++perm_suffix;
+       else
+               perm_suffix = devcap;
+
+       ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s.smack",
+                       app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
+                       perm_suffix);
+       if (ret == -1) {
+               C_LOGE("asprintf failed");
+               return PC_ERR_MEM_OPERATION;
+       }
+       return PC_OPERATION_SUCCESS;
+}
+
+static bool file_exists(const char* path) {
+       FILE* file = fopen(path, "r");
+       if (file) {
+               fclose(file);
+               return true;
+       }
+       return false;
+}
+
 static int perm_to_smack(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
 {
        C_LOGD("Enter function: %s", __func__);
@@ -585,23 +622,13 @@ static int perm_to_smack(struct smack_accesses* smack, const char* app_label, ap
        char smack_subject[SMACK_LABEL_LEN + 1];
        char smack_object[SMACK_LABEL_LEN + 1];
        char smack_accesses[10];
-       const char* app_type_prefix;
-       const char* perm_suffix;
-
-       app_type_prefix = app_type_name(app_type);
-
-       perm_suffix = strrchr(perm, '/');
-       if (perm_suffix)
-               ++perm_suffix;
-       else
-               perm_suffix = perm;
 
-       ret = asprintf(&path, TOSTRING(SHAREDIR) "/%s%s%s.smack",
-                       app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "", perm_suffix);
-       if (ret == -1) {
-               C_LOGE("asprintf failed");
-               ret = PC_ERR_MEM_OPERATION;
-               goto out;
+       // get file name for permission (devcap)
+       ret = perm_file(app_type, perm, &path);
+       if (ret != PC_OPERATION_SUCCESS)
+       {
+           free(path);
+           return ret;
        }
 
        if (asprintf(&format_string,"%%%ds %%%ds %%%lus\n",
@@ -1228,3 +1255,118 @@ out:
 
        return ret;
 }
+
+#ifdef SMACK_ENABLED
+static int save_rules(int fd, struct smack_accesses* accesses) {
+       if (flock(fd, LOCK_EX)) {
+               C_LOGE("flock failed, error %s", strerror(errno));
+               return PC_ERR_FILE_OPERATION;
+       }
+
+       if (smack_accesses_save(accesses, fd)) {
+               C_LOGE("smack_accesses_save failed");
+               return PC_ERR_FILE_OPERATION;
+       }
+       return PC_OPERATION_SUCCESS ;
+}
+
+static int validate_and_add_rule(char* rule, struct smack_accesses* accesses) {
+       const char* subject = NULL;
+       const char* object = NULL;
+       const char* access = NULL;
+       char* saveptr = NULL;
+
+       subject = strtok_r(rule, " \t\n", &saveptr);
+       object = strtok_r(NULL, " \t\n", &saveptr);
+       access = strtok_r(NULL, " \t\n", &saveptr);
+
+       // check rule validity
+       if (subject == NULL ||
+               object == NULL ||
+               access == NULL ||
+               strtok_r(NULL, " \t\n", &saveptr) != NULL ||
+               !smack_label_is_valid(subject) ||
+               !smack_label_is_valid(object))
+       {
+               C_LOGE("Incorrect rule format: %s", rule);
+               return PC_ERR_INVALID_PARAM;
+       }
+
+       if (smack_accesses_add(accesses, subject, object, access)) {
+               C_LOGE("smack_accesses_add failed");
+               return PC_ERR_INVALID_OPERATION;
+       }
+       return PC_OPERATION_SUCCESS ;
+}
+
+static int parse_and_save_rules(const char** smack_rules,
+               struct smack_accesses* accesses, const char* feature_file) {
+       size_t i = 0;
+       int fd = 0;
+       int ret = PC_OPERATION_SUCCESS;
+       char* tmp = NULL;
+
+       for (i = 0; smack_rules[i] != NULL ; i++) {
+               // ignore empty lines
+               if (strspn(smack_rules[i], " \t\n") == strlen(smack_rules[i]))
+                       continue;
+
+               tmp = strdup(smack_rules[i]);
+               ret = validate_and_add_rule(tmp, accesses);
+               free(tmp);
+               if (ret != PC_OPERATION_SUCCESS )
+                       return ret;
+       }
+
+       // save to file
+       fd = open(feature_file, O_CREAT | O_WRONLY, 0644);
+       if (fd == -1) {
+               C_LOGE("Unable to create file %s. Error: %s", feature_file, strerror(errno));
+               return PC_ERR_FILE_OPERATION;
+       }
+
+       ret = save_rules(fd, accesses);
+       close(fd);
+       return ret;
+}
+#endif
+
+API int add_api_feature(app_type_t app_type, const char* api_feature_name,
+               const char** smack_rules, int** list_of_db_gids) {
+       C_LOGD("Enter function: %s", __func__);
+#ifdef SMACK_ENABLED
+       int ret = PC_OPERATION_SUCCESS;
+       char* feature_file = NULL;
+       struct smack_accesses* accesses = NULL;
+
+       // TODO check process capabilities
+
+       // get feature file name
+       ret = perm_file(app_type, api_feature_name, &feature_file);
+       if (ret != PC_OPERATION_SUCCESS ) {
+               return ret;
+       }
+
+       // check if feature exists
+       if (file_exists(feature_file)) {
+               C_LOGE("Feature file %s already exists", feature_file);
+               return PC_ERR_INVALID_PARAM;
+       }
+
+       // parse & save rules
+       if (smack_rules != NULL ) {
+               if (smack_accesses_new(&accesses)) {
+                       C_LOGE("smack_acceses_new failed");
+                       return PC_ERR_MEM_OPERATION;
+               }
+
+               ret = parse_and_save_rules(smack_rules, accesses, feature_file);
+               smack_accesses_free(accesses);
+       }
+
+       // TODO go through gid list
+       return ret;
+#else
+       return PC_OPERATION_SUCCESS;
+#endif // SMACK_ENABLED
+}