From 26f5fc11a671420003e9f3fb42aad52085bd7b60 Mon Sep 17 00:00:00 2001 From: Torkel Niklasson Date: Tue, 28 Apr 2026 15:14:26 +0200 Subject: [PATCH] permission-manager: Add core_permissions support The core object (ID 0) is implicit in the PipeWire connection and never appears in the permission manager's ObjectManager. Add a core_permissions field to set explicit permissions on it independently of default_permissions. --- docs/rst/daemon/configuration/access.rst | 6 +++ lib/wp/permission-manager.c | 37 +++++++++++++++++++ lib/wp/permission-manager.h | 4 ++ modules/module-lua-scripting/api/api.c | 25 ++++++++++++- .../wireplumber.conf.d.examples/access.conf | 6 +++ src/scripts/client/find-config-access.lua | 5 +++ 6 files changed, 81 insertions(+), 2 deletions(-) diff --git a/docs/rst/daemon/configuration/access.rst b/docs/rst/daemon/configuration/access.rst index 6d5ff945..2696a66c 100644 --- a/docs/rst/daemon/configuration/access.rst +++ b/docs/rst/daemon/configuration/access.rst @@ -75,6 +75,7 @@ Example: { name = "custom" default_permissions = "all" + core_permissions = "rx" rules = [ { matches = [ @@ -111,6 +112,11 @@ Each permission manager supports the following properties: ``access.rules`` * ``default_permissions``: the fallback permissions applied to all objects that don't match any rule (applied as ``PW_ID_ANY``) + * ``core_permissions``: permissions applied specifically to the PipeWire core + object (``PW_ID_CORE``, ID 0). This is useful when you want to allow a + client to interact with the core (e.g. enumerate objects, subscribe to + events) while restricting access to individual objects. If not set, the + ``default_permissions`` value is used for the core as well. * ``rules``: a list of match rules with ``set-permissions`` actions that grant specific permissions to objects matching the given constraints diff --git a/lib/wp/permission-manager.c b/lib/wp/permission-manager.c index 48f193ed..0e5a384b 100644 --- a/lib/wp/permission-manager.c +++ b/lib/wp/permission-manager.c @@ -76,6 +76,7 @@ struct _WpPermissionManager WpObject parent; guint32 default_perms; + guint32 core_perms; GPtrArray *clients; GHashTable *matches; @@ -90,6 +91,9 @@ wp_permission_manager_init (WpPermissionManager * self) /* Init default permissions to all */ self->default_perms = PW_PERM_R | PW_PERM_W | PW_PERM_X; + /* Core permissions not set by default (inherit from default_perms) */ + self->core_perms = PW_PERM_INVALID; + /* Init permission interests table */ self->matches = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)permission_interest_free); @@ -271,6 +275,13 @@ build_permissions_array (WpPermissionManager *self, WpClient *client) /* Add default permissions */ g_array_append_val (arr, def_perm); + /* Add core permissions if explicitly set (core is not in the OM since it is + * implicit in the PipeWire connection and not sent through the registry) */ + if (self->core_perms != PW_PERM_INVALID) { + struct pw_permission core_perm = { PW_ID_CORE, self->core_perms }; + g_array_append_val (arr, core_perm); + } + /* Add object specific permissions in the array */ it = wp_object_manager_new_iterator (self->om); for (; wp_iterator_next (it, &value); g_value_unset (&value)) { @@ -512,6 +523,32 @@ wp_permission_manager_set_default_permissions (WpPermissionManager *self, } } +/*! + * \brief Sets the permissions that will be applied to the core object (ID 0). + * + * The core object is not visible to the permission manager's object manager + * because it is implicit in the PipeWire connection and not sent through the + * registry. This method allows setting explicit permissions on it, independent + * of the default permissions. + * + * If not set (or set to PW_PERM_INVALID), the core inherits default_permissions. + * + * \ingroup wppermissionmanager + * \param self the permission manager + * \param permissions the permissions to apply to the core object + */ +void +wp_permission_manager_set_core_permissions (WpPermissionManager *self, + guint32 permissions) +{ + g_return_if_fail (WP_IS_PERMISSION_MANAGER (self)); + + if (self->core_perms != permissions) { + self->core_perms = permissions; + update_permissions (self); + } +} + static guint32 wp_permission_manager_add_match (WpPermissionManager *self, PermissionMatch *match) diff --git a/lib/wp/permission-manager.h b/lib/wp/permission-manager.h index d0708982..073dfb66 100644 --- a/lib/wp/permission-manager.h +++ b/lib/wp/permission-manager.h @@ -54,6 +54,10 @@ WP_API void wp_permission_manager_set_default_permissions ( WpPermissionManager *self, guint32 permissions); +WP_API +void wp_permission_manager_set_core_permissions ( + WpPermissionManager *self, guint32 permissions); + WP_API guint32 wp_permission_manager_add_interest_match (WpPermissionManager *self, WpPermissionMatchCallback callback, gpointer user_data, diff --git a/modules/module-lua-scripting/api/api.c b/modules/module-lua-scripting/api/api.c index 8374807b..3b9dfdde 100644 --- a/modules/module-lua-scripting/api/api.c +++ b/modules/module-lua-scripting/api/api.c @@ -2657,8 +2657,28 @@ permission_manager_set_default_permissions (lua_State *L) } wp_permission_manager_set_default_permissions (pm, perms); - lua_pushboolean (L, TRUE); - return 1; + return 0; +} + +static int +permission_manager_set_core_permissions (lua_State *L) +{ + WpPermissionManager *pm = wplua_checkobject (L, 1, + WP_TYPE_PERMISSION_MANAGER); + guint32 perms = PW_PERM_ALL; + + if (lua_isinteger (L, 2)) { + perms = luaL_checkinteger (L, 2); + } else if (lua_isstring (L, 2)) { + const gchar *perms_str = luaL_checkstring (L, 2); + if (!client_parse_permissions (perms_str, &perms)) + luaL_error (L, "invalid permission string: '%s'", perms_str); + } else { + luaL_error (L, "invalid permission argument"); + } + + wp_permission_manager_set_core_permissions (pm, perms); + return 0; } static int @@ -2726,6 +2746,7 @@ permission_manager_update_permissions (lua_State *L) static const luaL_Reg permission_manager_funcs[] = { { "set_default_permissions", permission_manager_set_default_permissions }, + { "set_core_permissions", permission_manager_set_core_permissions }, { "add_interest_match", permission_manager_add_interest_match }, { "add_interest_match_simple", permission_manager_add_interest_match_simple }, { "add_rules_match", permission_manager_add_rules_match }, diff --git a/src/config/wireplumber.conf.d.examples/access.conf b/src/config/wireplumber.conf.d.examples/access.conf index 4da8b0c9..da1a4d7d 100644 --- a/src/config/wireplumber.conf.d.examples/access.conf +++ b/src/config/wireplumber.conf.d.examples/access.conf @@ -12,6 +12,12 @@ access.permission-managers = [ # ## The default permissions to apply on all objects that dont have a match # default_permissions = "all" # + # ## The permissions to apply specifically on the PipeWire core object + # ## (ID 0). This is useful to allow clients to interact with the core + # ## (e.g. enumerate objects) while restricting access to individual objects. + # ## If not set, the default_permissions value is used for the core as well. + # core_permissions = "rx" + # # ## The rules to apply specific permissions to matched objects # rules = [ # { diff --git a/src/scripts/client/find-config-access.lua b/src/scripts/client/find-config-access.lua index ac83e4b0..835405ee 100644 --- a/src/scripts/client/find-config-access.lua +++ b/src/scripts/client/find-config-access.lua @@ -30,6 +30,11 @@ for _, pm_info in ipairs (config_pm_table) do config_pm:set_default_permissions (pm_info.default_permissions) end + -- Set core permissions if defined + if pm_info.core_permissions ~= nil then + config_pm:set_core_permissions (pm_info.core_permissions) + end + -- Set rules match if defined if pm_info.rules ~= nil then config_pm:add_rules_match (Json.Raw (pm_info.rules))