]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-bus: use the new information in the client's sockaddr in the creds structure
authorLennart Poettering <lennart@poettering.net>
Fri, 5 May 2023 19:43:57 +0000 (21:43 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 16 May 2023 10:08:41 +0000 (12:08 +0200)
Now that clients might convey comm/description strings via the sockaddr,
let's actually use them on the other side, read the data via
getpeername() parse it, and include it in the "owner" creds (which is
how we call the peer's creds).

src/libsystemd/sd-bus/bus-control.c
src/libsystemd/sd-bus/bus-internal.h
src/libsystemd/sd-bus/bus-socket.c

index 864acd73ac174b036f942539c228be7de9b40aab..287cde6d419f61973952a4770e707ab1b7c4a5c0 100644 (file)
@@ -722,9 +722,51 @@ _public_ int sd_bus_get_name_creds(
         return 0;
 }
 
+static int parse_sockaddr_string(const char *t, char **ret_comm, char **ret_description) {
+        _cleanup_free_ char *comm = NULL, *description = NULL;
+        const char *e, *sl;
+
+        assert(t);
+        assert(ret_comm);
+        assert(ret_description);
+
+        e = strstrafter(t, "/bus/");
+        if (!e) {
+                log_debug("Didn't find /bus/ substring in peer socket address, ignoring.");
+                goto not_found;
+        }
+
+        sl = strchr(e, '/');
+        if (!sl) {
+                log_debug("Didn't find / substring after /bus/ in peer socket address, ignoring.");
+                goto not_found;
+        }
+
+        if (sl - e > 0) {
+                comm = strndup(e, sl - e);
+                if (!comm)
+                        return -ENOMEM;
+        }
+
+        sl++;
+        if (!isempty(sl)) {
+                description = strdup(sl);
+                if (!description)
+                        return -ENOMEM;
+        }
+
+        *ret_comm = TAKE_PTR(comm);
+        *ret_description = TAKE_PTR(description);
+        return 0;
+
+not_found:
+        *ret_comm = *ret_description = NULL;
+        return 0;
+}
+
 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
-        bool do_label, do_groups;
+        bool do_label, do_groups, do_sockaddr_peer;
         pid_t pid = 0;
         int r;
 
@@ -742,9 +784,12 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
 
         do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
         do_groups = bus->n_groups != SIZE_MAX && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS);
+        do_sockaddr_peer = bus->sockaddr_size_peer >= offsetof(struct sockaddr_un, sun_path) + 1 &&
+                bus->sockaddr_peer.sa.sa_family == AF_UNIX &&
+                bus->sockaddr_peer.un.sun_path[0] == 0;
 
         /* Avoid allocating anything if we have no chance of returning useful data */
-        if (!bus->ucred_valid && !do_label && !do_groups)
+        if (!bus->ucred_valid && !do_label && !do_groups && !do_sockaddr_peer)
                 return -ENODATA;
 
         c = bus_creds_new();
@@ -786,6 +831,35 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
                 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
         }
 
+        if (do_sockaddr_peer) {
+                _cleanup_free_ char *t = NULL;
+
+                assert(bus->sockaddr_size_peer >= offsetof(struct sockaddr_un, sun_path) + 1);
+                assert(bus->sockaddr_peer.sa.sa_family == AF_UNIX);
+                assert(bus->sockaddr_peer.un.sun_path[0] == 0);
+
+                /* So this is an abstract namespace socket, good. Now let's find the data we are interested in */
+                r = make_cstring(bus->sockaddr_peer.un.sun_path + 1,
+                                 bus->sockaddr_size_peer - offsetof(struct sockaddr_un, sun_path) - 1,
+                                 MAKE_CSTRING_ALLOW_TRAILING_NUL,
+                                 &t);
+                if (r == -ENOMEM)
+                        return r;
+                if (r < 0)
+                        log_debug_errno(r, "Can't extract string from peer socket address, ignoring: %m");
+                else {
+                        r = parse_sockaddr_string(t, &c->comm, &c->description);
+                        if (r < 0)
+                                return r;
+
+                        if (c->comm)
+                                c->mask |= SD_BUS_CREDS_COMM & mask;
+
+                        if (c->description)
+                                c->mask |= SD_BUS_CREDS_DESCRIPTION & mask;
+                }
+        }
+
         r = bus_creds_add_more(c, mask, pid, 0);
         if (r < 0 && r != -ESRCH) /* If the process vanished, then don't complain, just return what we got */
                 return r;
index 0e44897e0e1292858b87ae9f49ce65af734e8769..1cf6974bff97e4c16c44fe3afaaaf7574e7f942d 100644 (file)
@@ -267,6 +267,8 @@ struct sd_bus {
         char *label;
         gid_t *groups;
         size_t n_groups;
+        union sockaddr_union sockaddr_peer;
+        socklen_t sockaddr_size_peer;
 
         uint64_t creds_mask;
 
index 11f4aa9669d4765672ac4b6a990bb93b99be8d44..741d54cabdfb624b33ff76199f8e61bd5a756140 100644 (file)
@@ -652,6 +652,17 @@ static void bus_get_peercred(sd_bus *b) {
                 b->n_groups = (size_t) r;
         else if (!IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT))
                 log_debug_errno(r, "Failed to determine peer's group list: %m");
+
+        /* Let's query the peers socket address, it might carry information such as the peer's comm or
+         * description string */
+        zero(b->sockaddr_peer);
+        b->sockaddr_size_peer = 0;
+
+        socklen_t l = sizeof(b->sockaddr_peer) - 1; /* Leave space for a NUL */
+        if (getpeername(b->input_fd, &b->sockaddr_peer.sa, &l) < 0)
+                log_debug_errno(errno, "Failed to get peer's socket address, ignoring: %m");
+        else
+                b->sockaddr_size_peer = l;
 }
 
 static int bus_socket_start_auth_client(sd_bus *b) {