]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-bus: also read supplementary gids from bus driver
authorLennart Poettering <lennart@poettering.net>
Fri, 26 Jan 2024 16:09:02 +0000 (17:09 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 29 Jan 2024 13:42:30 +0000 (14:42 +0100)
src/libsystemd/sd-bus/bus-control.c
src/libsystemd/sd-bus/test-bus-peersockaddr.c

index 3b11d754a22aaaa9d586f73b6eaa9a721f423851..0953b6ab26c9325a3e41ff5c603010f408279335 100644 (file)
@@ -483,8 +483,8 @@ _public_ int sd_bus_get_name_creds(
         }
 
         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();
@@ -513,10 +513,11 @@ _public_ int sd_bus_get_name_creds(
 
                 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() */
 
@@ -626,6 +627,49 @@ _public_ int sd_bus_get_name_creds(
                                                         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)
index 0c57d3821824c6c2c8a292fd52dfaca1d38a3292..a7bba17a9884a60064dbdb20ea63405b855b440b 100644 (file)
 #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;
@@ -29,11 +56,11 @@ static void *server(void *p) {
         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);
 
@@ -57,6 +84,18 @@ static void *server(void *p) {
                 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);