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.
This commit is contained in:
Torkel Niklasson 2026-05-25 14:32:33 +02:00 committed by Wim Taymans
parent 4bde2415f9
commit 1066ec98a8
3 changed files with 41 additions and 0 deletions

View file

@ -32,6 +32,7 @@
#include <spa/utils/result.h>
#include <spa/utils/string.h>
#include <spa/utils/json.h>
#include <spa/utils/json-builder.h>
#include <spa/debug/log.h>
#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);

View file

@ -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

View file

@ -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 */