diff options
-rw-r--r-- | src/examples/export-sink.c | 21 | ||||
-rw-r--r-- | src/examples/media-session.c | 7 | ||||
-rw-r--r-- | src/modules/module-access.c | 8 | ||||
-rw-r--r-- | src/modules/module-protocol-native/protocol-native.c | 115 | ||||
-rw-r--r-- | src/pipewire/client.c | 215 | ||||
-rw-r--r-- | src/pipewire/client.h | 6 | ||||
-rw-r--r-- | src/pipewire/core.c | 15 | ||||
-rw-r--r-- | src/pipewire/core.h | 10 | ||||
-rw-r--r-- | src/pipewire/global.c | 68 | ||||
-rw-r--r-- | src/pipewire/global.h | 9 | ||||
-rw-r--r-- | src/pipewire/interfaces.h | 49 | ||||
-rw-r--r-- | src/pipewire/permission.h | 60 | ||||
-rw-r--r-- | src/tools/pipewire-cli.c | 17 |
13 files changed, 281 insertions, 319 deletions
diff --git a/src/examples/export-sink.c b/src/examples/export-sink.c index ab0cbd1b..9b1a3552 100644 --- a/src/examples/export-sink.c +++ b/src/examples/export-sink.c @@ -509,21 +509,18 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo case PW_REMOTE_STATE_CONNECTED: { - struct spa_dict_item items[5]; - int i = 0; - - /* set specific permissions on all existing objects without permissions */ - items[i++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_EXISTING, "r--"); - /* set default permission for new objects and objects without - * specific permissions */ - items[i++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_DEFAULT, "---"); + struct pw_permission permissions[2]; + /* an example, set specific permissions on one object, this is the - * core object, we already have a binding to it that is not affected - * by the removal of X permissions, only future bindings. */ - items[i++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, "0:rw-"); + * core object. */ + permissions[0].id = 0; + permissions[0].permissions = PW_PERM_R | PW_PERM_X; + /* remove WX from all other objects */ + permissions[1].id = SPA_ID_INVALID; + permissions[1].permissions = PW_PERM_R; pw_core_proxy_permissions(pw_remote_get_core_proxy(data->remote), - &SPA_DICT_INIT(items, i)); + 2, permissions); make_node(data); break; diff --git a/src/examples/media-session.c b/src/examples/media-session.c index d3709993..c313d143 100644 --- a/src/examples/media-session.c +++ b/src/examples/media-session.c @@ -700,7 +700,7 @@ handle_client(struct impl *impl, uint32_t id, uint32_t parent_id, { struct pw_proxy *p; struct client *client; - struct spa_dict_item items[2]; + struct pw_permission perms[2]; const char *str; p = pw_registry_proxy_bind(impl->registry_proxy, @@ -727,10 +727,9 @@ handle_client(struct impl *impl, uint32_t id, uint32_t parent_id, return 0; if (strcmp(str, "restricted") == 0) { - items[0].key = PW_CORE_PROXY_PERMISSIONS_DEFAULT; - items[0].value = "rwx"; + perms[0] = PW_PERMISSION_INIT(-1, PW_PERM_RWX); pw_client_proxy_update_permissions((struct pw_client_proxy*)p, - &SPA_DICT_INIT(items, 1)); + 1, perms); } return 0; } diff --git a/src/modules/module-access.c b/src/modules/module-access.c index 08573742..2adfdd7d 100644 --- a/src/modules/module-access.c +++ b/src/modules/module-access.c @@ -110,6 +110,7 @@ core_check_access(void *data, struct pw_client *client) { struct impl *impl = data; const struct ucred *ucred; + struct pw_permission permissions[1]; struct spa_dict_item items[2]; const char *str; int res; @@ -128,7 +129,8 @@ core_check_access(void *data, struct pw_client *client) if (res == 0) goto granted; if (res > 0) - res = EACCES; + res = -EACCES; + items[0] = SPA_DICT_ITEM_INIT("pipewire.access", "blacklisted"); goto blacklisted; } @@ -162,7 +164,8 @@ core_check_access(void *data, struct pw_client *client) granted: pw_log_debug("module %p: client %p access granted", impl, client); - pw_client_set_permissions(client, PW_PERM_RWX); + permissions[0] = PW_PERMISSION_INIT(-1, PW_PERM_RWX); + pw_client_update_permissions(client, 1, permissions); return; wait_permissions: @@ -172,7 +175,6 @@ core_check_access(void *data, struct pw_client *client) return; blacklisted: - items[0] = SPA_DICT_ITEM_INIT("pipewire.access", "blacklisted"); pw_resource_error(pw_client_get_core_resource(client), 0, res, "blacklisted"); pw_client_update_properties(client, &SPA_DICT_INIT(items, 1)); return; diff --git a/src/modules/module-protocol-native/protocol-native.c b/src/modules/module-protocol-native/protocol-native.c index 6be0b121..7c7c7dff 100644 --- a/src/modules/module-protocol-native/protocol-native.c +++ b/src/modules/module-protocol-native/protocol-native.c @@ -64,22 +64,23 @@ static void core_marshal_client_update(void *object, const struct spa_dict *prop pw_protocol_native_end_proxy(proxy, b); } -static void core_marshal_permissions(void *object, const struct spa_dict *props) +static void core_marshal_permissions(void *object, uint32_t n_permissions, + const struct pw_permission *permissions) { struct pw_proxy *proxy = object; struct spa_pod_builder *b; - int i, n_items; + int i; b = pw_protocol_native_begin_proxy(proxy, PW_CORE_PROXY_METHOD_PERMISSIONS); - n_items = props ? props->n_items : 0; - - spa_pod_builder_add(b, "[ i", n_items, NULL); + spa_pod_builder_add(b, "[", + "i", n_permissions, + NULL); - for (i = 0; i < n_items; i++) { + for (i = 0; i < n_permissions; i++) { spa_pod_builder_add(b, - "s", props->items[i].key, - "s", props->items[i].value, NULL); + "i", permissions[i].id, + "i", permissions[i].permissions, NULL); } spa_pod_builder_add(b, "]", NULL); @@ -340,23 +341,25 @@ static int core_demarshal_client_update(void *object, void *data, size_t size) static int core_demarshal_permissions(void *object, void *data, size_t size) { struct pw_resource *resource = object; - struct spa_dict props; struct spa_pod_parser prs; - uint32_t i; + struct pw_permission *permissions; + uint32_t i, n_permissions; spa_pod_parser_init(&prs, data, size, 0); - if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0) + if (spa_pod_parser_get(&prs, "[", + "i", &n_permissions, NULL) < 0) return -EINVAL; - props.items = alloca(props.n_items * sizeof(struct spa_dict_item)); - for (i = 0; i < props.n_items; i++) { + permissions = alloca(n_permissions * sizeof(struct pw_permission)); + for (i = 0; i < n_permissions; i++) { if (spa_pod_parser_get(&prs, - "s", &props.items[i].key, - "s", &props.items[i].value, + "i", &permissions[i].id, + "i", &permissions[i].permissions, NULL) < 0) return -EINVAL; } - pw_resource_do(resource, struct pw_core_proxy_methods, permissions, 0, &props); + pw_resource_do(resource, struct pw_core_proxy_methods, permissions, 0, + n_permissions, permissions); return 0; } @@ -1017,24 +1020,23 @@ static int client_demarshal_info(void *object, void *data, size_t size) return 0; } -static void client_marshal_permissions(void *object, const struct spa_dict *dict) +static void client_marshal_permissions(void *object, uint32_t index, uint32_t n_permissions, + struct pw_permission *permissions) { struct pw_resource *resource = object; struct spa_pod_builder *b; - uint32_t i, n_items; + uint32_t i; b = pw_protocol_native_begin_resource(resource, PW_CLIENT_PROXY_EVENT_PERMISSIONS); - n_items = dict ? dict->n_items : 0; - spa_pod_builder_add(b, - "[", - "i", n_items, NULL); + "[ i", index, + "i", n_permissions, NULL); - for (i = 0; i < n_items; i++) { + for (i = 0; i < n_permissions; i++) { spa_pod_builder_add(b, - "s", dict->items[i].key, - "s", dict->items[i].value, NULL); + "s", permissions[i].id, + "s", permissions[i].permissions, NULL); } spa_pod_builder_add(b, "]", NULL); @@ -1044,23 +1046,24 @@ static void client_marshal_permissions(void *object, const struct spa_dict *dict static int client_demarshal_permissions(void *object, void *data, size_t size) { struct pw_proxy *proxy = object; - struct spa_dict props; + struct pw_permission *permissions; struct spa_pod_parser prs; - uint32_t i; + uint32_t i, index, n_permissions; spa_pod_parser_init(&prs, data, size, 0); - if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0) + if (spa_pod_parser_get(&prs, "[ i", &index, + "i", &n_permissions, NULL) < 0) return -EINVAL; - props.items = alloca(props.n_items * sizeof(struct spa_dict_item)); - for (i = 0; i < props.n_items; i++) { + permissions = alloca(n_permissions * sizeof(struct pw_permission)); + for (i = 0; i < n_permissions; i++) { if (spa_pod_parser_get(&prs, - "s", &props.items[i].key, - "s", &props.items[i].value, + "i", &permissions[i].id, + "i", &permissions[i].permissions, NULL) < 0) return -EINVAL; } - pw_proxy_notify(proxy, struct pw_client_proxy_events, permissions, 0, &props); + pw_proxy_notify(proxy, struct pw_client_proxy_events, permissions, 0, index, n_permissions, permissions); return 0; } @@ -1095,14 +1098,16 @@ static int client_demarshal_error(void *object, void *data, size_t size) return 0; } -static void client_marshal_get_permissions(void *object) +static void client_marshal_get_permissions(void *object, uint32_t index, uint32_t num) { struct pw_proxy *proxy = object; struct spa_pod_builder *b; b = pw_protocol_native_begin_proxy(proxy, PW_CLIENT_PROXY_METHOD_GET_PERMISSIONS); - spa_pod_builder_add_struct(b, "P", NULL); + spa_pod_builder_add_struct(b, + "i", index, + "i", num, NULL); pw_protocol_native_end_proxy(proxy, b); } @@ -1111,32 +1116,33 @@ static int client_demarshal_get_permissions(void *object, void *data, size_t siz { struct pw_resource *resource = object; struct spa_pod_parser prs; - void *ptr; + uint32_t index, num; spa_pod_parser_init(&prs, data, size, 0); - if (spa_pod_parser_get(&prs, "[P]", &ptr, NULL) < 0) + if (spa_pod_parser_get(&prs, + "[i", &index, + "i", &num, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_client_proxy_methods, get_permissions, 0); + pw_resource_do(resource, struct pw_client_proxy_methods, get_permissions, 0, index, num); return 0; } -static void client_marshal_update_permissions(void *object, const struct spa_dict *props) +static void client_marshal_update_permissions(void *object, uint32_t n_permissions, + const struct pw_permission *permissions) { struct pw_proxy *proxy = object; struct spa_pod_builder *b; - int i, n_items; + int i; b = pw_protocol_native_begin_proxy(proxy, PW_CLIENT_PROXY_METHOD_UPDATE_PERMISSIONS); - n_items = props ? props->n_items : 0; - - spa_pod_builder_add(b, "[ i", n_items, NULL); + spa_pod_builder_add(b, "[ i", n_permissions, NULL); - for (i = 0; i < n_items; i++) { + for (i = 0; i < n_permissions; i++) { spa_pod_builder_add(b, - "s", props->items[i].key, - "s", props->items[i].value, NULL); + "i", permissions[i].id, + "i", permissions[i].permissions, NULL); } spa_pod_builder_add(b, "]", NULL); @@ -1146,23 +1152,24 @@ static void client_marshal_update_permissions(void *object, const struct spa_dic static int client_demarshal_update_permissions(void *object, void *data, size_t size) { struct pw_resource *resource = object; - struct spa_dict props; + struct pw_permission *permissions; struct spa_pod_parser prs; - uint32_t i; + uint32_t i, n_permissions; spa_pod_parser_init(&prs, data, size, 0); - if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0) + if (spa_pod_parser_get(&prs, "[ i", &n_permissions, NULL) < 0) return -EINVAL; - props.items = alloca(props.n_items * sizeof(struct spa_dict_item)); - for (i = 0; i < props.n_items; i++) { + permissions = alloca(n_permissions * sizeof(struct pw_permission)); + for (i = 0; i < n_permissions; i++) { if (spa_pod_parser_get(&prs, - "s", &props.items[i].key, - "s", &props.items[i].value, + "i", &permissions[i].id, + "i", &permissions[i].permissions, NULL) < 0) return -EINVAL; } - pw_resource_do(resource, struct pw_client_proxy_methods, update_permissions, 0, &props); + pw_resource_do(resource, struct pw_client_proxy_methods, update_permissions, 0, + n_permissions, permissions); return 0; } diff --git a/src/pipewire/client.c b/src/pipewire/client.c index ffde610b..e1bc112a 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -27,11 +27,6 @@ #include "pipewire/private.h" #include "pipewire/resource.h" -struct permission { - uint32_t id; - uint32_t permissions; -}; - /** \cond */ struct impl { struct pw_client this; @@ -46,40 +41,40 @@ struct resource_data { }; /** find a specific permission for a global or NULL when there is none */ -static struct permission * +static struct pw_permission * find_permission(struct pw_client *client, uint32_t id) { struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this); - struct permission *p; + struct pw_permission *p; - if (!pw_array_check_index(&impl->permissions, id, struct permission)) + if (!pw_array_check_index(&impl->permissions, id, struct pw_permission)) return NULL; - p = pw_array_get_unchecked(&impl->permissions, id, struct permission); + p = pw_array_get_unchecked(&impl->permissions, id, struct pw_permission); if (p->permissions == -1) return NULL; else return p; } -static struct permission *ensure_permissions(struct pw_client *client, uint32_t id) +static struct pw_permission *ensure_permissions(struct pw_client *client, uint32_t id) { struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this); - struct permission *p; + struct pw_permission *p; size_t len, i; - len = pw_array_get_len(&impl->permissions, struct permission); + len = pw_array_get_len(&impl->permissions, struct pw_permission); if (len <= id) { size_t diff = id - len + 1; - p = pw_array_add(&impl->permissions, diff * sizeof(struct permission)); + p = pw_array_add(&impl->permissions, diff * sizeof(struct pw_permission)); if (p == NULL) return NULL; for (i = 0; i < diff; i++) p[i].permissions = -1; } - p = pw_array_get_unchecked(&impl->permissions, id, struct permission); + p = pw_array_get_unchecked(&impl->permissions, id, struct pw_permission); return p; } @@ -90,7 +85,7 @@ client_permission_func(struct pw_global *global, struct pw_client *client, void *data) { struct impl *impl = data; - struct permission *p; + struct pw_permission *p; p = find_permission(client, global->id); if (p == NULL) @@ -99,26 +94,6 @@ client_permission_func(struct pw_global *global, return p->permissions; } -static uint32_t parse_mask(const char *str) -{ - uint32_t mask = 0; - - while (*str != '\0') { - switch (*str++) { - case 'r': - mask |= PW_PERM_R; - break; - case 'w': - mask |= PW_PERM_W; - break; - case 'x': - mask |= PW_PERM_X; - break; - } - } - return mask; -} - static void client_error(void *object, uint32_t id, int res, const char *error) { struct pw_resource *resource = object; @@ -127,65 +102,21 @@ static void client_error(void *object, uint32_t id, int res, const char *error) pw_resource_error(client->core_resource, id, res, error); } -static void client_get_permissions(void *object) +static void client_get_permissions(void *object, uint32_t index, uint32_t num) { struct pw_resource *resource = object; struct resource_data *data = pw_resource_get_user_data(resource); struct pw_client *client = data->client; + pw_log_debug("client %p", client); } -static void client_update_permissions(void *object, const struct spa_dict *props) +static void client_update_permissions(void *object, + uint32_t n_permissions, const struct pw_permission *permissions) { struct pw_resource *resource = object; struct resource_data *data = pw_resource_get_user_data(resource); struct pw_client *client = data->client; - struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this); - const char *str; - int i, len; - - for (i = 0; i < props->n_items; i++) { - str = props->items[i].value; - - pw_log_debug("client %p: %s %s", client, props->items[i].key, str); - - if (strcmp(props->items[i].key, PW_CORE_PROXY_PERMISSIONS_DEFAULT) == 0) { - impl->permissions_default = parse_mask(str); - pw_log_debug("client %p: set default permissions to %08x", - client, impl->permissions_default); - } - else if (strcmp(props->items[i].key, PW_CORE_PROXY_PERMISSIONS_GLOBAL) == 0) { - struct pw_global *global; - uint32_t global_id, old_perm, new_perm; - struct permission *p; - - /* permissions.update=<global-id>:[r][w][x] */ - len = strcspn(str, ":"); - if (len == 0) - continue; - - global_id = atoi(str); - global = pw_core_find_global(client->core, global_id); - if (global == NULL) { - pw_log_warn("client %p: invalid global %d", client, global_id); - continue; - } - - p = ensure_permissions(client, global_id); - old_perm = p->permissions == -1 ? impl->permissions_default : p->permissions; - new_perm = parse_mask(str + len); - - pw_log_debug("client %p: %08x %08x", client, old_perm, new_perm); - - p->permissions = new_perm; - - if (PW_PERM_IS_R(old_perm) && !PW_PERM_IS_R(new_perm)) { - pw_global_revoke(global, client); - } - else if (!PW_PERM_IS_R(old_perm) && PW_PERM_IS_R(new_perm)) { - pw_global_grant(global, client); - } - } - } + pw_client_update_permissions(client, n_permissions, permissions); pw_client_set_busy(client, false); } @@ -246,7 +177,7 @@ core_global_removed(void *data, struct pw_global *global) { struct impl *impl = data; struct pw_client *client = &impl->this; - struct permission *p; + struct pw_permission *p; p = find_permission(client, global->id); pw_log_debug("client %p: global %d removed, %p", client, global->id, p); @@ -492,91 +423,61 @@ int pw_client_update_properties(struct pw_client *client, const struct spa_dict return changed; } -struct permissions_update { - struct pw_client *client; - uint32_t permissions; - bool only_new; -}; - -static int do_permissions(void *data, struct pw_global *global) +int pw_client_update_permissions(struct pw_client *client, + uint32_t n_permissions, const struct pw_permission *permissions) { - struct permissions_update *update = data; - struct pw_client *client = update->client; struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this); - struct permission *p; - - p = ensure_permissions(client, global->id); - if (p == NULL) - return -ENOMEM; - if (p->permissions == -1) - p->permissions = impl->permissions_default; - else if (update->only_new) - return 0; + struct pw_core *core = client->core; + int i; - p->permissions &= update->permissions; - pw_log_debug("client %p: set global %d permissions to %08x", client, global->id, p->permissions); + for (i = 0; i < n_permissions; i++) { + struct pw_permission *p; + uint32_t old_perm, new_perm; + struct pw_global *global; - return 0; -} + if (permissions[i].id == SPA_ID_INVALID) { + old_perm = impl->permissions_default; + new_perm = permissions[i].permissions; -int pw_client_update_permissions(struct pw_client *client, const struct spa_dict *dict) -{ - struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this); - int i; - const char *str; - size_t len; - struct permissions_update update = { client, 0 }; - uint32_t permissions_existing, permissions_default; + if (core->current_client == client) + new_perm &= old_perm; - permissions_default = impl->permissions_default; - permissions_existing = -1; + pw_log_debug("client %p: set default permissions %08x -> %08x", + client, old_perm, new_perm); - for (i = 0; i < dict->n_items; i++) { - str = dict->items[i].value; + spa_list_for_each(global, &core->global_list, link) { + p = find_permission(client, global->id); + if (p != NULL) + continue; - if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_DEFAULT) == 0) { - permissions_default &= parse_mask(str); - pw_log_debug("client %p: set default permissions to %08x", - client, permissions_default); + pw_global_update_permissions(global, client, old_perm, new_perm); + } + impl->permissions_default = new_perm; } - else if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_GLOBAL) == 0) { + else { struct pw_global *global; - uint32_t global_id; - /* permissions.update=<global-id>:[r][w][x] */ - len = strcspn(str, ":"); - if (len == 0) - continue; - - global_id = atoi(str); - global = pw_core_find_global(client->core, global_id); + global = pw_core_find_global(client->core, permissions[i].id); if (global == NULL) { - pw_log_warn("client %p: invalid global %d", client, global_id); + pw_log_warn("client %p: invalid global %d", client, permissions[i].id); continue; } + p = ensure_permissions(client, global->id); + old_perm = p->permissions == -1 ? impl->permissions_default : p->permissions; + new_perm = permissions[i].permissions; - /* apply the specific updates in order. This is ok for now, we could add - * a field to the permission struct later to accumulate the changes - * and apply them out of this loop */ - update.permissions = parse_mask(str + len); - update.only_new = false; - do_permissions(&update, global); - } - else if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_EXISTING) == 0) { - permissions_existing = parse_mask(str); - pw_log_debug("client %p: set existing permissions to %08x", - client, permissions_existing); + if (core->current_client == client) + new_perm &= old_perm; + + pw_log_debug("client %p: set global %d permissions %08x -> %08x", + client, global->id, old_perm, new_perm); + + pw_global_update_permissions(global, client, old_perm, new_perm); + p->permissions = new_perm; } } - /* apply default and existing permissions after specific ones to make the - * permission update look like an atomic unordered set of changes. */ - if (permissions_existing != -1) { - update.permissions = permissions_existing; - update.only_new = true; - pw_core_for_each_global(client->core, do_permissions, &update); - } - impl->permissions_default = permissions_default; - + if (n_permissions > 0) + pw_client_set_busy(client, false); return 0; } @@ -588,11 +489,3 @@ void pw_client_set_busy(struct pw_client *client, bool busy) pw_client_events_busy_changed(client, busy); } } - -void pw_client_set_permissions(struct pw_client *client, uint32_t permissions) -{ - struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this); - pw_log_debug("client %p: permissions %08x", client, permissions); - impl->permissions_default = permissions; - pw_client_set_busy(client, false); -} diff --git a/src/pipewire/client.h b/src/pipewire/client.h index 64eba357..4a092fe0 100644 --- a/src/pipewire/client.h +++ b/src/pipewire/client.h @@ -49,6 +49,7 @@ struct pw_client; #include <pipewire/introspect.h> #include <pipewire/properties.h> #include <pipewire/resource.h> +#include <pipewire/permission.h> #define PW_TYPE__Client PW_TYPE_OBJECT_BASE "Client" #define PW_TYPE_CLIENT_BASE PW_TYPE__Client ":" @@ -146,7 +147,8 @@ const struct pw_client_info *pw_client_get_info(struct pw_client *client); int pw_client_update_properties(struct pw_client *client, const struct spa_dict *dict); /** Update the client permissions */ -int pw_client_update_permissions(struct pw_client *client, const struct spa_dict *dict); +int pw_client_update_permissions(struct pw_client *client, uint32_t n_permissions, + const struct pw_permission *permissions); /** Get the client properties */ const struct pw_properties *pw_client_get_properties(struct pw_client *client); @@ -177,8 +179,6 @@ void pw_client_add_listener(struct pw_client *client, * started and no further processing is allowed to happen for the client */ void pw_client_set_busy(struct pw_client *client, bool busy); -void pw_client_set_permissions(struct pw_client *client, uint32_t permissions); - #ifdef __cplusplus } #endif diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 678b7a60..5a77f744 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -64,11 +64,11 @@ static void registry_bind(void *object, uint32_t id, if (!PW_PERM_IS_R(permissions)) goto no_id; - if (type != global->type) + if (global->type != type) goto wrong_interface; - pw_log_debug("global %p: bind global id %d, iface %s to %d", global, id, - spa_debug_type_find_name(pw_type_info(), type), new_id); + pw_log_debug("global %p: bind global id %d, iface %s/%d to %d", global, id, + spa_debug_type_find_name(pw_type_info(), type), version, new_id); if (pw_global_bind(global, client, permissions, version, new_id) < 0) goto exit; @@ -77,9 +77,13 @@ static void registry_bind(void *object, uint32_t id, no_id: pw_log_debug("registry %p: no global with id %u to bind to %u", resource, id, new_id); + pw_core_resource_error(client->core_resource, id, + -ENOENT, "no such global %u", id); goto exit; wrong_interface: pw_log_debug("registry %p: global with id %u has no interface %u", resource, id, type); + pw_core_resource_error(client->core_resource, id, + -ENOENT, "no such interface %u", type); goto exit; exit: /* unmark the new_id the map, the client does not yet know about the failed @@ -151,10 +155,11 @@ static void core_client_update(void *object, const struct spa_dict *props) pw_client_update_properties(resource->client, props); } -static void core_permissions(void *object, const struct spa_dict *props) +static void core_permissions(void *object, uint32_t n_permissions, + const struct pw_permission *permissions) { struct pw_resource *resource = object; - pw_client_update_permissions(resource->client, props); + pw_client_update_permissions(resource->client, n_permissions, permissions); } static void core_sync(void *object, uint32_t seq) diff --git a/src/pipewire/core.h b/src/pipewire/core.h index 75c5e1c5..71073bd2 100644 --- a/src/pipewire/core.h +++ b/src/pipewire/core.h @@ -73,16 +73,6 @@ struct pw_core; * resources of a PipeWire instance. */ -#define PW_PERM_R 0400 /**< object can be seen and events can be received */ -#define PW_PERM_W 0200 /**< methods can be called that modify the object */ -#define PW_PERM_X 0100 /**< methods can be called on the object. The W flag must be - * present in order to call methods that modify the object. */ -#define PW_PERM_RWX (PW_PERM_R|PW_PERM_W|PW_PERM_X) - -#define PW_PERM_IS_R(p) (((p)&PW_PERM_R) == PW_PERM_R) -#define PW_PERM_IS_W(p) (((p)&PW_PERM_W) == PW_PERM_W) -#define PW_PERM_IS_X(p) (((p)&PW_PERM_X) == PW_PERM_X) - /** core events emited by the core object added with \ref pw_core_add_listener */ struct pw_core_events { #define PW_VERSION_CORE_EVENTS 0 diff --git a/src/pipewire/global.c b/src/pipewire/global.c index 0110933e..79c965d8 100644 --- a/src/pipewire/global.c +++ b/src/pipewire/global.c @@ -147,17 +147,19 @@ static int global_unregister(struct pw_global *global) { struct impl *impl = SPA_CONTAINER_OF(global, struct impl, this); struct pw_core *core = global->core; - struct pw_resource *registry; + struct pw_resource *resource; if (!impl->registered) return 0; - spa_list_for_each(registry, &core->registry_resource_list, link) { - uint32_t permissions = pw_global_get_permissions(global, registry->client); - pw_log_debug("registry %p: global %d %08x", registry, global->id, permissions); + spa_list_for_each(resource, &core->registry_resource_list, link) { + uint32_t permissions = pw_global_get_permissions(global, resource->client); + pw_log_debug("registry %p: global %d %08x", resource, global->id, permissions); if (PW_PERM_IS_R(permissions)) - pw_registry_resource_global_remove(registry, global->id); + pw_registry_resource_global_remove(resource, global->id); } + spa_list_consume(resource, &global->resource_list, link) + pw_resource_destroy(resource); spa_list_remove(&global->link); pw_core_events_global_removed(core, global); @@ -220,17 +222,17 @@ void pw_global_add_listener(struct pw_global *global, * \param global the global to bind to * \param client the client that binds * \param version the version - * \param id the id + * \param id the id of the resource * * Let \a client bind to \a global with the given version and id. * After binding, the client and the global object will be able to - * exchange messages. + * exchange messages on the proxy/resource with \a id. * * \memberof pw_global */ int pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t permissions, - uint32_t version, uint32_t id) + uint32_t version, uint32_t id) { int res; @@ -241,55 +243,47 @@ pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t perm return 0; - wrong_version: + wrong_version: res = -EINVAL; pw_core_resource_error(client->core_resource, id, - res, "id %d: interface version %d < %d", - id, global->version, version); + res, "id %d: interface version %d < %d", + id, global->version, version); return res; } -int pw_global_grant(struct pw_global *global, struct pw_client *client) +int pw_global_update_permissions(struct pw_global *global, struct pw_client *client, + uint32_t old_permissions, uint32_t new_permissions) { - struct pw_resource *registry; struct pw_core *core = global->core; + struct pw_resource *resource, *t; - spa_list_for_each(registry, &core->registry_resource_list, link) { - uint32_t permissions; - - if (registry->client != client) + spa_list_for_each(resource, &core->registry_resource_list, link) { + if (resource->client != client) continue; - permissions = pw_global_get_permissions(global, client); - - pw_log_debug("registry %p: global %d %08x", registry, global->id, permissions); - if (PW_PERM_IS_R(permissions)) - pw_registry_resource_global(registry, + if (PW_PERM_IS_R(old_permissions) && !PW_PERM_IS_R(new_permissions)) { + pw_registry_resource_global_remove(resource, global->id); + } + else if (!PW_PERM_IS_R(old_permissions) && PW_PERM_IS_R(new_permissions)) { + pw_registry_resource_global(resource, global->id, global->parent->id, - permissions, + new_permissions, global->type, global->version, global->properties ? &global->properties->dict : NULL); - } - return 0; -} - -int pw_global_revoke(struct pw_global *global, struct pw_client *client) -{ - struct pw_resource *registry, *resource, *t; - struct pw_core *core = global->core; - - spa_list_for_each(registry, &core->registry_resource_list, link) { - if (registry->client != client) - continue; - pw_registry_resource_global_remove(registry, global->id); + } } spa_list_for_each_safe(resource, t, &global->resource_list, link) { if (resource->client != client) continue; - pw_resource_destroy(resource); + + /* don't ever destroy the core resource */ + if (!PW_PERM_IS_R(new_permissions) && global->id != 0) + pw_resource_destroy(resource); + else + resource->permissions = new_permissions; } return 0; } diff --git a/src/pipewire/global.h b/src/pipewire/global.h index dcd83127..6eee3670 100644 --- a/src/pipewire/global.h +++ b/src/pipewire/global.h @@ -128,13 +128,8 @@ int pw_global_bind(struct pw_global *global, uint32_t version, uint32_t id); -/** Revoke access to global for client, the global will be removed from - * the client registry and all the bound resources for the client will be - * destroyed */ -int pw_global_revoke(struct pw_global *global, struct pw_client *client); -/** Grant access to a global for client. The client registry will be - * notified of a new global */ -int pw_global_grant(struct pw_global *global, struct pw_client *client); +int pw_global_update_permissions(struct pw_global *global, struct pw_client *client, + uint32_t old_permissions, uint32_t new_permissions); /** Destroy a global */ void pw_global_destroy(struct pw_global *global); diff --git a/src/pipewire/interfaces.h b/src/pipewire/interfaces.h index a2553614..c846909c 100644 --- a/src/pipewire/interfaces.h +++ b/src/pipewire/interfaces.h @@ -30,6 +30,7 @@ extern "C" { #include <pipewire/introspect.h> #include <pipewire/proxy.h> +#include <pipewire/permission.h> struct pw_core_proxy; struct pw_registry_proxy; @@ -143,18 +144,21 @@ struct pw_core_proxy_methods { */ void (*client_update) (void *object, const struct spa_dict *props); /** - * Manage the permissions of the global objects + * Manage the permissions of the global objects for this + * client * * Update the permissions of the global objects using the - * dictionary with properties. + * provided array with permissions * * Globals can use the default permissions or can have specific * permissions assigned to them. * - * \param id the global id to change - * \param props dictionary with permission properties + * \param n_permissions number of permissions + * \param permissions array of permissions */ - void (*permissions) (void *object, const struct spa_dict *props); + void (*permissions) (void *object, + uint32_t n_permissions, + const struct pw_permission *permissions); /** * Create a new object on the PipeWire server from a factory. * Use a \a factory_name of "client-node" to create a @@ -209,9 +213,9 @@ pw_core_proxy_client_update(struct pw_core_proxy *core, const struct spa_dict *p } static inline void -pw_core_proxy_permissions(struct pw_core_proxy *core, const struct spa_dict *props) +pw_core_proxy_permissions(struct pw_core_proxy *core, uint32_t n_permissions, struct pw_permission *permissions) { - pw_proxy_do((struct pw_proxy*)core, struct pw_core_proxy_methods, permissions, props); + pw_proxy_do((struct pw_proxy*)core, struct pw_core_proxy_methods, permissions, n_permissions, permissions); } static inline void * @@ -696,9 +700,15 @@ struct pw_client_proxy_events { * * Event emited as a result of the get_permissions method. * - * \param param the parameter + * \param default_permissions the default permissions + * \param index the index of the first permission entry + * \param n_permissions the number of permissions + * \param permissions the permissions */ - void (*permissions) (void *object, const struct spa_dict *dict); + void (*permissions) (void *object, + uint32_t index, + uint32_t n_permissions, + struct pw_permission *permissions); }; /** Client */ @@ -736,15 +746,20 @@ struct pw_client_proxy_methods { * Get client permissions * * A permissions event will be emited with the permissions. + * + * \param index the first index to query, 0 for first + * \param num the maximum number of items to get */ - void (*get_permissions) (void *object); + void (*get_permissions) (void *object, uint32_t index, uint32_t num); /** * Update client permissions * - * \param dict list of permissions to update + * \param n_permissions number of permissions + * \param permissions array of new permissions */ - void (*update_permissions) (void *object, const struct spa_dict *dict); + void (*update_permissions) (void *object, uint32_t n_permissions, + const struct pw_permission *permissions); }; /** Client permissions */ @@ -755,15 +770,17 @@ pw_client_proxy_error(struct pw_client_proxy *client, uint32_t id, int res, cons } static inline void -pw_client_proxy_get_permissions(struct pw_client_proxy *client) +pw_client_proxy_get_permissions(struct pw_client_proxy *client, uint32_t index, uint32_t num) { - pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, get_permissions); + pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, get_permissions, index, num); } static inline void -pw_client_proxy_update_permissions(struct pw_client_proxy *client, const struct spa_dict *dict) +pw_client_proxy_update_permissions(struct pw_client_proxy *client, uint32_t n_permissions, + const struct pw_permission *permissions) { - pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, update_permissions, dict); + pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, update_permissions, + n_permissions, permissions); } #define PW_VERSION_LINK 0 diff --git a/src/pipewire/permission.h b/src/pipewire/permission.h new file mode 100644 index 00000000..8919dcf1 --- /dev/null +++ b/src/pipewire/permission.h @@ -0,0 +1,60 @@ +/* PipeWire + * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PIPEWIRE_PERMISSION_H__ +#define __PIPEWIRE_PERMISSION_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/utils/defs.h> + +/** \class pw_permission + * + * \brief a PipeWire permission + * + * Permissions are kept for a client and describe what the client is + * allowed to do with an object. + * + * See \ref page_core_api + */ + +#define PW_PERM_R 0400 /**< object can be seen and events can be received */ +#define PW_PERM_W 0200 /**< methods can be called that modify the object */ +#define PW_PERM_X 0100 /**< methods can be called on the object. The W flag must be + * present in order to call methods that modify the object. */ +#define PW_PERM_RWX (PW_PERM_R|PW_PERM_W|PW_PERM_X) + +#define PW_PERM_IS_R(p) (((p)&PW_PERM_R) == PW_PERM_R) +#define PW_PERM_IS_W(p) (((p)&PW_PERM_W) == PW_PERM_W) +#define PW_PERM_IS_X(p) (((p)&PW_PERM_X) == PW_PERM_X) + +struct pw_permission { + uint32_t id; /**< id of object, SPA_ID_INVALID for default permission */ + uint32_t permissions; /**< bitmask of above permissions */ +}; + +#define PW_PERMISSION_INIT(id,p) (struct pw_permission){ (id), (p) } + +#ifdef __cplusplus +} +#endif + +#endif /* __PIPEWIRE_PERMISSION_H__ */ diff --git a/src/tools/pipewire-cli.c b/src/tools/pipewire-cli.c index 1c6838d6..212717c8 100644 --- a/src/tools/pipewire-cli.c +++ b/src/tools/pipewire-cli.c @@ -32,6 +32,7 @@ #include <pipewire/command.h> #include <pipewire/interfaces.h> #include <pipewire/type.h> +#include <pipewire/permission.h> static const char WHITESPACE[] = " \t"; @@ -1164,15 +1165,15 @@ static bool do_port_params(struct data *data, const char *cmd, char *args, char static bool do_permissions(struct data *data, const char *cmd, char *args, char **error) { struct remote_data *rd = data->current; - char *a[2]; + char *a[3]; int n; uint32_t id; struct global *global; - struct spa_dict_item items[1]; + struct pw_permission permissions[1]; - n = pw_split_ip(args, WHITESPACE, 2, a); - if (n < 2) { - asprintf(error, "%s <client-id> <permission>", cmd); + n = pw_split_ip(args, WHITESPACE, 3, a); + if (n < 3) { + asprintf(error, "%s <client-id> <object> <permission>", cmd); return false; } @@ -1191,9 +1192,11 @@ static bool do_permissions(struct data *data, const char *cmd, char *args, char return false; } - items[0] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, a[1]); + + permissions[0] = PW_PERMISSION_INIT(atoi(a[1]), atoi(a[2])); + pw_client_proxy_update_permissions((struct pw_client_proxy*)global->proxy, - &SPA_DICT_INIT(items, 1)); + 1, permissions); return true; } |