[pulseaudio-discuss] [PATCH 2/2] module-access: make policy object containing rules

Wim Taymans wim.taymans at gmail.com
Mon Feb 23 07:26:37 PST 2015


Make a policy object that contains the rules for checking access to
resources. The idea is that we can have different policies later and
then, depending on the client, use one of the policies.
---
 src/modules/module-access.c | 184 +++++++++++++++++++++++++++-----------------
 1 file changed, 115 insertions(+), 69 deletions(-)

diff --git a/src/modules/module-access.c b/src/modules/module-access.c
index dc04b96..dd6af7f 100644
--- a/src/modules/module-access.c
+++ b/src/modules/module-access.c
@@ -52,6 +52,8 @@ static const char* const valid_modargs[] = {
 };
 
 typedef struct event_item event_item;
+typedef struct access_policy access_policy;
+typedef struct userdata userdata;
 
 struct event_item {
     PA_LLIST_FIELDS(event_item);
@@ -63,13 +65,28 @@ struct event_item {
 
 struct userdata {
     pa_core *core;
+
     pa_hook_slot *hook[PA_ACCESS_HOOK_MAX];
 
     PA_LLIST_HEAD(event_item, events);
+
+    pa_idxset *policies;
+    uint32_t default_policy;
+};
+
+typedef bool (*access_rule_t)(pa_core *c, pa_access_data *d, struct userdata *u);
+
+struct access_policy {
+    uint32_t index;
+    struct userdata *userdata;
+
+    access_rule_t rule[PA_ACCESS_HOOK_MAX];
 };
 
-static pa_hook_result_t access_check_owner (pa_core *c, pa_access_data *d, struct userdata *u) {
-    pa_hook_result_t result = PA_HOOK_STOP;
+
+/* rule checks if the operation on the object is performed by the owner of the object */
+static bool rule_check_owner (pa_core *c, pa_access_data *d, struct userdata *u) {
+    bool result = false;
     uint32_t idx = PA_INVALID_INDEX;
 
     switch (d->hook) {
@@ -102,13 +119,57 @@ static pa_hook_result_t access_check_owner (pa_core *c, pa_access_data *d, struc
             break;
     }
     if (idx == d->client_index)
-        result = PA_HOOK_OK;
+        result = true;
     else
         pa_log("blocked operation %d/%d of client %d to client %d", d->hook, d->object_index, idx, d->client_index);
 
     return result;
 }
 
+/* rule allows the operation */
+static bool rule_allow (pa_core *c, pa_access_data *d, struct userdata *u) {
+    pa_log("allow operation %d/%d for client %d", d->hook, d->object_index, d->client_index);
+    return true;
+}
+
+/* rule blocks the operation */
+static bool rule_block (pa_core *c, pa_access_data *d, struct userdata *u) {
+    pa_log("blocked operation %d/%d for client %d", d->hook, d->object_index, d->client_index);
+    return false;
+}
+
+static access_policy *access_policy_new(struct userdata *u, bool allow_all) {
+    access_policy *ap;
+    int i;
+
+    ap = pa_xnew0(access_policy, 1);
+    ap->userdata = u;
+    for (i = 0; i < PA_ACCESS_HOOK_MAX; i++)
+      ap->rule[i] = allow_all ? rule_allow : rule_block;
+
+    pa_idxset_put(u->policies, ap, &ap->index);
+
+    return ap;
+}
+
+static void access_policy_free(access_policy *ap) {
+    pa_idxset_remove_by_index(ap->userdata->policies, ap->index);
+    pa_xfree(ap);
+}
+
+static pa_hook_result_t check_access (pa_core *c, pa_access_data *d, struct userdata *u) {
+    access_policy *ap;
+    access_rule_t rule;
+
+    ap = pa_idxset_get_by_index(u->policies, u->default_policy);
+
+    rule = ap->rule[d->hook];
+    if (rule && rule(c, d, u))
+      return PA_HOOK_OK;
+
+    return PA_HOOK_STOP;
+}
+
 static const pa_access_hook_t event_hook[PA_SUBSCRIPTION_EVENT_FACILITY_MASK+1] = {
     [PA_SUBSCRIPTION_EVENT_SINK] = PA_ACCESS_HOOK_GET_SINK_INFO,
     [PA_SUBSCRIPTION_EVENT_SOURCE] = PA_ACCESS_HOOK_GET_SOURCE_INFO,
@@ -153,6 +214,7 @@ static bool remove_event(struct userdata *u, uint32_t cidx, int facility, uint32
     return false;
 }
 
+
 static pa_hook_result_t filter_event (pa_core *c, pa_access_data *d, struct userdata *u) {
     int facility;
 
@@ -195,47 +257,11 @@ static pa_hook_result_t filter_event (pa_core *c, pa_access_data *d, struct user
     return PA_HOOK_STOP;
 }
 
-static pa_hook_result_t access_block (pa_core *c, pa_access_data *d, struct userdata *u) {
-    pa_log("blocked operation %d/%d for client %d", d->hook, d->object_index, d->client_index);
-    return PA_HOOK_STOP;
-}
-
-static void install_cb(struct userdata *u, pa_access_hook_t id, pa_hook_cb_t cb) {
-    if (u->hook[id])
-        pa_hook_slot_free(u->hook[id]);
-    if (cb)
-        u->hook[id] = pa_hook_connect(&u->core->access[id], PA_HOOK_EARLY - 1, cb, u);
-    else
-        u->hook[id] = NULL;
-}
-
-static void allow(struct userdata *u, pa_access_hook_t id) {
-    install_cb(u, id, NULL);
-}
-
-static void block(struct userdata *u, pa_access_hook_t id) {
-    install_cb(u, id, (pa_hook_cb_t) access_block);
-}
-
-static void check_owner(struct userdata *u, pa_access_hook_t id) {
-    install_cb(u, id, (pa_hook_cb_t) access_check_owner);
-}
-
-static void allow_all(struct userdata *u) {
-    int i;
-    for (i = 0; i < PA_ACCESS_HOOK_MAX; i++)
-        allow(u, i);
-}
-
-static void block_all(struct userdata *u) {
-    int i;
-    for (i = 0; i < PA_ACCESS_HOOK_MAX; i++)
-        block(u, i);
-}
-
 int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     struct userdata *u;
+    int i;
+    access_policy *ap;
 
     pa_assert(m);
 
@@ -248,34 +274,47 @@ int pa__init(pa_module*m) {
     u->core = m->core;
     m->userdata = u;
 
-    block_all(u);
+    u->policies = pa_idxset_new (NULL, NULL);
 
-    allow (u, PA_ACCESS_HOOK_GET_SINK_INFO);
-    allow (u, PA_ACCESS_HOOK_GET_SOURCE_INFO);
-    allow (u, PA_ACCESS_HOOK_GET_SERVER_INFO);
-    allow (u, PA_ACCESS_HOOK_GET_MODULE_INFO);
-    allow (u, PA_ACCESS_HOOK_GET_CARD_INFO);
-    allow (u, PA_ACCESS_HOOK_STAT);
-    allow (u, PA_ACCESS_HOOK_GET_SAMPLE_INFO);
-    allow (u, PA_ACCESS_HOOK_PLAY_SAMPLE);
-    allow (u, PA_ACCESS_HOOK_CONNECT_PLAYBACK);
+    for (i = 0; i < PA_ACCESS_HOOK_MAX; i++) {
+        pa_hook_cb_t cb;
 
-    check_owner(u, PA_ACCESS_HOOK_GET_CLIENT_INFO);
-    check_owner(u, PA_ACCESS_HOOK_KILL_CLIENT);
+        if (i == PA_ACCESS_HOOK_FILTER_SUBSCRIBE_EVENT)
+            cb = (pa_hook_cb_t) filter_event;
+        else
+            cb = (pa_hook_cb_t) check_access;
+
+        u->hook[i] = pa_hook_connect(&u->core->access[i], PA_HOOK_EARLY - 1, cb, u);
+    }
 
-    check_owner(u, PA_ACCESS_HOOK_GET_SINK_INPUT_INFO);
-    check_owner(u, PA_ACCESS_HOOK_MOVE_SINK_INPUT);
-    check_owner(u, PA_ACCESS_HOOK_SET_SINK_INPUT_VOLUME);
-    check_owner(u, PA_ACCESS_HOOK_SET_SINK_INPUT_MUTE);
-    check_owner(u, PA_ACCESS_HOOK_KILL_SINK_INPUT);
+    ap = access_policy_new(u, false);
 
-    check_owner(u, PA_ACCESS_HOOK_GET_SOURCE_OUTPUT_INFO);
-    check_owner(u, PA_ACCESS_HOOK_MOVE_SOURCE_OUTPUT);
-    check_owner(u, PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_VOLUME);
-    check_owner(u, PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_MUTE);
-    check_owner(u, PA_ACCESS_HOOK_KILL_SOURCE_OUTPUT);
+    ap->rule[PA_ACCESS_HOOK_GET_SINK_INFO] = rule_allow;
+    ap->rule[PA_ACCESS_HOOK_GET_SOURCE_INFO] = rule_allow;
+    ap->rule[PA_ACCESS_HOOK_GET_SERVER_INFO] = rule_allow;
+    ap->rule[PA_ACCESS_HOOK_GET_MODULE_INFO] = rule_allow;
+    ap->rule[PA_ACCESS_HOOK_GET_CARD_INFO] = rule_allow;
+    ap->rule[PA_ACCESS_HOOK_STAT] = rule_allow;
+    ap->rule[PA_ACCESS_HOOK_GET_SAMPLE_INFO] = rule_allow;
+    ap->rule[PA_ACCESS_HOOK_PLAY_SAMPLE] = rule_allow;
+    ap->rule[PA_ACCESS_HOOK_CONNECT_PLAYBACK] = rule_allow;
 
-    install_cb(u, PA_ACCESS_HOOK_FILTER_SUBSCRIBE_EVENT, (pa_hook_cb_t) filter_event);
+    ap->rule[PA_ACCESS_HOOK_GET_CLIENT_INFO] = rule_check_owner;
+    ap->rule[PA_ACCESS_HOOK_KILL_CLIENT] = rule_check_owner;
+
+    ap->rule[PA_ACCESS_HOOK_GET_SINK_INPUT_INFO] = rule_check_owner;
+    ap->rule[PA_ACCESS_HOOK_MOVE_SINK_INPUT] = rule_check_owner;
+    ap->rule[PA_ACCESS_HOOK_SET_SINK_INPUT_VOLUME] = rule_check_owner;
+    ap->rule[PA_ACCESS_HOOK_SET_SINK_INPUT_MUTE] = rule_check_owner;
+    ap->rule[PA_ACCESS_HOOK_KILL_SINK_INPUT] = rule_check_owner;
+
+    ap->rule[PA_ACCESS_HOOK_GET_SOURCE_OUTPUT_INFO] = rule_check_owner;
+    ap->rule[PA_ACCESS_HOOK_MOVE_SOURCE_OUTPUT] = rule_check_owner;
+    ap->rule[PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_VOLUME] = rule_check_owner;
+    ap->rule[PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_MUTE] = rule_check_owner;
+    ap->rule[PA_ACCESS_HOOK_KILL_SOURCE_OUTPUT] = rule_check_owner;
+
+    u->default_policy = ap->index;
 
     pa_modargs_free(ma);
     return 0;
@@ -290,18 +329,25 @@ fail:
 
 void pa__done(pa_module*m) {
     struct userdata* u;
-    event_item *i;
+    event_item *ei;
+    int i;
 
     pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    allow_all(u);
+    for (i = 0; i < PA_ACCESS_HOOK_MAX; i++) {
+        if (u->hook[i])
+            pa_hook_slot_free(u->hook[i]);
+    }
+
+    if (u->policies)
+      pa_idxset_free(u->policies, (pa_free_cb_t) access_policy_free);
 
-    while ((i = u->events)) {
-        PA_LLIST_REMOVE(event_item, u->events, i);
-        pa_xfree(i);
+    while ((ei = u->events)) {
+        PA_LLIST_REMOVE(event_item, u->events, ei);
+        pa_xfree(ei);
     }
 
     pa_xfree(u);
-- 
2.1.0



More information about the pulseaudio-discuss mailing list