4cad4c
From ccdb8883c6ff0e72d5e221768af0718e25cbf177 Mon Sep 17 00:00:00 2001
4cad4c
From: David Rheinsberg <david.rheinsberg@gmail.com>
4cad4c
Date: Thu, 14 Mar 2019 13:34:13 +0100
4cad4c
Subject: [PATCH] sd-bus: skip sending formatted UIDs via SASL
4cad4c
4cad4c
The dbus external authentication takes as optional argument the UID the
4cad4c
sender wants to authenticate as. This uid is purely optional. The
4cad4c
AF_UNIX socket already conveys the same information through the
4cad4c
auxiliary socket data, so we really don't have to provide that
4cad4c
information.
4cad4c
4cad4c
Unfortunately, there is no way to send empty arguments, since they are
4cad4c
interpreted as "missing argument", which has a different meaning. The
4cad4c
SASL negotiation thus changes from:
4cad4c
4cad4c
    AUTH EXTERNAL <uid>
4cad4c
    NEGOTIATE_UNIX_FD                   (optional)
4cad4c
    BEGIN
4cad4c
4cad4c
to:
4cad4c
4cad4c
    AUTH EXTERNAL
4cad4c
    DATA
4cad4c
    NEGOTIATE_UNIX_FD                   (optional)
4cad4c
    BEGIN
4cad4c
4cad4c
And thus the replies we expect as a client change from:
4cad4c
4cad4c
    OK <server-id>
4cad4c
    AGREE_UNIX_FD                       (optional)
4cad4c
4cad4c
to:
4cad4c
4cad4c
    DATA
4cad4c
    OK <server-id>
4cad4c
    AGREE_UNIX_FD                       (optional)
4cad4c
4cad4c
Since the old sd-bus server implementation used the wrong reply for
4cad4c
"AUTH" requests that do not carry the arguments inlined, we decided to
4cad4c
make sd-bus clients accept this as well. Hence, sd-bus now allows
4cad4c
"OK <server-id>\r\n" replies instead of "DATA\r\n" replies.
4cad4c
4cad4c
Signed-off-by: David Rheinsberg <david.rheinsberg@gmail.com>
4cad4c
(cherry picked from commit 1ed4723d38cd0d1423c8fe650f90fa86007ddf55)
4cad4c
4cad4c
Resolves: #1838081
4cad4c
---
4cad4c
 src/libsystemd/sd-bus/bus-socket.c | 106 +++++++++++++++++------------
4cad4c
 1 file changed, 64 insertions(+), 42 deletions(-)
4cad4c
4cad4c
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
4cad4c
index e505d43c6b..8813dd5efd 100644
4cad4c
--- a/src/libsystemd/sd-bus/bus-socket.c
4cad4c
+++ b/src/libsystemd/sd-bus/bus-socket.c
4cad4c
@@ -162,17 +162,25 @@ static int bus_socket_write_auth(sd_bus *b) {
4cad4c
 }
4cad4c
 
4cad4c
 static int bus_socket_auth_verify_client(sd_bus *b) {
4cad4c
-        char *e, *f, *start;
4cad4c
+        char *d, *e, *f, *start;
4cad4c
         sd_id128_t peer;
4cad4c
         unsigned i;
4cad4c
         int r;
4cad4c
 
4cad4c
         assert(b);
4cad4c
 
4cad4c
-        /* We expect two response lines: "OK" and possibly
4cad4c
-         * "AGREE_UNIX_FD" */
4cad4c
+        /*
4cad4c
+         * We expect three response lines:
4cad4c
+         *   "DATA\r\n"
4cad4c
+         *   "OK <server-id>\r\n"
4cad4c
+         *   "AGREE_UNIX_FD\r\n"        (optional)
4cad4c
+         */
4cad4c
 
4cad4c
-        e = memmem_safe(b->rbuffer, b->rbuffer_size, "\r\n", 2);
4cad4c
+        d = memmem_safe(b->rbuffer, b->rbuffer_size, "\r\n", 2);
4cad4c
+        if (!d)
4cad4c
+                return 0;
4cad4c
+
4cad4c
+        e = memmem(d + 2, b->rbuffer_size - (d - (char*) b->rbuffer) - 2, "\r\n", 2);
4cad4c
         if (!e)
4cad4c
                 return 0;
4cad4c
 
4cad4c
@@ -187,13 +195,30 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
4cad4c
                 start = e + 2;
4cad4c
         }
4cad4c
 
4cad4c
-        /* Nice! We got all the lines we need. First check the OK
4cad4c
-         * line */
4cad4c
+        /* Nice! We got all the lines we need. First check the DATA line. */
4cad4c
+
4cad4c
+        if (d - (char*) b->rbuffer == 4) {
4cad4c
+                if (memcmp(b->rbuffer, "DATA", 4))
4cad4c
+                        return -EPERM;
4cad4c
+        } else if (d - (char*) b->rbuffer == 3 + 32) {
4cad4c
+                /*
4cad4c
+                 * Old versions of the server-side implementation of `sd-bus` replied with "OK <id>" to
4cad4c
+                 * "AUTH" requests from a client, even if the "AUTH" line did not contain inlined
4cad4c
+                 * arguments. Therefore, we also accept "OK <id>" here, even though it is technically the
4cad4c
+                 * wrong reply. We ignore the "<id>" parameter, though, since it has no real value.
4cad4c
+                 */
4cad4c
+                if (memcmp(b->rbuffer, "OK ", 3))
4cad4c
+                        return -EPERM;
4cad4c
+        } else {
4cad4c
+                return -EPERM;
4cad4c
+        }
4cad4c
+
4cad4c
+        /* Now check the OK line. */
4cad4c
 
