diff --git a/spa/include/spa/utils/dict.h b/spa/include/spa/utils/dict.h index c95e9595d..0abbb50e3 100644 --- a/spa/include/spa/utils/dict.h +++ b/spa/include/spa/utils/dict.h @@ -36,6 +36,8 @@ struct spa_dict_item { const char *value; }; +#define SPA_DICT_ITEM_INIT(key,value) (struct spa_dict_item) { key, value } + struct spa_dict { const struct spa_dict_item *items; uint32_t n_items; diff --git a/src/examples/export-sink.c b/src/examples/export-sink.c index b5c7e80ef..c02503758 100644 --- a/src/examples/export-sink.c +++ b/src/examples/export-sink.c @@ -554,22 +554,21 @@ 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[3]; + 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, "---"); /* 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[0].key = PW_CORE_PROXY_PERMISSIONS_GLOBAL; - items[0].value = "0:rw-"; - /* set specific permissions on all existing objects without permissions */ - items[1].key = PW_CORE_PROXY_PERMISSIONS_EXISTING; - items[1].value = "r--"; - /* set default permission for new objects and objects without - * specific permissions */ - items[2].key = PW_CORE_PROXY_PERMISSIONS_DEFAULT; - items[2].value = "---"; + items[i++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, "0:rw-"); + pw_core_proxy_permissions(pw_remote_get_core_proxy(data->remote), - &SPA_DICT_INIT(items, SPA_N_ELEMENTS(items))); + &SPA_DICT_INIT(items, i)); make_node(data); break; diff --git a/src/modules/module-autolink.c b/src/modules/module-autolink.c index 45353b88e..356327fea 100644 --- a/src/modules/module-autolink.c +++ b/src/modules/module-autolink.c @@ -185,6 +185,8 @@ static void try_link_port(struct pw_node *node, struct pw_port *port, struct nod struct pw_link *link; struct pw_port *target; struct link_data *ld; + struct pw_global *global = pw_node_get_global(info->node); + struct pw_client *owner = pw_global_get_owner(global); props = pw_node_get_properties(node); @@ -202,7 +204,7 @@ static void try_link_port(struct pw_node *node, struct pw_port *port, struct nod pw_log_debug("module %p: try to find and link to node '%d'", impl, path_id); - target = pw_core_find_port(impl->core, port, path_id, NULL, 0, NULL, &error); + target = pw_core_find_port(impl->core, owner, port, path_id, NULL, 0, NULL, &error); if (target == NULL) goto error; @@ -234,12 +236,8 @@ static void try_link_port(struct pw_node *node, struct pw_port *port, struct nod error: pw_log_error("module %p: can't link node '%s'", impl, error); - { - struct pw_global *global = pw_node_get_global(info->node); - struct pw_client *owner = pw_global_get_owner(global); - if (owner) - pw_resource_error(pw_client_get_core_resource(owner), -EINVAL, error); - } + if (owner) + pw_resource_error(pw_client_get_core_resource(owner), -EINVAL, error); free(error); return; } diff --git a/src/modules/module-jack.c b/src/modules/module-jack.c index 370e53c9c..58f3ff950 100644 --- a/src/modules/module-jack.c +++ b/src/modules/module-jack.c @@ -1351,7 +1351,7 @@ static bool init_nodes(struct impl *impl) make_audio_client(impl); make_freewheel_client(impl); - pw_core_for_each_global(core, on_global, impl); + pw_core_for_each_global(core, NULL, on_global, impl); return true; } diff --git a/src/modules/module-link-factory.c b/src/modules/module-link-factory.c index 5be8d5a79..9c1219ffc 100644 --- a/src/modules/module-link-factory.c +++ b/src/modules/module-link-factory.c @@ -83,13 +83,13 @@ static void *create_object(void *_data, core = pw_client_get_core(client); t = pw_core_get_type(core); - global = pw_core_find_global(core, output_node_id); + global = pw_core_find_global(core, client, output_node_id); if (global == NULL || pw_global_get_type(global) != t->node) goto no_output; output_node = pw_global_get_object(global); - global = pw_core_find_global(core, input_node_id); + global = pw_core_find_global(core, client, input_node_id); if (global == NULL || pw_global_get_type(global) != t->node) goto no_input; diff --git a/src/modules/module-mixer.c b/src/modules/module-mixer.c index f3c1a2f34..5dd51298b 100644 --- a/src/modules/module-mixer.c +++ b/src/modules/module-mixer.c @@ -233,7 +233,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie spa_list_init(&impl->node_list); - pw_core_for_each_global(core, on_global, impl); + pw_core_for_each_global(core, NULL, on_global, impl); pw_core_add_listener(core, &impl->core_listener, &core_events, impl); pw_module_add_listener(module, &impl->module_listener, &module_events, impl); diff --git a/src/pipewire/client.c b/src/pipewire/client.c index b4354cda7..02bd943a4 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -426,14 +426,18 @@ int pw_client_update_permissions(struct pw_client *client, const struct spa_dict const char *str; size_t len; struct permissions_update update = { client, 0 }; + uint32_t permissions_existing, permissions_default; + + permissions_default = impl->permissions_default; + permissions_existing = -1; for (i = 0; i < dict->n_items; i++) { str = dict->items[i].value; if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_DEFAULT) == 0) { - impl->permissions_default &= parse_mask(str); + permissions_default &= parse_mask(str); pw_log_debug("client %p: set default permissions to %08x", - client, impl->permissions_default); + client, permissions_default); } else if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_GLOBAL) == 0) { struct pw_global *global; @@ -445,22 +449,34 @@ int pw_client_update_permissions(struct pw_client *client, const struct spa_dict continue; global_id = atoi(str); - global = pw_core_find_global(client->core, global_id); + global = pw_core_find_global(client->core, client, global_id); if (global == NULL) { pw_log_warn("client %p: invalid global %d", client, global_id); continue; } + /* 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) { - update.permissions = parse_mask(str); - update.only_new = true; - pw_core_for_each_global(client->core, do_permissions, &update); + permissions_existing = parse_mask(str); + pw_log_debug("client %p: set existing permissions to %08x", + client, permissions_existing); } } + /* 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, client, do_permissions, &update); + } + impl->permissions_default = permissions_default; + return 0; } diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 9935b843b..611a91a47 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -51,7 +51,7 @@ static void registry_bind(void *object, uint32_t id, struct pw_global *global; uint32_t permissions; - if ((global = pw_core_find_global(core, id)) == NULL) + if ((global = pw_core_find_global(core, NULL, id)) == NULL) goto no_id; permissions = pw_global_get_permissions(global, client); @@ -198,7 +198,10 @@ core_create_object(void *object, struct pw_properties *properties; factory = pw_core_find_factory(client->core, factory_name); - if (factory == NULL) + if (factory == NULL || factory->global == NULL) + goto no_factory; + + if (!PW_PERM_IS_R(pw_global_get_permissions(factory->global, client))) goto no_factory; if (factory->info.type != type) @@ -544,21 +547,34 @@ int pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict) } int pw_core_for_each_global(struct pw_core *core, + struct pw_client *client, int (*callback) (void *data, struct pw_global *global), void *data) { struct pw_global *g, *t; int res; - spa_list_for_each_safe(g, t, &core->global_list, link) + spa_list_for_each_safe(g, t, &core->global_list, link) { + if (client && !PW_PERM_IS_R(pw_global_get_permissions(g, client))) + continue; if ((res = callback(data, g)) != 0) return res; + } return 0; } -struct pw_global *pw_core_find_global(struct pw_core *core, uint32_t id) +struct pw_global *pw_core_find_global(struct pw_core *core, struct pw_client *client, uint32_t id) { - return pw_map_lookup(&core->globals, id); + struct pw_global *global; + + global = pw_map_lookup(&core->globals, id); + if (global == NULL) + return NULL; + + if (client && !PW_PERM_IS_R(pw_global_get_permissions(global, client))) + return NULL; + + return global; } /** Find a port to link with @@ -575,6 +591,7 @@ struct pw_global *pw_core_find_global(struct pw_core *core, uint32_t id) * \memberof pw_core */ struct pw_port *pw_core_find_port(struct pw_core *core, + struct pw_client *client, struct pw_port *other_port, uint32_t id, struct pw_properties *props, @@ -597,6 +614,9 @@ struct pw_port *pw_core_find_port(struct pw_core *core, if (other_port->node == n) continue; + if (!PW_PERM_IS_R(pw_global_get_permissions(n->global, client))) + continue; + pw_log_debug("node id \"%d\"", n->global->id); if (have_id) { @@ -774,7 +794,8 @@ int pw_core_find_format(struct pw_core *core, * * \memberof pw_core */ -struct pw_factory *pw_core_find_factory(struct pw_core *core, const char *name) +struct pw_factory *pw_core_find_factory(struct pw_core *core, + const char *name) { struct pw_factory *factory; diff --git a/src/pipewire/core.h b/src/pipewire/core.h index 566d6f8e2..d9ed4c502 100644 --- a/src/pipewire/core.h +++ b/src/pipewire/core.h @@ -159,16 +159,20 @@ struct pw_loop *pw_core_get_main_loop(struct pw_core *core); * 0 to fetch the next item, any other value stops the iteration and returns * the value. When all callbacks return 0, this function returns 0 when all * globals are iterated. */ -int pw_core_for_each_global(struct pw_core *core, +int pw_core_for_each_global(struct pw_core *core, /**< the core */ + struct pw_client *client, /**< optional client */ int (*callback) (void *data, struct pw_global *global), void *data); /** Find a core global by id */ -struct pw_global *pw_core_find_global(struct pw_core *core, uint32_t id); +struct pw_global *pw_core_find_global(struct pw_core *core, /**< the core */ + struct pw_client *client, /**< optional client */ + uint32_t id /**< the global id */); /** Find a factory by name */ struct pw_factory * -pw_core_find_factory(struct pw_core *core, const char *name); +pw_core_find_factory(struct pw_core *core /**< the core */, + const char *name /**< the factory name */); #ifdef __cplusplus } diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 1f1e7418d..d79526bb4 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -434,6 +434,7 @@ int pw_core_find_format(struct pw_core *core, /** Find a ports compatible with \a other_port and the format filters */ struct pw_port * pw_core_find_port(struct pw_core *core, + struct pw_client *client, struct pw_port *other_port, uint32_t id, struct pw_properties *props, diff --git a/src/tools/pipewire-cli.c b/src/tools/pipewire-cli.c index 83a4ad67b..2d2dfa70d 100644 --- a/src/tools/pipewire-cli.c +++ b/src/tools/pipewire-cli.c @@ -1001,7 +1001,7 @@ static bool do_export_node(struct data *data, const char *cmd, char *args, char goto no_remote; } - global = pw_core_find_global(data->core, atoi(a[0])); + global = pw_core_find_global(data->core, NULL, atoi(a[0])); if (global == NULL) { asprintf(error, "object %d does not exist", atoi(a[0])); return false;