Implemet data control solution for OSP apps.
authorBartlomiej Grzelewski <b.grzelewski@samsung.com>
Tue, 9 Apr 2013 13:05:11 +0000 (15:05 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Tue, 16 Apr 2013 13:53:39 +0000 (15:53 +0200)
[Issue#]   SSDWSSP-177
[Bug]      N/A
[Cause]    Native apps use shared memory. To Shared memory application
           needs cross rules.
[Solution] Now libprivilege may add access to shared memory created by
           provider.
[Verification] Build.

Change-Id: I92fa7826e0efe21cea346ae38968af4c582a9b68

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

index b4a86bf..e96dd22 100644 (file)
@@ -227,6 +227,27 @@ int add_shared_dir_readers(const char* shared_label, const char** app_list);
  */
 int app_add_friend(const char* app_id1, const char* app_id2);
 
+/**
+ * Modify SMACK rules to give access from (subject)customer_label to (object)
+ * provider_label.
+ * Note: This function will do nothing if subject has already rwxat access to
+ * object. You can revoke this modyfication by calling app_rovoke_access.
+ *
+ * @param subject - label of client application
+ * @param object  - label of provider application
+ * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
+ */
+int app_give_access(const char* subject, const char* object, const char* permission);
+
+/**
+ * Revoke access granted by app_give_access. This function will not remove
+ * accesses that were granted before app_give_access call.
+ *
+ * @param subject - label of client application
+ * @param object  - label of provider application
+ * @return PC_OPERATION_SUCCESS on success, PC_ERR_* on error
+ */
+int app_revoke_access(const char* subject, const char* object);
 
 #ifdef __cplusplus
 }
index b85450d..a19c25c 100644 (file)
@@ -63,6 +63,7 @@
 #define SMACK_DATA_SUFFIX       "_data"
 #define WRT_BASE_DEVCAP         "WRT"
 #define WRT_CLIENT_PATH         "/usr/bin/wrt-client"
+#define ACC_LEN                 5
 
 #ifdef SMACK_ENABLED
 static int set_smack_for_wrt(const char* widget_id);
@@ -97,6 +98,97 @@ typedef struct {
        char group_list[64];
 } new_user;
 
+struct state_list_t {
+    struct state_list_t *next;
+    char *key;
+    char *value;
+};
+
+static struct state_list_t state_list = {};
+
+int state_list_push(const char* key, const char* value) {
+    struct state_list_t *e = malloc(sizeof(struct state_list_t));
+    if(!e)
+        return -1;
+
+    size_t key_len = strlen(key)+1;
+    size_t value_len = strlen(value)+1;
+    e->key = malloc(key_len);
+    e->value = malloc(value_len);
+
+    if (!e->key || !e->value) {
+        free(e->key);
+        free(e->value);
+        free(e);
+        return PC_ERR_MEM_OPERATION;
+    }
+
+    memcpy(e->key, key, key_len);
+    memcpy(e->value, value, value_len);
+    e->next = state_list.next;
+    state_list.next = e;
+    return PC_OPERATION_SUCCESS;
+}
+
+char* state_list_pop_new(char *key) {
+    struct state_list_t *back, *current = &state_list;
+    size_t key_len = strlen(key);
+    while (NULL != current->next) {
+        back = current;
+        current = current->next;
+        size_t current_key_len = strlen(current->key);
+        if (current_key_len == key_len && 0 == memcmp(current->key, key, key_len)) {
+            char *ret = current->value;
+            back->next = current->next;
+            free(current->key);
+            free(current);
+            return ret;
+        }
+    }
+    return NULL;
+}
+
+int state_save(const char *subject, const char *object, const char *perm)
+{
+    char *key = NULL;
+    if (-1 == asprintf(&key, "%s|%s", subject, object))
+        return PC_ERR_INVALID_OPERATION;
+    int ret = state_list_push(key, perm);
+    free(key);
+    return ret;
+}
+
+int state_restore(const char* subject, const char* object)
+{
+    char *key = NULL;
+    int ret = PC_OPERATION_SUCCESS;
+    struct smack_accesses *smack = NULL;
+    if (-1 == asprintf(&key, "%s|%s", subject, object))
+        return PC_ERR_INVALID_OPERATION;
+    char *perm = state_list_pop_new(key);
+    free(key);
+
+    if (!perm)
+        return PC_ERR_INVALID_OPERATION;
+
+    if (smack_accesses_new(&smack)) {
+        ret = PC_ERR_MEM_OPERATION;
+        goto out;
+    }
+
+    if (smack_accesses_add(smack, subject, object, perm)) {
+        ret = PC_ERR_MEM_OPERATION;
+        goto out;
+    }
+
+    if (smack_accesses_apply(smack))
+        ret = PC_ERR_NOT_PERMITTED;
+out:
+    free(perm);
+    smack_accesses_free(smack);
+    return ret;
+}
+
 static inline int have_smack(void)
 {
        static int have_smack = -1;
@@ -846,6 +938,106 @@ API int app_label_dir(const char* label, const char* path)
 #endif
 }
 
+#ifdef SMACK_ENABLED
+static int smack_get_access_new(const char* subject, const char* object, char** label)
+{
+    char buff[ACC_LEN] = {'r', 'w', 'x', 'a', 't'};
+    char perm[2] = {'-'};
+    int i;
+
+    if(!smack_label_is_valid(subject) || !smack_label_is_valid(object) || !label)
+        return PC_ERR_INVALID_PARAM;
+
+    for (i=0; i<ACC_LEN; ++i) {
+        perm[0] = buff[i];
+        int ret = smack_have_access(subject, object, perm);
+        if (-1 == ret)
+            return PC_ERR_INVALID_OPERATION;
+        if (0 == ret)
+            buff[i] = '-';
+    }
+
+    *label = malloc(ACC_LEN+1);
+    if (NULL == *label)
+        return PC_ERR_MEM_OPERATION;
+
+    memcpy(*label, buff, ACC_LEN);
+    (*label)[ACC_LEN] = 0;
+    return PC_OPERATION_SUCCESS;
+}
+#endif
+
+/*
+ * This function will be used to allow direct communication between 2 OSP application.
+ * This function requires to store "state" with list of added label.
+ *
+ * Full implementation requires some kind of database. This implemetation works without
+ * database so you wont be able to revoke permissions added by different process.
+ */
+API int app_give_access(const char* subject, const char* object, const char* permissions)
+{
+    C_LOGD("Enter function: %s", __func__);
+    int ret = PC_OPERATION_SUCCESS;
+#ifdef SMACK_ENABLED
+    struct smack_accesses *smack = NULL;
+    static const char * const revoke = "-----";
+    char *current_permissions = NULL;
+
+    if (!have_smack())
+        return PC_OPERATION_SUCCESS;
+
+    if (!smack_label_is_valid(subject) || !smack_label_is_valid(object))
+        return PC_ERR_INVALID_PARAM;
+
+    if (PC_OPERATION_SUCCESS != (ret = smack_get_access_new(subject, object, &current_permissions)))
+        return ret;
+
+    if (smack_accesses_new(&smack)) {
+        ret = PC_ERR_MEM_OPERATION;
+        goto out;
+    }
+
+    if (smack_accesses_add_modify(smack, subject, object, permissions, revoke)) {
+        ret = PC_ERR_MEM_OPERATION;
+        goto out;
+    }
+
+    if (smack_accesses_apply(smack)) {
+        ret = PC_ERR_NOT_PERMITTED;
+        goto out;
+    }
+
+    ret = state_save(subject, object, current_permissions);
+
+out:
+    free(current_permissions);
+    smack_accesses_free(smack);
+#endif
+    return ret;
+}
+
+/*
+ * This function will be used to revoke direct communication between 2 OSP application.
+ *
+ * Full implementation requires some kind of database. This implemetation works without
+ * database so you wont be able to revoke permissions added by different process.
+ */
+API int app_revoke_access(const char* subject, const char* object)
+{
+    C_LOGD("Enter function: %s", __func__);
+#ifdef SMACK_ENABLED
+    if (!have_smack())
+        return PC_OPERATION_SUCCESS;
+
+    if (!smack_label_is_valid(subject) || !smack_label_is_valid(object))
+        return PC_ERR_INVALID_PARAM;
+
+    return state_restore(subject, object);
+#else
+    return PC_OPERATION_SUCCESS;
+#endif
+}
+
 API int app_label_shared_dir(const char* app_label, const char* shared_label, const char* path)
 {
        C_LOGD("Enter function: %s", __func__);