diff --git a/src/gst/gstpipewiredeviceprovider.c b/src/gst/gstpipewiredeviceprovider.c index fe62e8f9a..b52cff48b 100644 --- a/src/gst/gstpipewiredeviceprovider.c +++ b/src/gst/gstpipewiredeviceprovider.c @@ -328,7 +328,7 @@ static const struct pw_node_events node_events = { }; -static void registry_event_global(void *object, uint32_t id, uint32_t parent_id, +static void registry_event_global(void *object, uint32_t id, uint32_t parent_id, uint32_t permissions, uint32_t type, uint32_t version) { struct pw_registry_proxy *registry = object; diff --git a/src/modules/module-flatpak.c b/src/modules/module-flatpak.c index 297cad50e..f6a712c6b 100644 --- a/src/modules/module-flatpak.c +++ b/src/modules/module-flatpak.c @@ -211,14 +211,14 @@ check_global_owner(struct pw_core *core, struct pw_client *client, struct pw_glo if (global->owner == NULL) return true; - if (global->owner->client->ucred.uid == client->ucred.uid) + if (global->owner->ucred.uid == client->ucred.uid) return true; return false; } -static bool -do_global_filter(struct pw_global *global, struct pw_client *client, void *data) +static uint32_t +do_permission(struct pw_global *global, struct pw_client *client, void *data) { if (global->type == client->core->type.link) { struct pw_link *link = global->object; @@ -226,16 +226,16 @@ do_global_filter(struct pw_global *global, struct pw_client *client, void *data) /* we must be able to see both nodes */ if (link->output && !check_global_owner(client->core, client, link->output->node->global)) - return false; + return 0; if (link->input && !check_global_owner(client->core, client, link->input->node->global)) - return false; + return 0; } else if (!check_global_owner(client->core, client, global)) - return false; + return 0; - return true; + return PW_PERM_RWX; } static DBusHandlerResult @@ -691,8 +691,8 @@ static struct impl *module_new(struct pw_core *core, struct pw_properties *prope pw_signal_add(&core->global_added, &impl->global_added, on_global_added); pw_signal_add(&core->global_removed, &impl->global_removed, on_global_removed); - core->global_filter = do_global_filter; - core->global_filter_data = impl; + core->permission_func = do_permission; + core->permission_data = impl; return impl; diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index b045d9bb6..e7c8c6cab 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -234,7 +234,7 @@ static struct pw_client *client_new(struct listener *l, int fd) pw_signal_add(&client->busy_changed, &this->busy_changed, on_busy_changed); - pw_global_bind(protocol->core->global, client, PW_VERSION_CORE, 0); + pw_global_bind(protocol->core->global, client, PW_PERM_RWX, PW_VERSION_CORE, 0); return client; diff --git a/src/modules/module-protocol-native/protocol-native.c b/src/modules/module-protocol-native/protocol-native.c index 594a1492c..b7e9e2d7d 100644 --- a/src/modules/module-protocol-native/protocol-native.c +++ b/src/modules/module-protocol-native/protocol-native.c @@ -529,7 +529,7 @@ static bool core_demarshal_update_types_server(void *object, void *data, size_t return true; } -static void registry_marshal_global(void *object, uint32_t id, uint32_t parent_id, +static void registry_marshal_global(void *object, uint32_t id, uint32_t parent_id, uint32_t permissions, uint32_t type, uint32_t version) { struct pw_resource *resource = object; @@ -541,6 +541,7 @@ static void registry_marshal_global(void *object, uint32_t id, uint32_t parent_i spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, id, SPA_POD_TYPE_INT, parent_id, + SPA_POD_TYPE_INT, permissions, SPA_POD_TYPE_ID, type, SPA_POD_TYPE_INT, version); @@ -827,18 +828,19 @@ static bool registry_demarshal_global(void *object, void *data, size_t size) { struct pw_proxy *proxy = object; struct spa_pod_iter it; - uint32_t id, parent_id, type, version; + uint32_t id, parent_id, permissions, type, version; if (!spa_pod_iter_struct(&it, data, size) || !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) || !spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &id, SPA_POD_TYPE_INT, &parent_id, + SPA_POD_TYPE_INT, &permissions, SPA_POD_TYPE_ID, &type, SPA_POD_TYPE_INT, &version, 0)) return false; - pw_proxy_notify(proxy, struct pw_registry_events, global, id, parent_id, type, version); + pw_proxy_notify(proxy, struct pw_registry_events, global, id, parent_id, permissions, type, version); return true; } diff --git a/src/pipewire/client.c b/src/pipewire/client.c index b72582146..90cd53134 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -39,13 +39,13 @@ static void client_unbind_func(void *data) static int client_bind_func(struct pw_global *global, - struct pw_client *client, + struct pw_client *client, uint32_t permissions, uint32_t version, uint32_t id) { struct pw_client *this = global->object; struct pw_resource *resource; - resource = pw_resource_new(client, id, global->type, version, 0, client_unbind_func); + resource = pw_resource_new(client, id, permissions, global->type, version, 0, client_unbind_func); if (resource == NULL) goto no_mem; @@ -116,7 +116,7 @@ struct pw_client *pw_client_new(struct pw_core *core, this->info.props = this->properties ? &this->properties->dict : NULL; - this->global = pw_core_add_global(core, NULL, parent, core->type.client, PW_VERSION_CLIENT, + this->global = pw_core_add_global(core, this, parent, core->type.client, PW_VERSION_CLIENT, client_bind_func, this); return this; diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 2a0301479..75ce60231 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -43,15 +43,19 @@ struct impl { /** \endcond */ -static bool pw_global_is_visible(struct pw_global *global, - struct pw_client *client) +static inline uint32_t pw_global_permissions(struct pw_global *global, + struct pw_client *client) { struct pw_core *core = client->core; - return (core->global_filter == NULL || - core->global_filter(global, client, core->global_filter_data)); + if (core->permission_func == NULL) + return PW_PERM_RWX; + + return core->permission_func(global, client, core->permission_data); } +#define PW_PERM_IS_R(p) (((p)&PW_PERM_R) == PW_PERM_R) + static struct pw_global *find_global(struct pw_core *core, uint32_t id) { struct pw_global *global; @@ -69,11 +73,14 @@ static void registry_bind(void *object, uint32_t id, struct pw_client *client = resource->client; struct pw_core *core = resource->core; struct pw_global *global; + uint32_t permissions; if ((global = find_global(core, id)) == 0) goto no_id; - if (!pw_global_is_visible(global, client)) + permissions = pw_global_permissions(global, client); + + if (!PW_PERM_IS_R(permissions)) goto no_id; if (type != global->type) @@ -82,7 +89,7 @@ static void registry_bind(void *object, uint32_t id, pw_log_debug("global %p: bind global id %d, iface %s to %d", global, id, spa_type_map_get_type(core->type.map, type), new_id); - pw_global_bind(global, client, version, new_id); + pw_global_bind(global, client, permissions, version, new_id); return; @@ -136,6 +143,7 @@ static void core_get_registry(void *object, uint32_t version, uint32_t new_id) registry_resource = pw_resource_new(client, new_id, + PW_PERM_RWX, this->type.registry, version, 0, destroy_registry_resource); @@ -149,10 +157,12 @@ static void core_get_registry(void *object, uint32_t version, uint32_t new_id) spa_list_insert(this->registry_resource_list.prev, ®istry_resource->link); spa_list_for_each(global, &this->global_list, link) { - if (pw_global_is_visible(global, client)) { + uint32_t permissions = pw_global_permissions(global, client); + if (PW_PERM_IS_R(permissions)) { pw_registry_resource_global(registry_resource, global->id, global->parent->id, + permissions, global->type, global->version); } @@ -185,7 +195,7 @@ core_create_node(void *object, if (factory == NULL) goto no_factory; - node_resource = pw_resource_new(client, new_id, type, version, 0, NULL); + node_resource = pw_resource_new(client, new_id, PW_PERM_RWX, type, version, 0, NULL); if (node_resource == NULL) goto no_resource; @@ -274,13 +284,14 @@ static void core_unbind_func(void *data) static int core_bind_func(struct pw_global *global, struct pw_client *client, + uint32_t permissions, uint32_t version, uint32_t id) { struct pw_core *this = global->object; struct pw_resource *resource; - resource = pw_resource_new(client, id, global->type, version, 0, core_unbind_func); + resource = pw_resource_new(client, id, permissions, global->type, version, 0, core_unbind_func); if (resource == NULL) goto no_mem; @@ -328,7 +339,7 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro this->main_loop = main_loop; pw_type_init(&this->type); - pw_map_init(&this->objects, 128, 32); + pw_map_init(&this->globals, 128, 32); spa_graph_init(&this->rt.graph); spa_graph_scheduler_init(&this->rt.sched, &this->rt.graph); @@ -402,7 +413,7 @@ void pw_core_destroy(struct pw_core *core) pw_data_loop_destroy(impl->data_loop); - pw_map_clear(&core->objects); + pw_map_clear(&core->globals); pw_log_debug("core %p: free", core); free(impl); @@ -424,7 +435,7 @@ void pw_core_destroy(struct pw_core *core) */ struct pw_global * pw_core_add_global(struct pw_core *core, - struct pw_resource *owner, + struct pw_client *owner, struct pw_global *parent, uint32_t type, uint32_t version, @@ -450,10 +461,10 @@ pw_core_add_global(struct pw_core *core, pw_signal_init(&this->destroy_signal); - this->id = pw_map_insert_new(&core->objects, this); + this->id = pw_map_insert_new(&core->globals, this); - if (owner && owner->client) - parent = owner->client->global; + if (owner) + parent = owner->global; if (parent == NULL) parent = core->global; if (parent == NULL) @@ -466,11 +477,16 @@ pw_core_add_global(struct pw_core *core, pw_log_debug("global %p: new %u %s, owner %p", this, this->id, spa_type_map_get_type(core->type.map, this->type), owner); - spa_list_for_each(registry, &core->registry_resource_list, link) - if (pw_global_is_visible(this, registry->client)) - pw_registry_resource_global(registry, this->id, this->parent->id, - this->type, this->version); - + spa_list_for_each(registry, &core->registry_resource_list, link) { + uint32_t permissions = pw_global_permissions(this, registry->client); + if (PW_PERM_IS_R(permissions)) + pw_registry_resource_global(registry, + this->id, + this->parent->id, + permissions, + this->type, + this->version); + } return this; } @@ -488,7 +504,7 @@ pw_core_add_global(struct pw_core *core, * \memberof pw_global */ int -pw_global_bind(struct pw_global *global, struct pw_client *client, +pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t permissions, uint32_t version, uint32_t id) { int res; @@ -499,7 +515,7 @@ pw_global_bind(struct pw_global *global, struct pw_client *client, if (global->version < version) goto wrong_version; - res = global->bind(global, client, version, id); + res = global->bind(global, client, permissions, version, id); return res; @@ -532,11 +548,13 @@ void pw_global_destroy(struct pw_global *global) pw_log_debug("global %p: destroy %u", global, global->id); pw_signal_emit(&global->destroy_signal, global); - spa_list_for_each(registry, &core->registry_resource_list, link) - if (pw_global_is_visible(global, registry->client)) + spa_list_for_each(registry, &core->registry_resource_list, link) { + uint32_t permissions = pw_global_permissions(global, registry->client); + if (PW_PERM_IS_R(permissions)) pw_registry_resource_global_remove(registry, global->id); + } - pw_map_remove(&core->objects, global->id); + pw_map_remove(&core->globals, global->id); spa_list_remove(&global->link); pw_signal_emit(&core->global_removed, core, global); diff --git a/src/pipewire/core.h b/src/pipewire/core.h index 4edb0f5ab..1392b5559 100644 --- a/src/pipewire/core.h +++ b/src/pipewire/core.h @@ -92,11 +92,17 @@ struct pw_global; */ typedef int (*pw_bind_func_t) (struct pw_global *global, /**< the global to bind */ struct pw_client *client, /**< client that binds */ + uint32_t permissions, /**< permissions for the bind */ uint32_t version, /**< client interface version */ uint32_t id); /**< client proxy id */ -typedef bool (*pw_global_filter_func_t) (struct pw_global *global, - struct pw_client *client, void *data); +#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) +typedef uint32_t (*pw_permission_func_t) (struct pw_global *global, + struct pw_client *client, void *data); /** \page page_global Global * @@ -122,7 +128,7 @@ typedef bool (*pw_global_filter_func_t) (struct pw_global *global, */ struct pw_global { struct pw_core *core; /**< the core */ - struct pw_resource *owner; /**< the owner of this object, NULL when the + struct pw_client *owner; /**< the owner of this object, NULL when the * PipeWire server is the owner */ struct spa_list link; /**< link in core list of globals */ @@ -157,12 +163,12 @@ struct pw_core { struct pw_properties *properties; /**< properties of the core */ - struct pw_type type; /**< type map and common types */ + struct pw_type type; /**< type map and common types */ - pw_global_filter_func_t global_filter; - void *global_filter_data; + pw_permission_func_t permission_func; /**< get permissions of an object */ + void *permission_data; /**< data passed to permission function */ - struct pw_map objects; /**< map of known objects */ + struct pw_map globals; /**< map of globals */ struct spa_list protocol_list; /**< list of protocols */ struct spa_list remote_list; /**< list of remote connections */ @@ -208,7 +214,7 @@ pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict); struct pw_global * pw_core_add_global(struct pw_core *core, - struct pw_resource *owner, + struct pw_client *owner, struct pw_global *parent, uint32_t type, uint32_t version, @@ -218,6 +224,7 @@ pw_core_add_global(struct pw_core *core, int pw_global_bind(struct pw_global *global, struct pw_client *client, + uint32_t permissions, uint32_t version, uint32_t id); diff --git a/src/pipewire/interfaces.h b/src/pipewire/interfaces.h index 634b2fd8b..ee38dabb3 100644 --- a/src/pipewire/interfaces.h +++ b/src/pipewire/interfaces.h @@ -365,10 +365,12 @@ struct pw_registry_events { * * \param id the global object id * \param parent_id the parent global id + * \param permissions the permissions of the object * \param type the type of the interface * \param version the version of the interface */ - void (*global) (void *object, uint32_t id, uint32_t parent_id, uint32_t type, uint32_t version); + void (*global) (void *object, uint32_t id, uint32_t parent_id, + uint32_t permissions, uint32_t type, uint32_t version); /** * Notify of a global object removal * diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 258a56211..ffbdb7f7d 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -940,13 +940,13 @@ static void link_unbind_func(void *data) static int link_bind_func(struct pw_global *global, - struct pw_client *client, + struct pw_client *client, uint32_t permissions, uint32_t version, uint32_t id) { struct pw_link *this = global->object; struct pw_resource *resource; - resource = pw_resource_new(client, id, global->type, version, 0, link_unbind_func); + resource = pw_resource_new(client, id, permissions, global->type, version, 0, link_unbind_func); if (resource == NULL) goto no_mem; diff --git a/src/pipewire/module.c b/src/pipewire/module.c index d212f7fac..39cdafaee 100644 --- a/src/pipewire/module.c +++ b/src/pipewire/module.c @@ -89,13 +89,13 @@ static char *find_module(const char *path, const char *name) static int module_bind_func(struct pw_global *global, - struct pw_client *client, + struct pw_client *client, uint32_t permissions, uint32_t version, uint32_t id) { struct pw_module *this = global->object; struct pw_resource *resource; - resource = pw_resource_new(client, id, global->type, version, 0, NULL); + resource = pw_resource_new(client, id, permissions, global->type, version, 0, NULL); if (resource == NULL) goto no_mem; diff --git a/src/pipewire/node.c b/src/pipewire/node.c index efda00918..fce9f8cef 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -229,13 +229,13 @@ clear_info(struct pw_node *this) static int node_bind_func(struct pw_global *global, - struct pw_client *client, + struct pw_client *client, uint32_t permissions, uint32_t version, uint32_t id) { struct pw_node *this = global->object; struct pw_resource *resource; - resource = pw_resource_new(client, id, global->type, version, 0, node_unbind_func); + resource = pw_resource_new(client, id, permissions, global->type, version, 0, node_unbind_func); if (resource == NULL) goto no_mem; @@ -282,7 +282,8 @@ void pw_node_register(struct pw_node *this) pw_loop_invoke(this->data_loop, do_node_add, 1, 0, NULL, false, this); spa_list_insert(core->node_list.prev, &this->link); - this->global = pw_core_add_global(core, this->owner, impl->parent, + this->global = pw_core_add_global(core, this->owner ? this->owner->client : NULL, + impl->parent, core->type.node, PW_VERSION_NODE, node_bind_func, this); diff --git a/src/pipewire/resource.c b/src/pipewire/resource.c index 245d5e96e..dbdea341a 100644 --- a/src/pipewire/resource.c +++ b/src/pipewire/resource.c @@ -31,6 +31,7 @@ struct impl { struct pw_resource *pw_resource_new(struct pw_client *client, uint32_t id, + uint32_t permissions, uint32_t type, uint32_t version, size_t user_data_size, @@ -46,6 +47,7 @@ struct pw_resource *pw_resource_new(struct pw_client *client, this = &impl->this; this->core = client->core; this->client = client; + this->permissions = permissions; this->type = type; this->version = version; diff --git a/src/pipewire/resource.h b/src/pipewire/resource.h index 8e85f9014..7d8bcefef 100644 --- a/src/pipewire/resource.h +++ b/src/pipewire/resource.h @@ -64,6 +64,7 @@ struct pw_resource { struct pw_client *client; /**< owner client */ uint32_t id; /**< per client unique id, index in client objects */ + uint32_t permissions; /**< resource permissions */ uint32_t type; /**< type of the client interface */ uint32_t version; /**< version of the client interface */ @@ -85,6 +86,7 @@ struct pw_resource { struct pw_resource * pw_resource_new(struct pw_client *client, /**< the client owning the resource */ uint32_t id, /**< the remote per client id */ + uint32_t permissions, /**< permissions on this resource */ uint32_t type, /**< interface of the resource */ uint32_t version, /**< requested interface version */ size_t user_data_size, /**< extra user data size */ diff --git a/src/tools/pipewire-monitor.c b/src/tools/pipewire-monitor.c index c9b8d36da..8fb5863d2 100644 --- a/src/tools/pipewire-monitor.c +++ b/src/tools/pipewire-monitor.c @@ -40,6 +40,7 @@ struct data { struct proxy_data { uint32_t id; uint32_t parent_id; + uint32_t permissions; uint32_t version; void *info; }; @@ -95,6 +96,9 @@ static void module_event_info(void *object, struct pw_module_info *info) printf("\tid: %d\n", data->id); printf("\tparent_id: %d\n", data->parent_id); + printf("\tpermissions: %c%c%c\n", data->permissions & PW_PERM_R ? 'r' : '-', + data->permissions & PW_PERM_W ? 'w' : '-', + data->permissions & PW_PERM_X ? 'x' : '-'); printf("\ttype: %s (version %d)\n", PW_TYPE_INTERFACE__Module, data->version); if (print_all) { printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name); @@ -129,6 +133,9 @@ static void node_event_info(void *object, struct pw_node_info *info) printf("\tid: %d\n", data->id); printf("\tparent_id: %d\n", data->parent_id); + printf("\tpermissions: %c%c%c\n", data->permissions & PW_PERM_R ? 'r' : '-', + data->permissions & PW_PERM_W ? 'w' : '-', + data->permissions & PW_PERM_X ? 'x' : '-'); printf("\ttype: %s (version %d)\n", PW_TYPE_INTERFACE__Node, data->version); if (print_all) { int i; @@ -178,6 +185,9 @@ static void client_event_info(void *object, struct pw_client_info *info) printf("\tid: %d\n", data->id); printf("\tparent_id: %d\n", data->parent_id); + printf("\tpermissions: %c%c%c\n", data->permissions & PW_PERM_R ? 'r' : '-', + data->permissions & PW_PERM_W ? 'w' : '-', + data->permissions & PW_PERM_X ? 'x' : '-'); printf("\ttype: %s (version %d)\n", PW_TYPE_INTERFACE__Client, data->version); if (print_all) { print_properties(info->props, MARK_CHANGE(0)); @@ -209,6 +219,9 @@ static void link_event_info(void *object, struct pw_link_info *info) printf("\tid: %d\n", data->id); printf("\tparent_id: %d\n", data->parent_id); + printf("\tpermissions: %c%c%c\n", data->permissions & PW_PERM_R ? 'r' : '-', + data->permissions & PW_PERM_W ? 'w' : '-', + data->permissions & PW_PERM_X ? 'x' : '-'); printf("\ttype: %s (version %d)\n", PW_TYPE_INTERFACE__Link, data->version); if (print_all) { printf("%c\toutput-node-id: %u\n", MARK_CHANGE(0), info->output_node_id); @@ -258,7 +271,7 @@ destroy_proxy (void *data) static void registry_event_global(void *object, uint32_t id, uint32_t parent_id, - uint32_t type, uint32_t version) + uint32_t permissions, uint32_t type, uint32_t version) { struct pw_proxy *proxy = object; struct data *data = proxy->object; @@ -287,6 +300,9 @@ static void registry_event_global(void *object, uint32_t id, uint32_t parent_id, printf("added:\n"); printf("\tid: %u\n", id); printf("\tparent_id: %d\n", parent_id); + printf("\tpermissions: %c%c%c\n", permissions & PW_PERM_R ? 'r' : '-', + permissions & PW_PERM_W ? 'w' : '-', + permissions & PW_PERM_X ? 'x' : '-'); printf("\ttype: %s (version %d)\n", spa_type_map_get_type(core->type.map, type), version); return; } @@ -299,6 +315,7 @@ static void registry_event_global(void *object, uint32_t id, uint32_t parent_id, pd = proxy->user_data; pd->id = id; pd->parent_id = parent_id; + pd->permissions = permissions; pd->version = version; pw_proxy_add_listener(proxy, proxy, events);