From 1066ec98a82e87a07f8fac33f20c63e950be4c42 Mon Sep 17 00:00:00 2001 From: Torkel Niklasson Date: Mon, 25 May 2026 14:32:33 +0200 Subject: [PATCH] protocol-native: expose client supplementary GIDs Retrieve the connecting client's supplementary group list via SO_PEERGROUPS and store it as the "pipewire.sec.gids" property. This allows access-control policies in wireplumber to match on all groups and not just the primary. --- src/modules/module-protocol-native.c | 39 ++++++++++++++++++++++++++++ src/pipewire/impl-client.c | 1 + src/pipewire/keys.h | 1 + 3 files changed, 41 insertions(+) diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 00da2cc0e..ba930125e 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #ifdef HAVE_SELINUX @@ -182,6 +183,10 @@ static const struct spa_dict_item module_props[] = { #define SO_PEERSEC 31 #endif +#ifndef SO_PEERGROUPS +#define SO_PEERGROUPS 59 +#endif + #define LOCK_SUFFIX ".lock" #define LOCK_SUFFIXLEN 5 @@ -593,6 +598,39 @@ static bool check_print(const uint8_t *buffer, int len) return true; } +#if defined(__linux__) +/** Retrieve the peer's supplementary group list via SO_PEERGROUPS and store + * as a JSON array property on the client connection. */ +static void +set_supplementary_gids(struct pw_properties *props, int fd) +{ + gid_t gids[128]; + socklen_t len = sizeof(gids); + + if (getsockopt(fd, SOL_SOCKET, SO_PEERGROUPS, gids, &len) < 0) { + pw_log_debug("no SO_PEERGROUPS: %m"); + return; + } + + size_t n = len / sizeof(gid_t); + if (n == 0) + return; + + struct spa_json_builder b; + spa_autofree char *str = NULL; + size_t size; + if (spa_json_builder_memstream(&b, &str, &size, 0) < 0) + return; + spa_json_builder_array_push(&b, "["); + for (size_t i = 0; i < n; i++) + spa_json_builder_array_uint(&b, gids[i]); + spa_json_builder_pop(&b, "]"); + spa_json_builder_close(&b); + + pw_properties_set(props, PW_KEY_SEC_GIDS, str); +} +#endif /* __linux__ */ + static struct client_data *client_new(struct server *s, int fd) { struct client_data *this; @@ -622,6 +660,7 @@ static struct client_data *client_new(struct server *s, int fd) pw_properties_setf(props, PW_KEY_SEC_PID, "%d", ucred.pid); pw_properties_setf(props, PW_KEY_SEC_UID, "%d", ucred.uid); pw_properties_setf(props, PW_KEY_SEC_GID, "%d", ucred.gid); + set_supplementary_gids(props, fd); } len = sizeof(buffer); diff --git a/src/pipewire/impl-client.c b/src/pipewire/impl-client.c index 6566d1a51..b32917154 100644 --- a/src/pipewire/impl-client.c +++ b/src/pipewire/impl-client.c @@ -531,6 +531,7 @@ int pw_impl_client_register(struct pw_impl_client *client, PW_KEY_SEC_PID, PW_KEY_SEC_UID, PW_KEY_SEC_GID, + PW_KEY_SEC_GIDS, PW_KEY_SEC_LABEL, PW_KEY_SEC_SOCKET, NULL diff --git a/src/pipewire/keys.h b/src/pipewire/keys.h index 08e6fb2df..e5c38fd8c 100644 --- a/src/pipewire/keys.h +++ b/src/pipewire/keys.h @@ -37,6 +37,7 @@ extern "C" { #define PW_KEY_SEC_PID "pipewire.sec.pid" /**< Client pid, set by protocol */ #define PW_KEY_SEC_UID "pipewire.sec.uid" /**< Client uid, set by protocol*/ #define PW_KEY_SEC_GID "pipewire.sec.gid" /**< client gid, set by protocol*/ +#define PW_KEY_SEC_GIDS "pipewire.sec.gids" /**< client supplementary gids, set by protocol */ #define PW_KEY_SEC_LABEL "pipewire.sec.label" /**< client security label, set by protocol*/ #define PW_KEY_SEC_SOCKET "pipewire.sec.socket" /**< client socket name, set by protocol */