4cad4c
-        if (e - (char*) b->rbuffer != 3 + 32)
4cad4c
+        if (e - d != 2 + 3 + 32)
4cad4c
                 return -EPERM;
4cad4c
 
4cad4c
-        if (memcmp(b->rbuffer, "OK ", 3))
4cad4c
+        if (memcmp(d + 2, "OK ", 3))
4cad4c
                 return -EPERM;
4cad4c
 
4cad4c
         b->auth = b->anonymous_auth ? BUS_AUTH_ANONYMOUS : BUS_AUTH_EXTERNAL;
4cad4c
@@ -201,8 +226,8 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
4cad4c
         for (i = 0; i < 32; i += 2) {
4cad4c
                 int x, y;
4cad4c
 
4cad4c
-                x = unhexchar(((char*) b->rbuffer)[3 + i]);
4cad4c
-                y = unhexchar(((char*) b->rbuffer)[3 + i + 1]);
4cad4c
+                x = unhexchar(d[2 + 3 + i]);
4cad4c
+                y = unhexchar(d[2 + 3 + i + 1]);
4cad4c
 
4cad4c
                 if (x < 0 || y < 0)
4cad4c
                         return -EINVAL;
4cad4c
@@ -216,7 +241,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
4cad4c
 
4cad4c
         b->server_id = peer;
4cad4c
 
4cad4c
-        /* And possibly check the second line, too */
4cad4c
+        /* And possibly check the third line, too */
4cad4c
 
4cad4c
         if (f)
4cad4c
                 b->can_fds =
4cad4c
@@ -616,42 +641,39 @@ static void bus_get_peercred(sd_bus *b) {
4cad4c
 }
4cad4c
 
4cad4c
 static int bus_socket_start_auth_client(sd_bus *b) {
4cad4c
-        size_t l;
4cad4c
-        const char *auth_suffix, *auth_prefix;
4cad4c
+        static const char sasl_auth_anonymous[] = {
4cad4c
+                /*
4cad4c
+                 * We use an arbitrary trace-string for the ANONYMOUS authentication. It can be used by the
4cad4c
+                 * message broker to aid debugging of clients. We fully anonymize the connection and use a
4cad4c
+                 * static default.
4cad4c
+                 */
4cad4c
+                "\0AUTH ANONYMOUS\r\n"
4cad4c
+                /* HEX a n o n y m o u s */
4cad4c
+                "DATA 616e6f6e796d6f7573\r\n"
4cad4c
+        };
4cad4c
+        static const char sasl_auth_external[] = {
4cad4c
+                "\0AUTH EXTERNAL\r\n"
4cad4c
+                "DATA\r\n"
4cad4c
+        };
4cad4c
+        static const char sasl_negotiate_unix_fd[] = {
4cad4c
+                "NEGOTIATE_UNIX_FD\r\n"
4cad4c
+        };
4cad4c
+        static const char sasl_begin[] = {
4cad4c
+                "BEGIN\r\n"
4cad4c
+        };
4cad4c
+        size_t i = 0;
4cad4c
 
4cad4c
         assert(b);
4cad4c
 
4cad4c
-        if (b->anonymous_auth) {
4cad4c
-                auth_prefix = "\0AUTH ANONYMOUS ";
4cad4c
-
4cad4c
-                /* For ANONYMOUS auth we send some arbitrary "trace" string */
4cad4c
-                l = 9;
4cad4c
-                b->auth_buffer = hexmem("anonymous", l);
4cad4c
-        } else {
4cad4c
-                char text[DECIMAL_STR_MAX(uid_t) + 1];
4cad4c
-
4cad4c
-                auth_prefix = "\0AUTH EXTERNAL ";
4cad4c
-
4cad4c
-                xsprintf(text, UID_FMT, geteuid());
4cad4c
-
4cad4c
-                l = strlen(text);
4cad4c
-                b->auth_buffer = hexmem(text, l);
4cad4c
-        }
4cad4c
-
4cad4c
-        if (!b->auth_buffer)
4cad4c
-                return -ENOMEM;
4cad4c
+        if (b->anonymous_auth)
4cad4c
+                b->auth_iovec[i++] = IOVEC_MAKE((char*) sasl_auth_anonymous, sizeof(sasl_auth_anonymous) - 1);
4cad4c
+        else
4cad4c
+                b->auth_iovec[i++] = IOVEC_MAKE((char*) sasl_auth_external, sizeof(sasl_auth_external) - 1);
4cad4c
 
4cad4c
         if (b->accept_fd)
4cad4c
-                auth_suffix = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n";
4cad4c
-        else
4cad4c
-                auth_suffix = "\r\nBEGIN\r\n";
4cad4c
-
4cad4c
-        b->auth_iovec[0].iov_base = (void*) auth_prefix;
4cad4c
-        b->auth_iovec[0].iov_len = 1 + strlen(auth_prefix + 1);
4cad4c
-        b->auth_iovec[1].iov_base = (void*) b->auth_buffer;
4cad4c
-        b->auth_iovec[1].iov_len = l * 2;
4cad4c
-        b->auth_iovec[2].iov_base = (void*) auth_suffix;
4cad4c
-        b->auth_iovec[2].iov_len = strlen(auth_suffix);
4cad4c
+                b->auth_iovec[i++] = IOVEC_MAKE_STRING(sasl_negotiate_unix_fd);
4cad4c
+
4cad4c
+        b->auth_iovec[i++] = IOVEC_MAKE_STRING(sasl_begin);
4cad4c
 
4cad4c
         return bus_socket_write_auth(b);
4cad4c
 }