diff options
author | Lennart Poettering <lennart@poettering.net> | 2019-03-14 15:42:03 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-14 15:42:03 +0100 |
commit | beb6196982148a7403cf56db7399909a0da049ee (patch) | |
tree | dce3026ac5181a2b83007a36698e28f8eefbf9db /src/libsystemd/sd-bus | |
parent | 9e9213cd08ca82d6cc3565f753f343b1739cb263 (diff) | |
parent | 1ed4723d38cd0d1423c8fe650f90fa86007ddf55 (diff) | |
download | systemd-beb6196982148a7403cf56db7399909a0da049ee.tar.gz |
Merge pull request #11785 from dvdhrm/implicit-sasl
sd-bus: allow cross-uid-namespace connections
Diffstat (limited to 'src/libsystemd/sd-bus')
-rw-r--r-- | src/libsystemd/sd-bus/bus-socket.c | 119 |
1 files changed, 77 insertions, 42 deletions
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 89ac503ab8..790b64010a 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -158,17 +158,25 @@ static int bus_socket_write_auth(sd_bus *b) { } static int bus_socket_auth_verify_client(sd_bus *b) { - char *e, *f, *start; + char *d, *e, *f, *start; sd_id128_t peer; unsigned i; int r; assert(b); - /* We expect two response lines: "OK" and possibly - * "AGREE_UNIX_FD" */ + /* + * We expect three response lines: + * "DATA\r\n" + * "OK <server-id>\r\n" + * "AGREE_UNIX_FD\r\n" (optional) + */ - e = memmem_safe(b->rbuffer, b->rbuffer_size, "\r\n", 2); + d = memmem_safe(b->rbuffer, b->rbuffer_size, "\r\n", 2); + if (!d) + return 0; + + e = memmem(d + 2, b->rbuffer_size - (d - (char*) b->rbuffer) - 2, "\r\n", 2); if (!e) return 0; @@ -183,13 +191,30 @@ static int bus_socket_auth_verify_client(sd_bus *b) { start = e + 2; } - /* Nice! We got all the lines we need. First check the OK - * line */ + /* Nice! We got all the lines we need. First check the DATA line. */ + + if (d - (char*) b->rbuffer == 4) { + if (memcmp(b->rbuffer, "DATA", 4)) + return -EPERM; + } else if (d - (char*) b->rbuffer == 3 + 32) { + /* + * Old versions of the server-side implementation of `sd-bus` replied with "OK <id>" to + * "AUTH" requests from a client, even if the "AUTH" line did not contain inlined + * arguments. Therefore, we also accept "OK <id>" here, even though it is technically the + * wrong reply. We ignore the "<id>" parameter, though, since it has no real value. + */ + if (memcmp(b->rbuffer, "OK ", 3)) + return -EPERM; + } else { + return -EPERM; + } + + /* Now check the OK line. */ - if (e - (char*) b->rbuffer != 3 + 32) + if (e - d != 2 + 3 + 32) return -EPERM; - if (memcmp(b->rbuffer, "OK ", 3)) + if (memcmp(d + 2, "OK ", 3)) return -EPERM; b->auth = b->anonymous_auth ? BUS_AUTH_ANONYMOUS : BUS_AUTH_EXTERNAL; @@ -197,8 +222,8 @@ static int bus_socket_auth_verify_client(sd_bus *b) { for (i = 0; i < 32; i += 2) { int x, y; - x = unhexchar(((char*) b->rbuffer)[3 + i]); - y = unhexchar(((char*) b->rbuffer)[3 + i + 1]); + x = unhexchar(d[2 + 3 + i]); + y = unhexchar(d[2 + 3 + i + 1]); if (x < 0 || y < 0) return -EINVAL; @@ -212,7 +237,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) { b->server_id = peer; - /* And possibly check the second line, too */ + /* And possibly check the third line, too */ if (f) b->can_fds = @@ -386,26 +411,36 @@ static int bus_socket_auth_verify_server(sd_bus *b) { if (line_begins(line, l, "AUTH ANONYMOUS")) { - r = verify_anonymous_token(b, line + 14, l - 14); + r = verify_anonymous_token(b, + line + strlen("AUTH ANONYMOUS"), + l - strlen("AUTH ANONYMOUS")); if (r < 0) return r; if (r == 0) r = bus_socket_auth_write(b, "REJECTED\r\n"); else { b->auth = BUS_AUTH_ANONYMOUS; - r = bus_socket_auth_write_ok(b); + if (l <= strlen("AUTH ANONYMOUS")) + r = bus_socket_auth_write(b, "DATA\r\n"); + else + r = bus_socket_auth_write_ok(b); } } else if (line_begins(line, l, "AUTH EXTERNAL")) { - r = verify_external_token(b, line + 13, l - 13); + r = verify_external_token(b, + line + strlen("AUTH EXTERNAL"), + l - strlen("AUTH EXTERNAL")); if (r < 0) return r; if (r == 0) r = bus_socket_auth_write(b, "REJECTED\r\n"); else { b->auth = BUS_AUTH_EXTERNAL; - r = bus_socket_auth_write_ok(b); + if (l <= strlen("AUTH EXTERNAL")) + r = bus_socket_auth_write(b, "DATA\r\n"); + else + r = bus_socket_auth_write_ok(b); } } else if (line_begins(line, l, "AUTH")) @@ -601,39 +636,39 @@ static void bus_get_peercred(sd_bus *b) { } static int bus_socket_start_auth_client(sd_bus *b) { - size_t l; - const char *auth_suffix, *auth_prefix; + static const char sasl_auth_anonymous[] = { + /* + * We use an arbitrary trace-string for the ANONYMOUS authentication. It can be used by the + * message broker to aid debugging of clients. We fully anonymize the connection and use a + * static default. + */ + "\0AUTH ANONYMOUS\r\n" + /* HEX a n o n y m o u s */ + "DATA 616e6f6e796d6f7573\r\n" + }; + static const char sasl_auth_external[] = { + "\0AUTH EXTERNAL\r\n" + "DATA\r\n" + }; + static const char sasl_negotiate_unix_fd[] = { + "NEGOTIATE_UNIX_FD\r\n" + }; + static const char sasl_begin[] = { + "BEGIN\r\n" + }; + size_t i = 0; assert(b); - if (b->anonymous_auth) { - auth_prefix = "\0AUTH ANONYMOUS "; - - /* For ANONYMOUS auth we send some arbitrary "trace" string */ - l = 9; - b->auth_buffer = hexmem("anonymous", l); - } else { - char text[DECIMAL_STR_MAX(uid_t) + 1]; - - auth_prefix = "\0AUTH EXTERNAL "; - - xsprintf(text, UID_FMT, geteuid()); - - l = strlen(text); - b->auth_buffer = hexmem(text, l); - } - - if (!b->auth_buffer) - return -ENOMEM; + if (b->anonymous_auth) + b->auth_iovec[i++] = IOVEC_MAKE((char*) sasl_auth_anonymous, sizeof(sasl_auth_anonymous) - 1); + else + b->auth_iovec[i++] = IOVEC_MAKE((char*) sasl_auth_external, sizeof(sasl_auth_external) - 1); if (b->accept_fd) - auth_suffix = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n"; - else - auth_suffix = "\r\nBEGIN\r\n"; + b->auth_iovec[i++] = IOVEC_MAKE_STRING(sasl_negotiate_unix_fd); - b->auth_iovec[0] = IOVEC_MAKE((void*) auth_prefix, 1 + strlen(auth_prefix + 1)); - b->auth_iovec[1] = IOVEC_MAKE(b->auth_buffer, l * 2); - b->auth_iovec[2] = IOVEC_MAKE_STRING(auth_suffix); + b->auth_iovec[i++] = IOVEC_MAKE_STRING(sasl_begin); return bus_socket_write_auth(b); } |