}
if (mask != 0) {
+ bool need_pid, need_uid, need_gids, need_selinux, need_separate_calls, need_pidfd, need_augment;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- bool need_pid, need_uid, need_selinux, need_separate_calls, need_pidfd, need_augment;
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
c = bus_creds_new();
need_pid = (mask & SD_BUS_CREDS_PID) || need_augment;
need_uid = mask & SD_BUS_CREDS_EUID;
+ need_gids = mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
need_pidfd = (mask & SD_BUS_CREDS_PIDFD) || need_augment;
- if (need_pid + need_uid + need_selinux + need_pidfd > 1) {
+ if (need_pid + need_uid + need_selinux + need_pidfd + need_gids > 1) {
/* If we need more than one of the credentials, then use GetConnectionCredentials() */
close_and_replace(c->pidfd, fd);
c->mask |= SD_BUS_CREDS_PIDFD;
}
+ } else if (need_gids && streq(m, "UnixGroupIDs")) {
+
+ /* Note that D-Bus actualy only gives us a combined list of
+ * primary gid and supplementary gids. And we don't know
+ * which one the primary one is. We'll take the whole shebang
+ * hence and use it as the supplementary group list, and not
+ * initialize the primary gid field. This is slightly
+ * incorrect of course, but only slightly, as in effect if
+ * the primary gid is also listed in the supplementary gid
+ * it has zero effect. */
+
+ r = sd_bus_message_enter_container(reply, 'v', "au");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_enter_container(reply, 'a', "u");
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ uint32_t u;
+
+ r = sd_bus_message_read(reply, "u", &u);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ if (!GREEDY_REALLOC(c->supplementary_gids, c->n_supplementary_gids+1))
+ return -ENOMEM;
+
+ c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) u;
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return r;
+
+ c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
} else {
r = sd_bus_message_skip(reply, "v");
if (r < 0)
#include "fd-util.h"
#include "process-util.h"
#include "socket-util.h"
+#include "sort-util.h"
#include "tests.h"
+#include "user-util.h"
+
+static bool gid_list_contained(const gid_t *a, size_t n, const gid_t *b, size_t m) {
+ assert_se(a || n == 0);
+ assert_se(b || m == 0);
+
+ /* Checks if every entry in a[] is also in b[] */
+
+ for (size_t i = 0; i < n; i++) {
+ size_t j;
+
+ for (j = 0; j < m; j++)
+ if (a[i] == b[j])
+ break;
+
+ if (j >= m)
+ return false;
+ }
+
+ return true;
+}
+
+static bool gid_list_same(const gid_t *a, size_t n, const gid_t *b, size_t m) {
+ return gid_list_contained(a, n, b, m) &&
+ gid_list_contained(b, m, a, n);
+}
static void *server(void *p) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
assert_se(sd_bus_set_fd(bus, fd, fd) >= 0);
TAKE_FD(fd);
assert_se(sd_bus_set_server(bus, true, id) >= 0);
- assert_se(sd_bus_negotiate_creds(bus, 1, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_PIDFD) >= 0);
+ assert_se(sd_bus_negotiate_creds(bus, 1, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_PIDFD|SD_BUS_CREDS_SUPPLEMENTARY_GIDS) >= 0);
assert_se(sd_bus_start(bus) >= 0);
- assert_se(sd_bus_get_owner_creds(bus, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_PIDFD, &c) >= 0);
+ assert_se(sd_bus_get_owner_creds(bus, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_PIDFD|SD_BUS_CREDS_SUPPLEMENTARY_GIDS, &c) >= 0);
bus_creds_dump(c, /* f= */ NULL, /* terse= */ false);
assert_se(pidref.pid == getpid_cached());
}
+ const gid_t *gl = NULL;
+ int n;
+ n = sd_bus_creds_get_supplementary_gids(c, &gl);
+
+ if (n >= 0) {
+ _cleanup_free_ gid_t *gg = NULL;
+ r = getgroups_alloc(&gg);
+ assert_se(r >= 0);
+
+ assert_se(gid_list_same(gl, n, gg, r));
+ }
+
const char *comm;
assert_se(sd_bus_creds_get_comm(c, &comm) >= 0);
assert_se(pid_get_comm(0, &our_comm) >= 0);