diff options
Diffstat (limited to 'src/libelogind/sd-bus')
47 files changed, 2121 insertions, 6045 deletions
diff --git a/src/libelogind/sd-bus/Makefile b/src/libelogind/sd-bus/Makefile deleted file mode 120000 index 94aaae2c4..000000000 --- a/src/libelogind/sd-bus/Makefile +++ /dev/null @@ -1 +0,0 @@ -../../Makefile
\ No newline at end of file diff --git a/src/libelogind/sd-bus/bus-bloom.c b/src/libelogind/sd-bus/bus-bloom.c deleted file mode 100644 index 112769fcb..000000000 --- a/src/libelogind/sd-bus/bus-bloom.c +++ /dev/null @@ -1,156 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include "bus-bloom.h" -#include "siphash24.h" -#include "util.h" - -static inline void set_bit(uint64_t filter[], unsigned long b) { - filter[b >> 6] |= 1ULL << (b & 63); -} - -static const sd_id128_t hash_keys[] = { - SD_ID128_ARRAY(b9,66,0b,f0,46,70,47,c1,88,75,c4,9c,54,b9,bd,15), - SD_ID128_ARRAY(aa,a1,54,a2,e0,71,4b,39,bf,e1,dd,2e,9f,c5,4a,3b), - SD_ID128_ARRAY(63,fd,ae,be,cd,82,48,12,a1,6e,41,26,cb,fa,a0,c8), - SD_ID128_ARRAY(23,be,45,29,32,d2,46,2d,82,03,52,28,fe,37,17,f5), - SD_ID128_ARRAY(56,3b,bf,ee,5a,4f,43,39,af,aa,94,08,df,f0,fc,10), - SD_ID128_ARRAY(31,80,c8,73,c7,ea,46,d3,aa,25,75,0f,9e,4c,09,29), - SD_ID128_ARRAY(7d,f7,18,4b,7b,a4,44,d5,85,3c,06,e0,65,53,96,6d), - SD_ID128_ARRAY(f2,77,e9,6f,93,b5,4e,71,9a,0c,34,88,39,25,bf,35), -}; - -static void bloom_add_data( - uint64_t filter[], /* The filter bits */ - size_t size, /* Size of the filter in bytes */ - unsigned k, /* Number of hash functions */ - const void *data, /* Data to hash */ - size_t n) { /* Size of data to hash in bytes */ - - uint64_t h; - uint64_t m; - unsigned w, i, c = 0; - unsigned hash_index; - - assert(size > 0); - assert(k > 0); - - /* Determine bits in filter */ - m = size * 8; - - /* Determine how many bytes we need to generate a bit index 0..m for this filter */ - w = (u64log2(m) + 7) / 8; - - assert(w <= sizeof(uint64_t)); - - /* Make sure we have enough hash keys to generate m * k bits - * of hash value. Note that SipHash24 generates 64 bits of - * hash value for each 128 bits of hash key. */ - assert(k * w <= ELEMENTSOF(hash_keys) * 8); - - for (i = 0, hash_index = 0; i < k; i++) { - uint64_t p = 0; - unsigned d; - - for (d = 0; d < w; d++) { - if (c <= 0) { - h = siphash24(data, n, hash_keys[hash_index++].bytes); - c += 8; - } - - p = (p << 8ULL) | (uint64_t) ((uint8_t *)&h)[8 - c]; - c--; - } - - p &= m - 1; - set_bit(filter, p); - } - - /* log_debug("bloom: adding <%.*s>", (int) n, (char*) data); */ -} - -void bloom_add_pair(uint64_t filter[], size_t size, unsigned k, const char *a, const char *b) { - size_t n; - char *c; - - assert(filter); - assert(a); - assert(b); - - n = strlen(a) + 1 + strlen(b); - c = alloca(n + 1); - strcpy(stpcpy(stpcpy(c, a), ":"), b); - - bloom_add_data(filter, size, k, c, n); -} - -void bloom_add_prefixes(uint64_t filter[], size_t size, unsigned k, const char *a, const char *b, char sep) { - size_t n; - char *c, *p; - - assert(filter); - assert(a); - assert(b); - - n = strlen(a) + 1 + strlen(b); - c = alloca(n + 1); - - p = stpcpy(stpcpy(c, a), ":"); - strcpy(p, b); - - bloom_add_data(filter, size, k, c, n); - - for (;;) { - char *e; - - e = strrchr(p, sep); - if (!e) - break; - - *(e + 1) = 0; - bloom_add_data(filter, size, k, c, e - c + 1); - - if (e == p) - break; - - *e = 0; - bloom_add_data(filter, size, k, c, e - c); - } -} - -bool bloom_validate_parameters(size_t size, unsigned k) { - uint64_t m; - unsigned w; - - if (size <= 0) - return false; - - if (k <= 0) - return false; - - m = size * 8; - w = (u64log2(m) + 7) / 8; - if (w > sizeof(uint64_t)) - return false; - - if (k * w > ELEMENTSOF(hash_keys) * 8) - return false; - - return true; -} diff --git a/src/libelogind/sd-bus/bus-bloom.h b/src/libelogind/sd-bus/bus-bloom.h deleted file mode 100644 index c824622b9..000000000 --- a/src/libelogind/sd-bus/bus-bloom.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -/* - * Our default bloom filter has the following parameters: - * - * m=512 (bits in the filter) - * k=8 (hash functions) - * - * We use SipHash24 as hash function with a number of (originally - * randomized) but fixed hash keys. - * - */ - -#define DEFAULT_BLOOM_SIZE (512/8) /* m: filter size */ -#define DEFAULT_BLOOM_N_HASH 8 /* k: number of hash functions */ - -void bloom_add_pair(uint64_t filter[], size_t size, unsigned n_hash, const char *a, const char *b); -void bloom_add_prefixes(uint64_t filter[], size_t size, unsigned n_hash, const char *a, const char *b, char sep); - -bool bloom_validate_parameters(size_t size, unsigned n_hash); diff --git a/src/libelogind/sd-bus/bus-common-errors.c b/src/libelogind/sd-bus/bus-common-errors.c index a6d38b982..59974b254 100644 --- a/src/libelogind/sd-bus/bus-common-errors.c +++ b/src/libelogind/sd-bus/bus-common-errors.c @@ -1,21 +1,4 @@ -/*** - This file is part of systemd. - - Copyright 2014 Zbigniew JÄ™drzejewski-Szmek - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include <errno.h> @@ -31,6 +14,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID, ENOENT), SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_EXISTS, EEXIST), SD_BUS_ERROR_MAP(BUS_ERROR_LOAD_FAILED, EIO), + SD_BUS_ERROR_MAP(BUS_ERROR_BAD_UNIT_SETTING, ENOEXEC), SD_BUS_ERROR_MAP(BUS_ERROR_JOB_FAILED, EREMOTEIO), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_JOB, ENOENT), SD_BUS_ERROR_MAP(BUS_ERROR_NOT_SUBSCRIBED, EINVAL), @@ -74,6 +58,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { #if 0 /// UNNEEDED by elogind SD_BUS_ERROR_MAP(BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, EALREADY), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_NTP_SUPPORT, EOPNOTSUPP), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_PROCESS, ESRCH), diff --git a/src/libelogind/sd-bus/bus-common-errors.h b/src/libelogind/sd-bus/bus-common-errors.h index aad97ff5c..fa44ca1f6 100644 --- a/src/libelogind/sd-bus/bus-common-errors.h +++ b/src/libelogind/sd-bus/bus-common-errors.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "bus-error.h" @@ -24,8 +9,10 @@ #if 0 /// only system command elogind knows are needed #define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit" #define BUS_ERROR_NO_UNIT_FOR_PID "org.freedesktop.systemd1.NoUnitForPID" +#define BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID "org.freedesktop.elogind1.NoUnitForInvocationID" #define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists" #define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed" +#define BUS_ERROR_BAD_UNIT_SETTING "org.freedesktop.systemd1.BadUnitSetting" #define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed" #define BUS_ERROR_NO_SUCH_JOB "org.freedesktop.systemd1.NoSuchJob" #define BUS_ERROR_NOT_SUBSCRIBED "org.freedesktop.systemd1.NotSubscribed" @@ -42,6 +29,9 @@ #define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown" #define BUS_ERROR_SCOPE_NOT_RUNNING "org.freedesktop.systemd1.ScopeNotRunning" #endif // 0 +#define BUS_ERROR_NO_SUCH_DYNAMIC_USER "org.freedesktop.elogind1.NoSuchDynamicUser" +#define BUS_ERROR_NOT_REFERENCED "org.freedesktop.elogind1.NotReferenced" +#define BUS_ERROR_DISK_FULL "org.freedesktop.elogind1.DiskFull" #if 0 /// no machined in elogind #define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine" @@ -53,6 +43,8 @@ #define BUS_ERROR_NO_SUCH_GROUP_MAPPING "org.freedesktop.machine1.NoSuchGroupMapping" #endif // 0 +#define BUS_ERROR_NO_SUCH_PORTABLE_IMAGE "org.freedesktop.portable1.NoSuchImage" + #define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession" #define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID" #define BUS_ERROR_NO_SUCH_USER "org.freedesktop.login1.NoSuchUser" @@ -68,6 +60,7 @@ #if 0 /// more services unsupported by elogind #define BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED "org.freedesktop.timedate1.AutomaticTimeSyncEnabled" +#define BUS_ERROR_NO_NTP_SUPPORT "org.freedesktop.timedate1.NoNTPSupport" #define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess" @@ -83,6 +76,8 @@ #define BUS_ERROR_NO_SUCH_LINK "org.freedesktop.resolve1.NoSuchLink" #define BUS_ERROR_LINK_BUSY "org.freedesktop.resolve1.LinkBusy" #define BUS_ERROR_NETWORK_DOWN "org.freedesktop.resolve1.NetworkDown" +#define BUS_ERROR_NO_SUCH_DNSSD_SERVICE "org.freedesktop.resolve1.NoSuchDnssdService" +#define BUS_ERROR_DNSSD_SERVICE_EXISTS "org.freedesktop.resolve1.DnssdServiceExists" #define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError." #define BUS_ERROR_NO_SUCH_TRANSFER "org.freedesktop.import1.NoSuchTransfer" diff --git a/src/libelogind/sd-bus/bus-container.c b/src/libelogind/sd-bus/bus-container.c index 3191d27de..f50274a6a 100644 --- a/src/libelogind/sd-bus/bus-container.c +++ b/src/libelogind/sd-bus/bus-container.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <fcntl.h> @@ -30,9 +15,8 @@ int bus_container_connect_socket(sd_bus *b) { _cleanup_close_pair_ int pair[2] = { -1, -1 }; _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; - pid_t child; - siginfo_t si; int r, error_buf = 0; + pid_t child; ssize_t n; assert(b); @@ -54,6 +38,8 @@ int bus_container_connect_socket(sd_bus *b) { if (b->input_fd < 0) return -errno; + b->input_fd = fd_move_above_stdio(b->input_fd); + b->output_fd = b->input_fd; bus_socket_setup(b); @@ -61,11 +47,10 @@ int bus_container_connect_socket(sd_bus *b) { if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) return -errno; - child = fork(); - if (child < 0) - return -errno; - - if (child == 0) { + r = safe_fork("(sd-buscntr)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); + if (r < 0) + return r; + if (r == 0) { pid_t grandchild; pair[0] = safe_close(pair[0]); @@ -81,11 +66,10 @@ int bus_container_connect_socket(sd_bus *b) { * comes from a process from within the container, and * not outside of it */ - grandchild = fork(); - if (grandchild < 0) + r = safe_fork("(sd-buscntr2)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &grandchild); + if (r < 0) _exit(EXIT_FAILURE); - - if (grandchild == 0) { + if (r == 0) { r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); if (r < 0) { @@ -98,21 +82,20 @@ int bus_container_connect_socket(sd_bus *b) { _exit(EXIT_SUCCESS); } - r = wait_for_terminate(grandchild, &si); + r = wait_for_terminate_and_check("(sd-buscntr2)", grandchild, 0); if (r < 0) _exit(EXIT_FAILURE); - if (si.si_code != CLD_EXITED) - _exit(EXIT_FAILURE); - - _exit(si.si_status); + _exit(r); } pair[1] = safe_close(pair[1]); - r = wait_for_terminate(child, &si); + r = wait_for_terminate_and_check("(sd-buscntr)", child, 0); if (r < 0) return r; + if (r != EXIT_SUCCESS) + return -EPROTO; n = read(pair[0], &error_buf, sizeof(error_buf)); if (n < 0) @@ -132,146 +115,5 @@ int bus_container_connect_socket(sd_bus *b) { return -error_buf; } - if (si.si_code != CLD_EXITED) - return -EIO; - - if (si.si_status != EXIT_SUCCESS) - return -EIO; - return bus_socket_start_auth(b); } - -int bus_container_connect_kernel(sd_bus *b) { - _cleanup_close_pair_ int pair[2] = { -1, -1 }; - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - int error_buf = 0; - struct iovec iov = { - .iov_base = &error_buf, - .iov_len = sizeof(error_buf), - }; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - struct cmsghdr *cmsg; - pid_t child; - siginfo_t si; - int r, fd = -1; - ssize_t n; - - assert(b); - assert(b->input_fd < 0); - assert(b->output_fd < 0); - assert(b->nspid > 0 || b->machine); - - if (b->nspid <= 0) { - r = container_get_leader(b->machine, &b->nspid); - if (r < 0) - return r; - } - - r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); - if (r < 0) - return r; - - if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) - return -errno; - - child = fork(); - if (child < 0) - return -errno; - - if (child == 0) { - pid_t grandchild; - - pair[0] = safe_close(pair[0]); - - r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); - if (r < 0) - _exit(EXIT_FAILURE); - - /* We just changed PID namespace, however it will only - * take effect on the children we now fork. Hence, - * let's fork another time, and connect from this - * grandchild, so that kdbus only sees the credentials - * of this process which comes from within the - * container, and not outside of it */ - - grandchild = fork(); - if (grandchild < 0) - _exit(EXIT_FAILURE); - - if (grandchild == 0) { - fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) { - /* Try to send error up */ - error_buf = errno; - (void) write(pair[1], &error_buf, sizeof(error_buf)); - _exit(EXIT_FAILURE); - } - - r = send_one_fd(pair[1], fd, 0); - if (r < 0) - _exit(EXIT_FAILURE); - - _exit(EXIT_SUCCESS); - } - - r = wait_for_terminate(grandchild, &si); - if (r < 0) - _exit(EXIT_FAILURE); - - if (si.si_code != CLD_EXITED) - _exit(EXIT_FAILURE); - - _exit(si.si_status); - } - - pair[1] = safe_close(pair[1]); - - r = wait_for_terminate(child, &si); - if (r < 0) - return r; - - n = recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); - if (n < 0) - return -errno; - - CMSG_FOREACH(cmsg, &mh) { - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - int *fds; - unsigned n_fds; - - assert(fd < 0); - - fds = (int*) CMSG_DATA(cmsg); - n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - - if (n_fds != 1) { - close_many(fds, n_fds); - return -EIO; - } - - fd = fds[0]; - } - } - - /* If there's an fd passed, we are good. */ - if (fd >= 0) { - b->input_fd = b->output_fd = fd; - return bus_kernel_take_fd(b); - } - - /* If there's an error passed, use it */ - if (n == sizeof(error_buf) && error_buf > 0) - return -error_buf; - - /* Otherwise, we have no clue */ - return -EIO; -} diff --git a/src/libelogind/sd-bus/bus-container.h b/src/libelogind/sd-bus/bus-container.h index 509ef4562..dd115b4e2 100644 --- a/src/libelogind/sd-bus/bus-container.h +++ b/src/libelogind/sd-bus/bus-container.h @@ -1,25 +1,9 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "sd-bus.h" int bus_container_connect_socket(sd_bus *b); -int bus_container_connect_kernel(sd_bus *b); diff --git a/src/libelogind/sd-bus/bus-control.c b/src/libelogind/sd-bus/bus-control.c index b56bb0771..18a2cc2c9 100644 --- a/src/libelogind/sd-bus/bus-control.c +++ b/src/libelogind/sd-bus/bus-control.c @@ -1,23 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#ifdef HAVE_VALGRIND_MEMCHECK_H +#if HAVE_VALGRIND_MEMCHECK_H #include <valgrind/memcheck.h> #endif @@ -27,12 +12,12 @@ #include "sd-bus.h" #include "alloc-util.h" -#include "bus-bloom.h" #include "bus-control.h" #include "bus-internal.h" #include "bus-message.h" #include "bus-util.h" #include "capability-util.h" +#include "process-util.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" @@ -42,6 +27,7 @@ _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(unique, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -56,52 +42,61 @@ _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { return 0; } -static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) { - struct kdbus_cmd *n; - size_t size, l; - int r; +static int validate_request_name_parameters( + sd_bus *bus, + const char *name, + uint64_t flags, + uint32_t *ret_param) { + + uint32_t param = 0; assert(bus); assert(name); + assert(ret_param); - l = strlen(name) + 1; - size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l); - n = alloca0_align(size, 8); - n->size = size; - n->flags = request_name_flags_to_kdbus(flags); + assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL); + assert_return(service_name_is_valid(name), -EINVAL); + assert_return(name[0] != ':', -EINVAL); - n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l; - n->items[0].type = KDBUS_ITEM_NAME; - memcpy(n->items[0].str, name, l); + if (!bus->bus_client) + return -EINVAL; -#ifdef HAVE_VALGRIND_MEMCHECK_H - VALGRIND_MAKE_MEM_DEFINED(n, n->size); -#endif + /* Don't allow requesting the special driver and local names */ + if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local")) + return -EINVAL; - r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n); - if (r < 0) - return -errno; + if (!BUS_IS_OPEN(bus->state)) + return -ENOTCONN; - if (n->return_flags & KDBUS_NAME_IN_QUEUE) - return 0; + if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT) + param |= BUS_NAME_ALLOW_REPLACEMENT; + if (flags & SD_BUS_NAME_REPLACE_EXISTING) + param |= BUS_NAME_REPLACE_EXISTING; + if (!(flags & SD_BUS_NAME_QUEUE)) + param |= BUS_NAME_DO_NOT_QUEUE; - return 1; + *ret_param = param; + + return 0; } -static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) { +_public_ int sd_bus_request_name( + sd_bus *bus, + const char *name, + uint64_t flags) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; uint32_t ret, param = 0; int r; - assert(bus); - assert(name); + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(name, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); - if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT) - param |= BUS_NAME_ALLOW_REPLACEMENT; - if (flags & SD_BUS_NAME_REPLACE_EXISTING) - param |= BUS_NAME_REPLACE_EXISTING; - if (!(flags & SD_BUS_NAME_QUEUE)) - param |= BUS_NAME_DO_NOT_QUEUE; + r = validate_request_name_parameters(bus, name, flags, ¶m); + if (r < 0) + return r; r = sd_bus_call_method( bus, @@ -121,76 +116,145 @@ static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) if (r < 0) return r; - if (ret == BUS_NAME_ALREADY_OWNER) + switch (ret) { + + case BUS_NAME_ALREADY_OWNER: return -EALREADY; - else if (ret == BUS_NAME_EXISTS) + + case BUS_NAME_EXISTS: return -EEXIST; - else if (ret == BUS_NAME_IN_QUEUE) + + case BUS_NAME_IN_QUEUE: return 0; - else if (ret == BUS_NAME_PRIMARY_OWNER) + + case BUS_NAME_PRIMARY_OWNER: return 1; + } return -EIO; } -_public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) { +static int default_request_name_handler( + sd_bus_message *m, + void *userdata, + sd_bus_error *ret_error) { + + uint32_t ret; + int r; + + assert(m); + + if (sd_bus_message_is_method_error(m, NULL)) { + log_debug_errno(sd_bus_message_get_errno(m), + "Unable to request name, failing connection: %s", + sd_bus_message_get_error(m)->message); + + bus_enter_closing(sd_bus_message_get_bus(m)); + return 1; + } + + r = sd_bus_message_read(m, "u", &ret); + if (r < 0) + return r; + + switch (ret) { + + case BUS_NAME_ALREADY_OWNER: + log_debug("Already owner of requested service name, ignoring."); + return 1; + + case BUS_NAME_IN_QUEUE: + log_debug("In queue for requested service name."); + return 1; + + case BUS_NAME_PRIMARY_OWNER: + log_debug("Successfully acquired requested service name."); + return 1; + + case BUS_NAME_EXISTS: + log_debug("Requested service name already owned, failing connection."); + bus_enter_closing(sd_bus_message_get_bus(m)); + return 1; + } + + log_debug("Unexpected response from RequestName(), failing connection."); + bus_enter_closing(sd_bus_message_get_bus(m)); + return 1; +} + +_public_ int sd_bus_request_name_async( + sd_bus *bus, + sd_bus_slot **ret_slot, + const char *name, + uint64_t flags, + sd_bus_message_handler_t callback, + void *userdata) { + + uint32_t param = 0; + int r; + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(name, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); - assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL); + + r = validate_request_name_parameters(bus, name, flags, ¶m); + if (r < 0) + return r; + + return sd_bus_call_method_async( + bus, + ret_slot, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "RequestName", + callback ?: default_request_name_handler, + userdata, + "su", + name, + param); +} + +static int validate_release_name_parameters( + sd_bus *bus, + const char *name) { + + assert(bus); + assert(name); + assert_return(service_name_is_valid(name), -EINVAL); assert_return(name[0] != ':', -EINVAL); if (!bus->bus_client) return -EINVAL; - /* Don't allow requesting the special driver and local names */ + /* Don't allow releasing the special driver and local names */ if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local")) return -EINVAL; if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; - if (bus->is_kernel) - return bus_request_name_kernel(bus, name, flags); - else - return bus_request_name_dbus1(bus, name, flags); -} - -static int bus_release_name_kernel(sd_bus *bus, const char *name) { - struct kdbus_cmd *n; - size_t size, l; - int r; - - assert(bus); - assert(name); - - l = strlen(name) + 1; - size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l); - n = alloca0_align(size, 8); - n->size = size; - - n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l; - n->items[0].type = KDBUS_ITEM_NAME; - memcpy(n->items[0].str, name, l); - -#ifdef HAVE_VALGRIND_MEMCHECK_H - VALGRIND_MAKE_MEM_DEFINED(n, n->size); -#endif - r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n); - if (r < 0) - return -errno; - return 0; } -static int bus_release_name_dbus1(sd_bus *bus, const char *name) { +_public_ int sd_bus_release_name( + sd_bus *bus, + const char *name) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; uint32_t ret; int r; - assert(bus); - assert(name); + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(name, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = validate_release_name_parameters(bus, name); + if (r < 0) + return r; r = sd_bus_call_method( bus, @@ -208,129 +272,112 @@ static int bus_release_name_dbus1(sd_bus *bus, const char *name) { r = sd_bus_message_read(reply, "u", &ret); if (r < 0) return r; - if (ret == BUS_NAME_NON_EXISTENT) - return -ESRCH; - if (ret == BUS_NAME_NOT_OWNER) - return -EADDRINUSE; - if (ret == BUS_NAME_RELEASED) - return 0; - return -EINVAL; -} + switch (ret) { -_public_ int sd_bus_release_name(sd_bus *bus, const char *name) { - assert_return(bus, -EINVAL); - assert_return(name, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); - assert_return(service_name_is_valid(name), -EINVAL); - assert_return(name[0] != ':', -EINVAL); - - if (!bus->bus_client) - return -EINVAL; + case BUS_NAME_NON_EXISTENT: + return -ESRCH; - /* Don't allow releasing the special driver and local names */ - if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local")) - return -EINVAL; + case BUS_NAME_NOT_OWNER: + return -EADDRINUSE; - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + case BUS_NAME_RELEASED: + return 0; + } - if (bus->is_kernel) - return bus_release_name_kernel(bus, name); - else - return bus_release_name_dbus1(bus, name); + return -EIO; } -static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { - struct kdbus_cmd_list cmd = { - .size = sizeof(cmd), - .flags = flags, - }; - struct kdbus_info *name_list, *name; - uint64_t previous_id = 0; +static int default_release_name_handler( + sd_bus_message *m, + void *userdata, + sd_bus_error *ret_error) { + + uint32_t ret; int r; - /* Caller will free half-constructed list on failure... */ + assert(m); - r = ioctl(bus->input_fd, KDBUS_CMD_LIST, &cmd); - if (r < 0) - return -errno; + if (sd_bus_message_is_method_error(m, NULL)) { + log_debug_errno(sd_bus_message_get_errno(m), + "Unable to release name, failing connection: %s", + sd_bus_message_get_error(m)->message); - name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset); + bus_enter_closing(sd_bus_message_get_bus(m)); + return 1; + } - KDBUS_FOREACH(name, name_list, cmd.list_size) { - struct kdbus_item *item; + r = sd_bus_message_read(m, "u", &ret); + if (r < 0) + return r; - if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id && !(name->flags & KDBUS_HELLO_ACTIVATOR)) { - char *n; + switch (ret) { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat" - if (asprintf(&n, ":1.%llu", name->id) < 0) { - r = -ENOMEM; - goto fail; - } -#pragma GCC diagnostic pop - - r = strv_consume(x, n); - if (r < 0) - goto fail; + case BUS_NAME_NON_EXISTENT: + log_debug("Name asked to release is not taken currently, ignoring."); + return 1; - previous_id = name->id; - } + case BUS_NAME_NOT_OWNER: + log_debug("Name asked to release is owned by somebody else, ignoring."); + return 1; - KDBUS_ITEM_FOREACH(item, name, items) { - if (item->type == KDBUS_ITEM_OWNED_NAME) { - if (service_name_is_valid(item->name.name)) { - r = strv_extend(x, item->name.name); - if (r < 0) { - r = -ENOMEM; - goto fail; - } - } - } - } + case BUS_NAME_RELEASED: + log_debug("Name successfully released."); + return 1; } - r = 0; - -fail: - bus_kernel_cmd_free(bus, cmd.offset); - return r; + log_debug("Unexpected response from ReleaseName(), failing connection."); + bus_enter_closing(sd_bus_message_get_bus(m)); + return 1; } -static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) { - _cleanup_strv_free_ char **x = NULL, **y = NULL; - int r; - - if (acquired) { - r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x); - if (r < 0) - return r; - } +_public_ int sd_bus_release_name_async( + sd_bus *bus, + sd_bus_slot **ret_slot, + const char *name, + sd_bus_message_handler_t callback, + void *userdata) { - if (activatable) { - r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y); - if (r < 0) - return r; + int r; - *activatable = y; - y = NULL; - } + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(name, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); - if (acquired) { - *acquired = x; - x = NULL; - } + r = validate_release_name_parameters(bus, name); + if (r < 0) + return r; - return 0; + return sd_bus_call_method_async( + bus, + ret_slot, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "ReleaseName", + callback ?: default_release_name_handler, + userdata, + "s", + name); } -static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) { +_public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_strv_free_ char **x = NULL, **y = NULL; int r; + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(acquired || activatable, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (!bus->bus_client) + return -EINVAL; + + if (!BUS_IS_OPEN(bus->state)) + return -ENOTCONN; + if (acquired) { r = sd_bus_call_method( bus, @@ -368,401 +415,51 @@ static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatab if (r < 0) return r; - *activatable = y; - y = NULL; - } - - if (acquired) { - *acquired = x; - x = NULL; + *activatable = TAKE_PTR(y); } - return 0; -} - -_public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) { - assert_return(bus, -EINVAL); - assert_return(acquired || activatable, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); - - if (!bus->bus_client) - return -EINVAL; - - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; - - if (bus->is_kernel) - return bus_list_names_kernel(bus, acquired, activatable); - else - return bus_list_names_dbus1(bus, acquired, activatable); -} - -static int bus_populate_creds_from_items( - sd_bus *bus, - struct kdbus_info *info, - uint64_t mask, - sd_bus_creds *c) { - - struct kdbus_item *item; - uint64_t m; - int r; - - assert(bus); - assert(info); - assert(c); - - KDBUS_ITEM_FOREACH(item, info, items) { - - switch (item->type) { - - case KDBUS_ITEM_PIDS: - - if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) { - c->pid = (pid_t) item->pids.pid; - c->mask |= SD_BUS_CREDS_PID; - } - - if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) { - c->tid = (pid_t) item->pids.tid; - c->mask |= SD_BUS_CREDS_TID; - } - - if (mask & SD_BUS_CREDS_PPID) { - if (item->pids.ppid > 0) { - c->ppid = (pid_t) item->pids.ppid; - c->mask |= SD_BUS_CREDS_PPID; - } else if (item->pids.pid == 1) { - /* The structure doesn't - * really distinguish the case - * where a process has no - * parent and where we don't - * know it because it could - * not be translated due to - * namespaces. However, we - * know that PID 1 has no - * parent process, hence let's - * patch that in, manually. */ - c->ppid = 0; - c->mask |= SD_BUS_CREDS_PPID; - } - } - - break; - - case KDBUS_ITEM_CREDS: - - if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) { - c->uid = (uid_t) item->creds.uid; - c->mask |= SD_BUS_CREDS_UID; - } - - if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) { - c->euid = (uid_t) item->creds.euid; - c->mask |= SD_BUS_CREDS_EUID; - } - - if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) { - c->suid = (uid_t) item->creds.suid; - c->mask |= SD_BUS_CREDS_SUID; - } - - if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) { - c->fsuid = (uid_t) item->creds.fsuid; - c->mask |= SD_BUS_CREDS_FSUID; - } - - if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) { - c->gid = (gid_t) item->creds.gid; - c->mask |= SD_BUS_CREDS_GID; - } - - if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) { - c->egid = (gid_t) item->creds.egid; - c->mask |= SD_BUS_CREDS_EGID; - } - - if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) { - c->sgid = (gid_t) item->creds.sgid; - c->mask |= SD_BUS_CREDS_SGID; - } - - if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) { - c->fsgid = (gid_t) item->creds.fsgid; - c->mask |= SD_BUS_CREDS_FSGID; - } - - break; - - case KDBUS_ITEM_PID_COMM: - if (mask & SD_BUS_CREDS_COMM) { - r = free_and_strdup(&c->comm, item->str); - if (r < 0) - return r; - - c->mask |= SD_BUS_CREDS_COMM; - } - break; - - case KDBUS_ITEM_TID_COMM: - if (mask & SD_BUS_CREDS_TID_COMM) { - r = free_and_strdup(&c->tid_comm, item->str); - if (r < 0) - return r; - - c->mask |= SD_BUS_CREDS_TID_COMM; - } - break; - - case KDBUS_ITEM_EXE: - if (mask & SD_BUS_CREDS_EXE) { - r = free_and_strdup(&c->exe, item->str); - if (r < 0) - return r; - - c->mask |= SD_BUS_CREDS_EXE; - } - break; - - case KDBUS_ITEM_CMDLINE: - if (mask & SD_BUS_CREDS_CMDLINE) { - c->cmdline_size = item->size - offsetof(struct kdbus_item, data); - c->cmdline = memdup(item->data, c->cmdline_size); - if (!c->cmdline) - return -ENOMEM; - - c->mask |= SD_BUS_CREDS_CMDLINE; - } - break; - - case KDBUS_ITEM_CGROUP: - m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT | - SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE | - SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask; - - if (m) { - r = free_and_strdup(&c->cgroup, item->str); - if (r < 0) - return r; - - r = bus_get_root_path(bus); - if (r < 0) - return r; - - r = free_and_strdup(&c->cgroup_root, bus->cgroup_root); - if (r < 0) - return r; - - c->mask |= m; - } - break; - - case KDBUS_ITEM_CAPS: - m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS | - SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask; - - if (m) { - if (item->caps.last_cap != cap_last_cap() || - item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4) - return -EBADMSG; - - c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps)); - if (!c->capability) - return -ENOMEM; - - c->mask |= m; - } - break; - - case KDBUS_ITEM_SECLABEL: - if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { - r = free_and_strdup(&c->label, item->str); - if (r < 0) - return r; - - c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; - } - break; - - case KDBUS_ITEM_AUDIT: - if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) { - c->audit_session_id = (uint32_t) item->audit.sessionid; - c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; - } - - if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) { - c->audit_login_uid = (uid_t) item->audit.loginuid; - c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; - } - break; - - case KDBUS_ITEM_OWNED_NAME: - if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) { - r = strv_extend(&c->well_known_names, item->name.name); - if (r < 0) - return r; - - c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES; - } - break; - - case KDBUS_ITEM_CONN_DESCRIPTION: - if (mask & SD_BUS_CREDS_DESCRIPTION) { - r = free_and_strdup(&c->description, item->str); - if (r < 0) - return r; - - c->mask |= SD_BUS_CREDS_DESCRIPTION; - } - break; - - case KDBUS_ITEM_AUXGROUPS: - if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) { - size_t i, n; - uid_t *g; - - n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t); - g = new(gid_t, n); - if (!g) - return -ENOMEM; - - for (i = 0; i < n; i++) - g[i] = item->data64[i]; - - free(c->supplementary_gids); - c->supplementary_gids = g; - c->n_supplementary_gids = n; - - c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS; - } - break; - } - } + if (acquired) + *acquired = TAKE_PTR(x); return 0; } -int bus_get_name_creds_kdbus( +_public_ int sd_bus_get_name_creds( sd_bus *bus, const char *name, uint64_t mask, - bool allow_activator, sd_bus_creds **creds) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL; _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; - struct kdbus_cmd_info *cmd; - struct kdbus_info *conn_info; - size_t size, l; - uint64_t id; + const char *unique = NULL; + pid_t pid = 0; int r; - if (streq(name, "org.freedesktop.DBus")) - return -EOPNOTSUPP; - - r = bus_kernel_parse_unique_name(name, &id); - if (r < 0) - return r; - if (r > 0) { - size = offsetof(struct kdbus_cmd_info, items); - cmd = alloca0_align(size, 8); - cmd->id = id; - } else { - l = strlen(name) + 1; - size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l); - cmd = alloca0_align(size, 8); - cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l; - cmd->items[0].type = KDBUS_ITEM_NAME; - memcpy(cmd->items[0].str, name, l); - } - - /* If augmentation is on, and the bus didn't provide us - * the bits we want, then ask for the PID/TID so that we - * can read the rest from /proc. */ - if ((mask & SD_BUS_CREDS_AUGMENT) && - (mask & (SD_BUS_CREDS_PPID| - SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| - SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID| - SD_BUS_CREDS_SUPPLEMENTARY_GIDS| - SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| - SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID| - SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| - SD_BUS_CREDS_SELINUX_CONTEXT| - SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))) - mask |= SD_BUS_CREDS_PID; - - cmd->size = size; - cmd->attach_flags = attach_flags_to_kdbus(mask); - - r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd); - if (r < 0) - return -errno; - - conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset); - - /* Non-activated names are considered not available */ - if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) { - if (name[0] == ':') - r = -ENXIO; - else - r = -ESRCH; - goto fail; - } - - c = bus_creds_new(); - if (!c) { - r = -ENOMEM; - goto fail; - } - - if (mask & SD_BUS_CREDS_UNIQUE_NAME) { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat" - if (asprintf(&c->unique_name, ":1.%llu", conn_info->id) < 0) { - r = -ENOMEM; - goto fail; - } -#pragma GCC diagnostic pop - - c->mask |= SD_BUS_CREDS_UNIQUE_NAME; - } - - /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of - them in case the service has no names. This does not mean - however that the list of owned names could not be - acquired. Hence, let's explicitly clarify that the data is - complete. */ - c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES; - - r = bus_populate_creds_from_items(bus, conn_info, mask, c); - if (r < 0) - goto fail; - - r = bus_creds_add_more(c, mask, 0, 0); - if (r < 0) - goto fail; + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(name, -EINVAL); + assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP); + assert_return(mask == 0 || creds, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(service_name_is_valid(name), -EINVAL); - if (creds) { - *creds = c; - c = NULL; - } + if (!bus->bus_client) + return -EINVAL; - r = 0; + /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not + * going to match. */ + if (!bus->is_local) + mask &= ~SD_BUS_CREDS_AUGMENT; -fail: - bus_kernel_cmd_free(bus, cmd->offset); - return r; -} + if (streq(name, "org.freedesktop.DBus.Local")) + return -EINVAL; -static int bus_get_name_creds_dbus1( - sd_bus *bus, - const char *name, - uint64_t mask, - sd_bus_creds **creds) { + if (streq(name, "org.freedesktop.DBus")) + return sd_bus_get_owner_creds(bus, mask, creds); - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL; - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; - const char *unique = NULL; - pid_t pid = 0; - int r; + if (!BUS_IS_OPEN(bus->state)) + return -ENOTCONN; /* Only query the owner if the caller wants to know it or if * the caller just wants to check whether a name exists */ @@ -1018,112 +715,35 @@ static int bus_get_name_creds_dbus1( return r; } - if (creds) { - *creds = c; - c = NULL; - } + if (creds) + *creds = TAKE_PTR(c); return 0; } -_public_ int sd_bus_get_name_creds( - sd_bus *bus, - const char *name, - uint64_t mask, - sd_bus_creds **creds) { +_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; + pid_t pid = 0; + int r; assert_return(bus, -EINVAL); - assert_return(name, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP); - assert_return(mask == 0 || creds, -EINVAL); + assert_return(ret, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); - assert_return(service_name_is_valid(name), -EINVAL); - - if (!bus->bus_client) - return -EINVAL; - - /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not - * going to match. */ - if (!bus->is_local) - mask &= ~SD_BUS_CREDS_AUGMENT; - - if (streq(name, "org.freedesktop.DBus.Local")) - return -EINVAL; - - if (streq(name, "org.freedesktop.DBus")) - return sd_bus_get_owner_creds(bus, mask, creds); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; - if (bus->is_kernel) - return bus_get_name_creds_kdbus(bus, name, mask, false, creds); - else - return bus_get_name_creds_dbus1(bus, name, mask, creds); -} - -static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; - struct kdbus_cmd_info cmd = { - .size = sizeof(struct kdbus_cmd_info), - }; - struct kdbus_info *creator_info; - pid_t pid = 0; - int r; - - c = bus_creds_new(); - if (!c) - return -ENOMEM; - - /* If augmentation is on, and the bus doesn't didn't allow us - * to get the bits we want, then ask for the PID/TID so that we - * can read the rest from /proc. */ - if ((mask & SD_BUS_CREDS_AUGMENT) && - (mask & (SD_BUS_CREDS_PPID| - SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| - SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID| - SD_BUS_CREDS_SUPPLEMENTARY_GIDS| - SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| - SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID| - SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| - SD_BUS_CREDS_SELINUX_CONTEXT| - SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))) - mask |= SD_BUS_CREDS_PID; - - cmd.attach_flags = attach_flags_to_kdbus(mask); - - r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd); - if (r < 0) - return -errno; - - creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset); - - r = bus_populate_creds_from_items(bus, creator_info, mask, c); - bus_kernel_cmd_free(bus, cmd.offset); - if (r < 0) - return r; - - r = bus_creds_add_more(c, mask, pid, 0); - if (r < 0) - return r; - - *ret = c; - c = NULL; - return 0; -} - -static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; - pid_t pid = 0; - bool do_label; - int r; - - assert(bus); + if (!bus->is_local) + mask &= ~SD_BUS_CREDS_AUGMENT; do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); + do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS); /* Avoid allocating anything if we have no chance of returning useful data */ - if (!bus->ucred_valid && !do_label) + if (!bus->ucred_valid && !do_label && !do_groups) return -ENODATA; c = bus_creds_new(); @@ -1131,17 +751,17 @@ static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds ** return -ENOMEM; if (bus->ucred_valid) { - if (bus->ucred.pid > 0) { + if (pid_is_valid(bus->ucred.pid)) { pid = c->pid = bus->ucred.pid; c->mask |= SD_BUS_CREDS_PID & mask; } - if (bus->ucred.uid != UID_INVALID) { + if (uid_is_valid(bus->ucred.uid)) { c->euid = bus->ucred.uid; c->mask |= SD_BUS_CREDS_EUID & mask; } - if (bus->ucred.gid != GID_INVALID) { + if (gid_is_valid(bus->ucred.gid)) { c->egid = bus->ucred.gid; c->mask |= SD_BUS_CREDS_EGID & mask; } @@ -1155,436 +775,42 @@ static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds ** c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; } - r = bus_creds_add_more(c, mask, pid, 0); - if (r < 0) - return r; - - *ret = c; - c = NULL; - return 0; -} - -_public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { - assert_return(bus, -EINVAL); - assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP); - assert_return(ret, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); - - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; - - if (!bus->is_local) - mask &= ~SD_BUS_CREDS_AUGMENT; - - if (bus->is_kernel) - return bus_get_owner_creds_kdbus(bus, mask, ret); - else - return bus_get_owner_creds_dbus1(bus, mask, ret); -} - -static int add_name_change_match(sd_bus *bus, - uint64_t cookie, - const char *name, - const char *old_owner, - const char *new_owner) { - - uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0; - int is_name_id = -1, r; - struct kdbus_item *item; - - assert(bus); - - /* If we encounter a match that could match against - * NameOwnerChanged messages, then we need to create - * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and - * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly - * multiple if the match is underspecified. - * - * The NameOwnerChanged signals take three parameters with - * unique or well-known names, but only some forms actually - * exist: - * - * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD - * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE - * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE - * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD - * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE - * - * For the latter two the two unique names must be identical. - * - * */ - - if (name) { - is_name_id = bus_kernel_parse_unique_name(name, &name_id); - if (is_name_id < 0) - return 0; - } - - if (!isempty(old_owner)) { - r = bus_kernel_parse_unique_name(old_owner, &old_owner_id); - if (r < 0) - return 0; - if (r == 0) - return 0; - if (is_name_id > 0 && old_owner_id != name_id) - return 0; - } else - old_owner_id = KDBUS_MATCH_ID_ANY; - - if (!isempty(new_owner)) { - r = bus_kernel_parse_unique_name(new_owner, &new_owner_id); - if (r < 0) - return r; - if (r == 0) - return 0; - if (is_name_id > 0 && new_owner_id != name_id) - return 0; - } else - new_owner_id = KDBUS_MATCH_ID_ANY; - - if (is_name_id <= 0) { - struct kdbus_cmd_match *m; - size_t sz, l; - - /* If the name argument is missing or is a well-known - * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} - * matches for it */ - - l = name ? strlen(name) + 1 : 0; - - sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) + - offsetof(struct kdbus_item, name_change) + - offsetof(struct kdbus_notify_name_change, name) + - l); - - m = alloca0_align(sz, 8); - m->size = sz; - m->cookie = cookie; - - item = m->items; - item->size = - offsetof(struct kdbus_item, name_change) + - offsetof(struct kdbus_notify_name_change, name) + - l; - - item->name_change.old_id.id = old_owner_id; - item->name_change.new_id.id = new_owner_id; - - memcpy_safe(item->name_change.name, name, l); - - /* If the old name is unset or empty, then - * this can match against added names */ - if (isempty(old_owner)) { - item->type = KDBUS_ITEM_NAME_ADD; - - r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); - if (r < 0) - return -errno; - } - - /* If the new name is unset or empty, then - * this can match against removed names */ - if (isempty(new_owner)) { - item->type = KDBUS_ITEM_NAME_REMOVE; - - r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); - if (r < 0) - return -errno; - } - - /* The CHANGE match we need in either case, because - * what is reported as a name change by the kernel - * might just be an owner change between starter and - * normal clients. For userspace such a change should - * be considered a removal/addition, hence let's - * subscribe to this unconditionally. */ - item->type = KDBUS_ITEM_NAME_CHANGE; - r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); - if (r < 0) - return -errno; - } - - if (is_name_id != 0) { - struct kdbus_cmd_match *m; - uint64_t sz; - - /* If the name argument is missing or is a unique - * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches - * for it */ - - sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) + - offsetof(struct kdbus_item, id_change) + - sizeof(struct kdbus_notify_id_change)); - - m = alloca0_align(sz, 8); - m->size = sz; - m->cookie = cookie; - - item = m->items; - item->size = - offsetof(struct kdbus_item, id_change) + - sizeof(struct kdbus_notify_id_change); - item->id_change.id = name_id; - - /* If the old name is unset or empty, then this can - * match against added ids */ - if (isempty(old_owner)) { - item->type = KDBUS_ITEM_ID_ADD; - if (!isempty(new_owner)) - item->id_change.id = new_owner_id; - - r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); - if (r < 0) - return -errno; - } - - /* If thew new name is unset or empty, then this can - * match against removed ids */ - if (isempty(new_owner)) { - item->type = KDBUS_ITEM_ID_REMOVE; - if (!isempty(old_owner)) - item->id_change.id = old_owner_id; - - r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); - if (r < 0) - return -errno; - } - } - - return 0; -} - -int bus_add_match_internal_kernel( - sd_bus *bus, - struct bus_match_component *components, - unsigned n_components, - uint64_t cookie) { - - struct kdbus_cmd_match *m; - struct kdbus_item *item; - uint64_t *bloom; - size_t sz; - const char *sender = NULL; - size_t sender_length = 0; - uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY; - bool using_bloom = false; - unsigned i; - bool matches_name_change = true; - const char *name_change_arg[3] = {}; - int r; - - assert(bus); - - /* Monitor streams don't support matches, make this a NOP */ - if (bus->hello_flags & KDBUS_HELLO_MONITOR) - return 0; - - bloom = alloca0(bus->bloom_size); - - sz = ALIGN8(offsetof(struct kdbus_cmd_match, items)); - - for (i = 0; i < n_components; i++) { - struct bus_match_component *c = &components[i]; - - switch (c->type) { - - case BUS_MATCH_SENDER: - if (!streq(c->value_str, "org.freedesktop.DBus")) - matches_name_change = false; - - r = bus_kernel_parse_unique_name(c->value_str, &src_id); - if (r < 0) - return r; - else if (r > 0) - sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t)); - else { - sender = c->value_str; - sender_length = strlen(sender); - sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1); - } - - break; - - case BUS_MATCH_MESSAGE_TYPE: - if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL) - matches_name_change = false; - - bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8)); - using_bloom = true; - break; - - case BUS_MATCH_INTERFACE: - if (!streq(c->value_str, "org.freedesktop.DBus")) - matches_name_change = false; - - bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str); - using_bloom = true; - break; - - case BUS_MATCH_MEMBER: - if (!streq(c->value_str, "NameOwnerChanged")) - matches_name_change = false; - - bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str); - using_bloom = true; - break; - - case BUS_MATCH_PATH: - if (!streq(c->value_str, "/org/freedesktop/DBus")) - matches_name_change = false; - - bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str); - using_bloom = true; - break; - - case BUS_MATCH_PATH_NAMESPACE: - bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str); - using_bloom = true; - break; - - case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: { - char buf[sizeof("arg")-1 + 2 + 1]; - - if (c->type - BUS_MATCH_ARG < 3) - name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str; - - xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG); - bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); - using_bloom = true; - break; - } - - case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: { - char buf[sizeof("arg")-1 + 2 + sizeof("-has")]; - - xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS); - bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); - using_bloom = true; - break; - } - - case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: - /* - * XXX: DBus spec defines arg[0..63]path= matching to be - * a two-way glob. That is, if either string is a prefix - * of the other, it matches. - * This is really hard to realize in bloom-filters, as - * we would have to create a bloom-match for each prefix - * of @c->value_str. This is excessive, hence we just - * ignore all those matches and accept everything from - * the kernel. People should really avoid those matches. - * If they're used in real-life some day, we will have - * to properly support multiple-matches here. - */ - break; - - case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: { - char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")]; - - xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE); - bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); - using_bloom = true; - break; - } - - case BUS_MATCH_DESTINATION: - /* - * Kernel only supports matching on destination IDs, but - * not on destination names. So just skip the - * destination name restriction and verify it in - * user-space on retrieval. - */ - r = bus_kernel_parse_unique_name(c->value_str, &dst_id); - if (r < 0) - return r; - else if (r > 0) - sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t)); - - /* if not a broadcast, it cannot be a name-change */ - if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST) - matches_name_change = false; - - break; - - case BUS_MATCH_ROOT: - case BUS_MATCH_VALUE: - case BUS_MATCH_LEAF: - case _BUS_MATCH_NODE_TYPE_MAX: - case _BUS_MATCH_NODE_TYPE_INVALID: - assert_not_reached("Invalid match type?"); - } - } - - if (using_bloom) - sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size); - - m = alloca0_align(sz, 8); - m->size = sz; - m->cookie = cookie; - - item = m->items; - - if (src_id != KDBUS_MATCH_ID_ANY) { - item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t); - item->type = KDBUS_ITEM_ID; - item->id = src_id; - item = KDBUS_ITEM_NEXT(item); - } - - if (dst_id != KDBUS_MATCH_ID_ANY) { - item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t); - item->type = KDBUS_ITEM_DST_ID; - item->id = dst_id; - item = KDBUS_ITEM_NEXT(item); - } + if (do_groups) { + c->supplementary_gids = newdup(gid_t, bus->groups, bus->n_groups); + if (!c->supplementary_gids) + return -ENOMEM; - if (using_bloom) { - item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size; - item->type = KDBUS_ITEM_BLOOM_MASK; - memcpy(item->data64, bloom, bus->bloom_size); - item = KDBUS_ITEM_NEXT(item); - } + c->n_supplementary_gids = bus->n_groups; - if (sender) { - item->size = offsetof(struct kdbus_item, str) + sender_length + 1; - item->type = KDBUS_ITEM_NAME; - memcpy(item->str, sender, sender_length + 1); + c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS; } - r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); + r = bus_creds_add_more(c, mask, pid, 0); if (r < 0) - return -errno; - - if (matches_name_change) { + return r; - /* If this match could theoretically match - * NameOwnerChanged messages, we need to - * install a second non-bloom filter explitly - * for it */ - - r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]); - if (r < 0) - return r; - } + *ret = TAKE_PTR(c); return 0; } -#define internal_match(bus, m) \ - ((bus)->hello_flags & KDBUS_HELLO_MONITOR \ +#define append_eavesdrop(bus, m) \ + ((bus)->is_monitor \ ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \ : (m)) -static int bus_add_match_internal_dbus1( +int bus_add_match_internal( sd_bus *bus, const char *match) { const char *e; assert(bus); - assert(match); - e = internal_match(bus, match); + if (!bus->bus_client) + return -EINVAL; + + e = append_eavesdrop(bus, match); return sd_bus_call_method( bus, @@ -1597,49 +823,36 @@ static int bus_add_match_internal_dbus1( "s", e); } - -int bus_add_match_internal( +int bus_add_match_internal_async( sd_bus *bus, + sd_bus_slot **ret_slot, const char *match, - struct bus_match_component *components, - unsigned n_components, - uint64_t cookie) { + sd_bus_message_handler_t callback, + void *userdata) { + + const char *e; assert(bus); if (!bus->bus_client) return -EINVAL; - if (bus->is_kernel) - return bus_add_match_internal_kernel(bus, components, n_components, cookie); - else - return bus_add_match_internal_dbus1(bus, match); -} - -int bus_remove_match_internal_kernel( - sd_bus *bus, - uint64_t cookie) { - - struct kdbus_cmd_match m = { - .size = offsetof(struct kdbus_cmd_match, items), - .cookie = cookie, - }; - int r; - - assert(bus); - - /* Monitor streams don't support matches, make this a NOP */ - if (bus->hello_flags & KDBUS_HELLO_MONITOR) - return 0; - - r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m); - if (r < 0) - return -errno; + e = append_eavesdrop(bus, match); - return 0; + return sd_bus_call_method_async( + bus, + ret_slot, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "AddMatch", + callback, + userdata, + "s", + e); } -static int bus_remove_match_internal_dbus1( +int bus_remove_match_internal( sd_bus *bus, const char *match) { @@ -1648,10 +861,16 @@ static int bus_remove_match_internal_dbus1( assert(bus); assert(match); - e = internal_match(bus, match); + if (!bus->bus_client) + return -EINVAL; - return sd_bus_call_method( + e = append_eavesdrop(bus, match); + + /* Fire and forget */ + + return sd_bus_call_method_async( bus, + NULL, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", @@ -1662,28 +881,13 @@ static int bus_remove_match_internal_dbus1( e); } -int bus_remove_match_internal( - sd_bus *bus, - const char *match, - uint64_t cookie) { - - assert(bus); - - if (!bus->bus_client) - return -EINVAL; - - if (bus->is_kernel) - return bus_remove_match_internal_kernel(bus, cookie); - else - return bus_remove_match_internal_dbus1(bus, match); -} - _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; const char *mid; int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(name, -EINVAL); assert_return(machine, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); diff --git a/src/libelogind/sd-bus/bus-control.h b/src/libelogind/sd-bus/bus-control.h index c181aa795..901729749 100644 --- a/src/libelogind/sd-bus/bus-control.h +++ b/src/libelogind/sd-bus/bus-control.h @@ -1,32 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "sd-bus.h" -#include "bus-match.h" - -int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components, uint64_t cookie); -int bus_remove_match_internal(sd_bus *bus, const char *match, uint64_t cookie); - -int bus_add_match_internal_kernel(sd_bus *bus, struct bus_match_component *components, unsigned n_components, uint64_t cookie); -int bus_remove_match_internal_kernel(sd_bus *bus, uint64_t cookie); +int bus_add_match_internal(sd_bus *bus, const char *match); +int bus_add_match_internal_async(sd_bus *bus, sd_bus_slot **ret, const char *match, sd_bus_message_handler_t callback, void *userdata); -int bus_get_name_creds_kdbus(sd_bus *bus, const char *name, uint64_t mask, bool allow_activator, sd_bus_creds **creds); +int bus_remove_match_internal(sd_bus *bus, const char *match); diff --git a/src/libelogind/sd-bus/bus-convenience.c b/src/libelogind/sd-bus/bus-convenience.c index 04158cae4..68a419c6d 100644 --- a/src/libelogind/sd-bus/bus-convenience.c +++ b/src/libelogind/sd-bus/bus-convenience.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "bus-internal.h" @@ -35,6 +20,7 @@ _public_ int sd_bus_emit_signal( int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) @@ -72,6 +58,7 @@ _public_ int sd_bus_call_method_async( int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) @@ -533,22 +520,20 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b * to get it from the sender or peer. */ if (call->sender) - /* There's a sender, but the creds are - * missing. This means we are talking via - * dbus1, or are getting a message that was - * sent to us via kdbus, but was converted - * from a dbus1 message by the bus-proxy and - * thus also lacks the creds. */ + /* There's a sender, but the creds are missing. */ return sd_bus_get_name_creds(call->bus, call->sender, mask, creds); else - /* There's no sender, hence we are on a dbus1 - * direct connection. For direct connections + /* There's no sender. For direct connections * the credentials of the AF_UNIX peer matter, - * which may be queried via - * sd_bus_get_owner_creds(). */ + * which may be queried via sd_bus_get_owner_creds(). */ return sd_bus_get_owner_creds(call->bus, mask, creds); } + log_debug_elogind("Called by UID %u ; %s [%s] (%s)", c->uid, + c->unique_name ? c->unique_name : "no name", + c->label ? c->label : "no label", + c->description ? c->description : "no desc"); + return bus_creds_extend_by_pid(c, mask, creds); } @@ -579,9 +564,6 @@ _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) * here. */ assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM); - /* Note that not even on kdbus we might have the caps - * field, due to faked identities, or namespace - * translation issues. */ r = sd_bus_creds_has_effective_cap(creds, capability); if (r > 0) return 1; @@ -624,3 +606,71 @@ _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) return 0; } + +#define make_expression(sender, path, interface, member) \ + strjoina( \ + "type='signal'", \ + sender ? ",sender='" : "", \ + sender ?: "", \ + sender ? "'" : "", \ + path ? ",path='" : "", \ + path ?: "", \ + path ? "'" : "", \ + interface ? ",interface='" : "", \ + interface ?: "", \ + interface ? "'" : "", \ + member ? ",member='" : "", \ + member ?: "", \ + member ? "'" : "" \ + ) + +_public_ int sd_bus_match_signal( + sd_bus *bus, + sd_bus_slot **ret, + const char *sender, + const char *path, + const char *interface, + const char *member, + sd_bus_message_handler_t callback, + void *userdata) { + + const char *expression; + + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!sender || service_name_is_valid(sender), -EINVAL); + assert_return(!path || object_path_is_valid(path), -EINVAL); + assert_return(!interface || interface_name_is_valid(interface), -EINVAL); + assert_return(!member || member_name_is_valid(member), -EINVAL); + + expression = make_expression(sender, path, interface, member); + + return sd_bus_add_match(bus, ret, expression, callback, userdata); +} + +_public_ int sd_bus_match_signal_async( + sd_bus *bus, + sd_bus_slot **ret, + const char *sender, + const char *path, + const char *interface, + const char *member, + sd_bus_message_handler_t callback, + sd_bus_message_handler_t install_callback, + void *userdata) { + + const char *expression; + + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!sender || service_name_is_valid(sender), -EINVAL); + assert_return(!path || object_path_is_valid(path), -EINVAL); + assert_return(!interface || interface_name_is_valid(interface), -EINVAL); + assert_return(!member || member_name_is_valid(member), -EINVAL); + + expression = make_expression(sender, path, interface, member); + + return sd_bus_add_match_async(bus, ret, expression, callback, install_callback, userdata); +} diff --git a/src/libelogind/sd-bus/bus-creds.c b/src/libelogind/sd-bus/bus-creds.c index d52bbff84..7104a5371 100644 --- a/src/libelogind/sd-bus/bus-creds.c +++ b/src/libelogind/sd-bus/bus-creds.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <linux/capability.h> @@ -128,7 +113,6 @@ _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) { sd_bus_message_unref(m); } - return NULL; } @@ -165,7 +149,7 @@ _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t m assert_return(ret, -EINVAL); if (pid == 0) - pid = getpid(); + pid = getpid_cached(); c = bus_creds_new(); if (!c) @@ -221,7 +205,6 @@ _public_ int sd_bus_creds_get_suid(sd_bus_creds *c, uid_t *suid) { return 0; } - _public_ int sd_bus_creds_get_fsuid(sd_bus_creds *c, uid_t *fsuid) { assert_return(c, -EINVAL); assert_return(fsuid, -EINVAL); @@ -444,6 +427,7 @@ _public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) { *ret = c->user_unit; return 0; } +#endif // 0 _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) { int r; @@ -498,7 +482,6 @@ _public_ int sd_bus_creds_get_user_slice(sd_bus_creds *c, const char **ret) { *ret = c->user_slice; return 0; } -#endif // 0 _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) { int r; @@ -543,15 +526,12 @@ _public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) { assert(c->cgroup); r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted); + log_debug_elogind("Shifted to %s from %s/%s for c->uid %u (result %d)", + shifted, c->cgroup_root, c->cgroup, c->uid, r); if (r < 0) return r; -#if 0 /// elogind does not support systemd slices return cg_path_get_owner_uid(shifted, uid); -#else - *uid = c->uid; - return 0; -#endif // 0 } _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) { @@ -580,7 +560,7 @@ _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessio if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID)) return -ENODATA; - if (c->audit_session_id == AUDIT_SESSION_INVALID) + if (!audit_session_is_valid(c->audit_session_id)) return -ENXIO; *sessionid = c->audit_session_id; @@ -594,7 +574,7 @@ _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) { if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID)) return -ENODATA; - if (c->audit_login_uid == UID_INVALID) + if (!uid_is_valid(c->audit_login_uid)) return -ENXIO; *uid = c->audit_login_uid; @@ -826,7 +806,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (!f) { if (errno == ENOENT) return -ESRCH; - else if (errno != EPERM && errno != EACCES) + else if (!IN_SET(errno, EPERM, EACCES)) return -errno; } else { char line[LINE_MAX]; @@ -984,7 +964,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { p = procfs_file_alloca(pid, "attr/current"); r = read_one_line_file(p, &c->label); if (r < 0) { - if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES) + if (!IN_SET(r, -ENOENT, -EINVAL, -EPERM, -EACCES)) return r; } else c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; @@ -993,7 +973,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (missing & SD_BUS_CREDS_COMM) { r = get_process_comm(pid, &c->comm); if (r < 0) { - if (r != -EPERM && r != -EACCES) + if (!IN_SET(r, -EPERM, -EACCES)) return r; } else c->mask |= SD_BUS_CREDS_COMM; @@ -1012,7 +992,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { c->exe = NULL; c->mask |= SD_BUS_CREDS_EXE; } else if (r < 0) { - if (r != -EPERM && r != -EACCES) + if (!IN_SET(r, -EPERM, -EACCES)) return r; } else c->mask |= SD_BUS_CREDS_EXE; @@ -1026,7 +1006,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (r == -ENOENT) return -ESRCH; if (r < 0) { - if (r != -EPERM && r != -EACCES) + if (!IN_SET(r, -EPERM, -EACCES)) return r; } else { if (c->cmdline_size == 0) @@ -1046,7 +1026,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (r == -ENOENT) return -ESRCH; if (r < 0) { - if (r != -EPERM && r != -EACCES) + if (!IN_SET(r, -EPERM, -EACCES)) return r; } else c->mask |= SD_BUS_CREDS_TID_COMM; @@ -1057,7 +1037,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (!c->cgroup) { r = cg_pid_get_path(NULL, pid, &c->cgroup); if (r < 0) { - if (r != -EPERM && r != -EACCES) + if (!IN_SET(r, -EPERM, -EACCES)) return r; } } @@ -1079,7 +1059,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { c->audit_session_id = AUDIT_SESSION_INVALID; c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; } else if (r < 0) { - if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES) + if (!IN_SET(r, -EOPNOTSUPP, -ENOENT, -EPERM, -EACCES)) return r; } else c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; @@ -1092,7 +1072,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { c->audit_login_uid = UID_INVALID; c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; } else if (r < 0) { - if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES) + if (!IN_SET(r, -EOPNOTSUPP, -ENOENT, -EPERM, -EACCES)) return r; } else c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; @@ -1105,7 +1085,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { c->tty = NULL; c->mask |= SD_BUS_CREDS_TTY; } else if (r < 0) { - if (r != -EPERM && r != -EACCES && r != -ENOENT) + if (!IN_SET(r, -EPERM, -EACCES, -ENOENT)) return r; } else c->mask |= SD_BUS_CREDS_TTY; @@ -1353,7 +1333,7 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) if (r < 0) return r; - *ret = n; - n = NULL; + *ret = TAKE_PTR(n); + return 0; } diff --git a/src/libelogind/sd-bus/bus-creds.h b/src/libelogind/sd-bus/bus-creds.h index df8a1f100..7b77a1d73 100644 --- a/src/libelogind/sd-bus/bus-creds.h +++ b/src/libelogind/sd-bus/bus-creds.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <stdbool.h> diff --git a/src/libelogind/sd-bus/bus-error.c b/src/libelogind/sd-bus/bus-error.c index 378f7a377..ec359ac13 100644 --- a/src/libelogind/sd-bus/bus-error.c +++ b/src/libelogind/sd-bus/bus-error.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <errno.h> @@ -107,6 +92,7 @@ static int bus_error_name_to_errno(const char *name) { } m = __start_BUS_ERROR_MAP; +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION while (m < __stop_BUS_ERROR_MAP) { /* For magic ELF error maps, the end marker might * appear in the middle of things, since multiple maps @@ -124,6 +110,7 @@ static int bus_error_name_to_errno(const char *name) { m++; } +#endif return EIO; } @@ -594,7 +581,7 @@ _public_ int sd_bus_error_add_map(const sd_bus_error_map *map) { if (additional_error_maps[n] == map) return 0; - maps = realloc_multiply(additional_error_maps, sizeof(struct sd_bus_error_map*), n + 2); + maps = reallocarray(additional_error_maps, n + 2, sizeof(struct sd_bus_error_map*)); if (!maps) return -ENOMEM; diff --git a/src/libelogind/sd-bus/bus-error.h b/src/libelogind/sd-bus/bus-error.h index e2c4cf4b3..93cb9acd9 100644 --- a/src/libelogind/sd-bus/bus-error.h +++ b/src/libelogind/sd-bus/bus-error.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <stdbool.h> diff --git a/src/libelogind/sd-bus/bus-gvariant.c b/src/libelogind/sd-bus/bus-gvariant.c index 58782767f..05b17589d 100644 --- a/src/libelogind/sd-bus/bus-gvariant.c +++ b/src/libelogind/sd-bus/bus-gvariant.c @@ -1,21 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. +***/ - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. +#include <errno.h> +#include <string.h> - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ +#include "sd-bus.h" #include "bus-gvariant.h" #include "bus-signature.h" diff --git a/src/libelogind/sd-bus/bus-gvariant.h b/src/libelogind/sd-bus/bus-gvariant.h index 6da637fb0..40e3053ec 100644 --- a/src/libelogind/sd-bus/bus-gvariant.h +++ b/src/libelogind/sd-bus/bus-gvariant.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "macro.h" diff --git a/src/libelogind/sd-bus/bus-internal.c b/src/libelogind/sd-bus/bus-internal.c index 14d590a80..3e0f7d047 100644 --- a/src/libelogind/sd-bus/bus-internal.c +++ b/src/libelogind/sd-bus/bus-internal.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "alloc-util.h" @@ -148,7 +133,7 @@ bool service_name_is_valid(const char *p) { (*q >= 'a' && *q <= 'z') || (*q >= 'A' && *q <= 'Z') || ((!dot || unique) && *q >= '0' && *q <= '9') || - *q == '_' || *q == '-'; + IN_SET(*q, '_', '-'); if (!good) return false; @@ -363,13 +348,18 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) { } else return r; - log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s", + log_debug("Failed to process message type=%s sender=%s destination=%s path=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " signature=%s error-name=%s error-message=%s: %s", bus_message_type_to_string(m->header->type), - strna(m->sender), - strna(m->path), - strna(m->interface), - strna(m->member), + strna(sd_bus_message_get_sender(m)), + strna(sd_bus_message_get_destination(m)), + strna(sd_bus_message_get_path(m)), + strna(sd_bus_message_get_interface(m)), + strna(sd_bus_message_get_member(m)), + BUS_MESSAGE_COOKIE(m), + m->reply_cookie, strna(m->root_container.signature), + strna(m->error.name), + strna(m->error.message), bus_error_message(error, r)); return 1; diff --git a/src/libelogind/sd-bus/bus-internal.h b/src/libelogind/sd-bus/bus-internal.h index 4818ae28b..904d61038 100644 --- a/src/libelogind/sd-bus/bus-internal.h +++ b/src/libelogind/sd-bus/bus-internal.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <pthread.h> @@ -27,8 +12,8 @@ #include "bus-error.h" #include "bus-kernel.h" #include "bus-match.h" +#include "def.h" #include "hashmap.h" -#include "kdbus.h" #include "list.h" #include "prioq.h" #include "refcnt.h" @@ -37,7 +22,7 @@ struct reply_callback { sd_bus_message_handler_t callback; - usec_t timeout; + usec_t timeout_usec; /* this is a relative timeout until we reach the BUS_HELLO state, and an absolute one right after */ uint64_t cookie; unsigned prioq_idx; }; @@ -52,8 +37,10 @@ struct filter_callback { struct match_callback { sd_bus_message_handler_t callback; + sd_bus_message_handler_t install_callback; + + sd_bus_slot *install_slot; /* The AddMatch() call */ - uint64_t cookie; unsigned last_iteration; char *match_string; @@ -137,8 +124,17 @@ struct sd_bus_slot { unsigned n_ref; sd_bus *bus; void *userdata; + sd_bus_destroy_t destroy_callback; BusSlotType type:5; + + /* Slots can be "floating" or not. If they are not floating (the usual case) then they reference the bus object + * they are associated with. This means the bus object stays allocated at least as long as there is a slot + * around associated with it. If it is floating, then the slot's lifecycle is bound to the lifecycle of the + * bus: it will be disconnected from the bus when the bus is destroyed, and it keeping the slot reffed hence + * won't mean the bus stays reffed too. Internally this means the reference direction is reversed: floating + * slots objects are referenced by the bus object, and not vice versa. */ bool floating:1; + bool match_added:1; char *description; @@ -157,12 +153,14 @@ struct sd_bus_slot { enum bus_state { BUS_UNSET, - BUS_OPENING, - BUS_AUTHENTICATING, - BUS_HELLO, + BUS_WATCH_BIND, /* waiting for the socket to appear via inotify */ + BUS_OPENING, /* the kernel's connect() is still not ready */ + BUS_AUTHENTICATING, /* we are currently in the "SASL" authorization phase of dbus */ + BUS_HELLO, /* we are waiting for the Hello() response */ BUS_RUNNING, BUS_CLOSING, - BUS_CLOSED + BUS_CLOSED, + _BUS_STATE_MAX, }; static inline bool BUS_IS_OPEN(enum bus_state state) { @@ -188,10 +186,10 @@ struct sd_bus { enum bus_state state; int input_fd, output_fd; + int inotify_fd; int message_version; int message_endian; - bool is_kernel:1; bool can_fds:1; bool bus_client:1; bool ucred_valid:1; @@ -203,8 +201,6 @@ struct sd_bus { bool filter_callbacks_modified:1; bool nodes_modified:1; bool trusted:1; - bool fake_creds_valid:1; - bool fake_pids_valid:1; bool manual_peer_interface:1; bool is_system:1; bool is_user:1; @@ -213,6 +209,11 @@ struct sd_bus { bool exited:1; bool exit_triggered:1; bool is_local:1; + bool watch_bind:1; + bool is_monitor:1; + bool accept_fd:1; + bool attach_timestamp:1; + bool connected_signal:1; int use_memfd; @@ -245,7 +246,6 @@ struct sd_bus { union sockaddr_union sockaddr; socklen_t sockaddr_size; - char *kernel; char *machine; pid_t nspid; @@ -265,19 +265,19 @@ struct sd_bus { struct ucred ucred; char *label; + gid_t *groups; + size_t n_groups; uint64_t creds_mask; int *fds; - unsigned n_fds; + size_t n_fds; char *exec_path; char **exec_argv; unsigned iteration_counter; - void *kdbus_buffer; - /* We do locking around the memfd cache, since we want to * allow people to process a sd_bus_message in a different * thread then it was generated on and free it there. Since @@ -289,16 +289,13 @@ struct sd_bus { unsigned n_memfd_cache; pid_t original_pid; - - uint64_t hello_flags; - uint64_t attach_flags; - - uint64_t match_cookie; + pid_t busexec_pid; sd_event_source *input_io_event_source; sd_event_source *output_io_event_source; sd_event_source *time_event_source; sd_event_source *quit_event_source; + sd_event_source *inotify_event_source; sd_event *event; int event_priority; @@ -310,29 +307,31 @@ struct sd_bus { sd_bus **default_bus_ptr; pid_t tid; - struct kdbus_creds fake_creds; - struct kdbus_pids fake_pids; - char *fake_label; - char *cgroup_root; char *description; - - size_t bloom_size; - unsigned bloom_n_hash; + char *patch_sender; sd_bus_track *track_queue; LIST_HEAD(sd_bus_slot, slots); LIST_HEAD(sd_bus_track, tracks); + + int *inotify_watches; + size_t n_inotify_watches; }; +/* For method calls we time-out at 25s, like in the D-Bus reference implementation */ #define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC)) +/* For the authentication phase we grant 90s, to provide extra room during boot, when RNGs and such are not filled up + * with enough entropy yet and might delay the boot */ +#define BUS_AUTH_TIMEOUT ((usec_t) DEFAULT_TIMEOUT_USEC) + #define BUS_WQUEUE_MAX (192*1024) #define BUS_RQUEUE_MAX (192*1024) -#define BUS_MESSAGE_SIZE_MAX (64*1024*1024) +#define BUS_MESSAGE_SIZE_MAX (128*1024*1024) #define BUS_AUTH_SIZE_MAX (64*1024) #define BUS_CONTAINER_DEPTH 128 @@ -365,6 +364,8 @@ const char *bus_message_type_to_string(uint8_t u) _pure_; #define error_name_is_valid interface_name_is_valid +sd_bus *bus_resolve(sd_bus *bus); + int bus_ensure_running(sd_bus *bus); int bus_start_running(sd_bus *bus); int bus_next_address(sd_bus *bus); @@ -377,6 +378,12 @@ bool bus_pid_changed(sd_bus *bus); char *bus_address_escape(const char *v); +int bus_attach_io_events(sd_bus *b); +int bus_attach_inotify_event(sd_bus *b); + +void bus_close_inotify_fd(sd_bus *b); +void bus_close_io_fds(sd_bus *b); + #define OBJECT_PATH_FOREACH_PREFIX(prefix, path) \ for (char *_slash = ({ strcpy((prefix), (path)); streq((prefix), "/") ? NULL : strrchr((prefix), '/'); }) ; \ _slash && !(_slash[(_slash) == (prefix)] = 0); \ @@ -396,9 +403,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host); int bus_set_address_system_machine(sd_bus *b, const char *machine); #if 0 /// UNNEEDED by elogind -int bus_remove_match_by_string(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata); #endif // 0 - int bus_get_root_path(sd_bus *bus); int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error); @@ -408,3 +413,7 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error); if (!assert_log(expr, #expr)) \ return sd_bus_error_set_errno(error, r); \ } while (false) + +void bus_enter_closing(sd_bus *bus); + +void bus_set_state(sd_bus *bus, enum bus_state state); diff --git a/src/libelogind/sd-bus/bus-introspect.c b/src/libelogind/sd-bus/bus-introspect.c index d4b9878b1..483c29949 100644 --- a/src/libelogind/sd-bus/bus-introspect.c +++ b/src/libelogind/sd-bus/bus-introspect.c @@ -1,22 +1,9 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <stdio_ext.h> + #include "bus-internal.h" #include "bus-introspect.h" #include "bus-protocol.h" @@ -36,6 +23,8 @@ int introspect_begin(struct introspect *i, bool trusted) { if (!i->f) return -ENOMEM; + (void) __fsetlocking(i->f, FSETLOCKING_BYCALLER); + fputs(BUS_INTROSPECT_DOCTYPE "<node>\n", i->f); @@ -81,9 +70,9 @@ static void introspect_write_flags(struct introspect *i, int type, int flags) { if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY)) fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f); - if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) { + if (IN_SET(type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY)) { if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT) - fputs(" <annotation name=\"org.freedesktop.login1.Explicit\" value=\"true\"/>\n", i->f); + fputs(" <annotation name=\"org.freedesktop.elogind1.Explicit\" value=\"true\"/>\n", i->f); if (flags & SD_BUS_VTABLE_PROPERTY_CONST) fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f); @@ -94,9 +83,9 @@ static void introspect_write_flags(struct introspect *i, int type, int flags) { } if (!i->trusted && - (type == _SD_BUS_VTABLE_METHOD || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) && + IN_SET(type, _SD_BUS_VTABLE_METHOD, _SD_BUS_VTABLE_WRITABLE_PROPERTY) && !(flags & SD_BUS_VTABLE_UNPRIVILEGED)) - fputs(" <annotation name=\"org.freedesktop.login1.Privileged\" value=\"true\"/>\n", i->f); + fputs(" <annotation name=\"org.freedesktop.elogind1.Privileged\" value=\"true\"/>\n", i->f); } static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) { diff --git a/src/libelogind/sd-bus/bus-introspect.h b/src/libelogind/sd-bus/bus-introspect.h index 8e2f3800c..5dcaeace9 100644 --- a/src/libelogind/sd-bus/bus-introspect.h +++ b/src/libelogind/sd-bus/bus-introspect.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <stdio.h> diff --git a/src/libelogind/sd-bus/bus-kernel.c b/src/libelogind/sd-bus/bus-kernel.c index 84a8b7766..e0f521b4f 100644 --- a/src/libelogind/sd-bus/bus-kernel.c +++ b/src/libelogind/sd-bus/bus-kernel.c @@ -1,23 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#ifdef HAVE_VALGRIND_MEMCHECK_H +#if HAVE_VALGRIND_MEMCHECK_H #include <valgrind/memcheck.h> #endif @@ -33,7 +18,6 @@ #undef basename #include "alloc-util.h" -#include "bus-bloom.h" #include "bus-internal.h" #include "bus-kernel.h" #include "bus-label.h" @@ -51,1471 +35,14 @@ #include "user-util.h" #include "util.h" -#pragma GCC diagnostic ignored "-Wformat" - -#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t)) - -int bus_kernel_parse_unique_name(const char *s, uint64_t *id) { - int r; - - assert(s); - assert(id); - - if (!startswith(s, ":1.")) - return 0; - - r = safe_atou64(s + 3, id); - if (r < 0) - return r; - - return 1; -} - -static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) { - assert(d); - assert(sz > 0); - - *d = ALIGN8_PTR(*d); - - /* Note that p can be NULL, which encodes a region full of - * zeroes, which is useful to optimize certain padding - * conditions */ - - (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec); - (*d)->type = KDBUS_ITEM_PAYLOAD_VEC; - (*d)->vec.address = PTR_TO_UINT64(p); - (*d)->vec.size = sz; - - *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); -} - -static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t start, size_t sz) { - assert(d); - assert(memfd >= 0); - assert(sz > 0); - - *d = ALIGN8_PTR(*d); - (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd); - (*d)->type = KDBUS_ITEM_PAYLOAD_MEMFD; - (*d)->memfd.fd = memfd; - (*d)->memfd.start = start; - (*d)->memfd.size = sz; - - *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); -} - -static void append_destination(struct kdbus_item **d, const char *s, size_t length) { - assert(d); - assert(s); - - *d = ALIGN8_PTR(*d); - - (*d)->size = offsetof(struct kdbus_item, str) + length + 1; - (*d)->type = KDBUS_ITEM_DST_NAME; - memcpy((*d)->str, s, length + 1); - - *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); -} - -static struct kdbus_bloom_filter *append_bloom(struct kdbus_item **d, size_t length) { - struct kdbus_item *i; - - assert(d); - - i = ALIGN8_PTR(*d); - - i->size = offsetof(struct kdbus_item, bloom_filter) + - offsetof(struct kdbus_bloom_filter, data) + - length; - i->type = KDBUS_ITEM_BLOOM_FILTER; - - *d = (struct kdbus_item *) ((uint8_t*) i + i->size); - - return &i->bloom_filter; -} - -static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) { - assert(d); - assert(fds); - assert(n_fds > 0); - - *d = ALIGN8_PTR(*d); - (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds; - (*d)->type = KDBUS_ITEM_FDS; - memcpy((*d)->fds, fds, sizeof(int) * n_fds); - - *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); -} - -static void add_bloom_arg(void *data, size_t size, unsigned n_hash, unsigned i, const char *t) { - char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")]; - char *e; - - assert(data); - assert(size > 0); - assert(i < 64); - assert(t); - - e = stpcpy(buf, "arg"); - if (i < 10) - *(e++) = '0' + (char) i; - else { - *(e++) = '0' + (char) (i / 10); - *(e++) = '0' + (char) (i % 10); - } - - *e = 0; - bloom_add_pair(data, size, n_hash, buf, t); - - strcpy(e, "-dot-prefix"); - bloom_add_prefixes(data, size, n_hash, buf, t, '.'); - strcpy(e, "-slash-prefix"); - bloom_add_prefixes(data, size, n_hash, buf, t, '/'); -} - -static void add_bloom_arg_has(void *data, size_t size, unsigned n_hash, unsigned i, const char *t) { - char buf[sizeof("arg")-1 + 2 + sizeof("-has")]; - char *e; - - assert(data); - assert(size > 0); - assert(i < 64); - assert(t); - - e = stpcpy(buf, "arg"); - if (i < 10) - *(e++) = '0' + (char) i; - else { - *(e++) = '0' + (char) (i / 10); - *(e++) = '0' + (char) (i % 10); - } - - strcpy(e, "-has"); - bloom_add_pair(data, size, n_hash, buf, t); -} - -static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) { - void *data; - unsigned i; - int r; - - assert(m); - assert(bloom); - - data = bloom->data; - memzero(data, m->bus->bloom_size); - bloom->generation = 0; - - bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "message-type", bus_message_type_to_string(m->header->type)); - - if (m->interface) - bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "interface", m->interface); - if (m->member) - bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "member", m->member); - if (m->path) { - bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path", m->path); - bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path); - bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path, '/'); - } - - r = sd_bus_message_rewind(m, true); - if (r < 0) - return r; - - for (i = 0; i < 64; i++) { - const char *t, *contents; - char type; - - r = sd_bus_message_peek_type(m, &type, &contents); - if (r < 0) - return r; - - if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) { - - /* The bloom filter includes simple strings of any kind */ - r = sd_bus_message_read_basic(m, type, &t); - if (r < 0) - return r; - - add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t); - } - - if (type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")) { - - /* As well as array of simple strings of any kinds */ - r = sd_bus_message_enter_container(m, type, contents); - if (r < 0) - return r; - - while ((r = sd_bus_message_read_basic(m, contents[0], &t)) > 0) - add_bloom_arg_has(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t); - if (r < 0) - return r; - - r = sd_bus_message_exit_container(m); - if (r < 0) - return r; - - } else - /* Stop adding to bloom filter as soon as we - * run into the first argument we cannot add - * to it. */ - break; - } - - return 0; -} - -static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { - struct bus_body_part *part; - struct kdbus_item *d; - const char *destination; - bool well_known = false; - uint64_t dst_id; - size_t sz, dl; - unsigned i; - int r; - - assert(b); - assert(m); - assert(m->sealed); - - /* We put this together only once, if this message is reused - * we reuse the earlier-built version */ - if (m->kdbus) - return 0; - - destination = m->destination ?: m->destination_ptr; - - if (destination) { - r = bus_kernel_parse_unique_name(destination, &dst_id); - if (r < 0) - return r; - if (r == 0) { - well_known = true; - - /* verify_destination_id will usually be 0, which makes the kernel - * driver only look at the provided well-known name. Otherwise, - * the kernel will make sure the provided destination id matches - * the owner of the provided well-known-name, and fail if they - * differ. Currently, this is only needed for bus-proxyd. */ - dst_id = m->verify_destination_id; - } - } else - dst_id = KDBUS_DST_ID_BROADCAST; - - sz = offsetof(struct kdbus_msg, items); - - /* Add in fixed header, fields header and payload */ - sz += (1 + m->n_body_parts) * ALIGN8(offsetof(struct kdbus_item, vec) + - MAX(sizeof(struct kdbus_vec), - sizeof(struct kdbus_memfd))); - - /* Add space for bloom filter */ - sz += ALIGN8(offsetof(struct kdbus_item, bloom_filter) + - offsetof(struct kdbus_bloom_filter, data) + - m->bus->bloom_size); - - /* Add in well-known destination header */ - if (well_known) { - dl = strlen(destination); - sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1); - } - - /* Add space for unix fds */ - if (m->n_fds > 0) - sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds); - - m->kdbus = memalign(8, sz); - if (!m->kdbus) { - r = -ENOMEM; - goto fail; - } - - m->free_kdbus = true; - memzero(m->kdbus, sz); - - m->kdbus->flags = - ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_EXPECT_REPLY) | - ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_NO_AUTO_START : 0) | - ((m->header->type == SD_BUS_MESSAGE_SIGNAL) ? KDBUS_MSG_SIGNAL : 0); - - m->kdbus->dst_id = dst_id; - m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS; - m->kdbus->cookie = m->header->dbus2.cookie; - m->kdbus->priority = m->priority; - - if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - m->kdbus->cookie_reply = m->reply_cookie; - else { - struct timespec now; - - assert_se(clock_gettime(CLOCK_MONOTONIC_COARSE, &now) == 0); - m->kdbus->timeout_ns = now.tv_sec * NSEC_PER_SEC + now.tv_nsec + - m->timeout * NSEC_PER_USEC; - } - - d = m->kdbus->items; - - if (well_known) - append_destination(&d, destination, dl); - - append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m)); - - MESSAGE_FOREACH_PART(part, i, m) { - if (part->is_zero) { - /* If this is padding then simply send a - * vector with a NULL data pointer which the - * kernel will just pass through. This is the - * most efficient way to encode zeroes */ - - append_payload_vec(&d, NULL, part->size); - continue; - } - - if (part->memfd >= 0 && part->sealed && destination) { - /* Try to send a memfd, if the part is - * sealed and this is not a broadcast. Since we can only */ - - append_payload_memfd(&d, part->memfd, part->memfd_offset, part->size); - continue; - } - - /* Otherwise, let's send a vector to the actual data. - * For that, we need to map it first. */ - r = bus_body_part_map(part); - if (r < 0) - goto fail; - - append_payload_vec(&d, part->data, part->size); - } - - if (m->header->type == SD_BUS_MESSAGE_SIGNAL) { - struct kdbus_bloom_filter *bloom; - - bloom = append_bloom(&d, m->bus->bloom_size); - r = bus_message_setup_bloom(m, bloom); - if (r < 0) - goto fail; - } - - if (m->n_fds > 0) - append_fds(&d, m->fds, m->n_fds); - - m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus; - assert(m->kdbus->size <= sz); - - return 0; - -fail: - m->poisoned = true; - return r; -} - -static void unset_memfds(struct sd_bus_message *m) { - struct bus_body_part *part; - unsigned i; - - assert(m); - - /* Make sure the memfds are not freed twice */ - MESSAGE_FOREACH_PART(part, i, m) - if (part->memfd >= 0) - part->memfd = -1; -} - -static void message_set_timestamp(sd_bus *bus, sd_bus_message *m, const struct kdbus_timestamp *ts) { - assert(bus); - assert(m); - - if (!ts) - return; - - if (!(bus->attach_flags & KDBUS_ATTACH_TIMESTAMP)) - return; - - m->realtime = ts->realtime_ns / NSEC_PER_USEC; - m->monotonic = ts->monotonic_ns / NSEC_PER_USEC; - m->seqnum = ts->seqnum; -} - -static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { - sd_bus_message *m = NULL; - struct kdbus_item *d; - unsigned n_fds = 0; - _cleanup_free_ int *fds = NULL; - struct bus_header *header = NULL; - void *footer = NULL; - size_t header_size = 0, footer_size = 0; - size_t n_bytes = 0, idx = 0; - const char *destination = NULL, *seclabel = NULL; - bool last_was_memfd = false; - int r; - - assert(bus); - assert(k); - assert(k->payload_type == KDBUS_PAYLOAD_DBUS); - - KDBUS_ITEM_FOREACH(d, k, items) { - size_t l; - - l = d->size - offsetof(struct kdbus_item, data); - - switch (d->type) { - - case KDBUS_ITEM_PAYLOAD_OFF: - if (!header) { - header = (struct bus_header*)((uint8_t*) k + d->vec.offset); - header_size = d->vec.size; - } - - footer = (uint8_t*) k + d->vec.offset; - footer_size = d->vec.size; - - n_bytes += d->vec.size; - last_was_memfd = false; - break; - - case KDBUS_ITEM_PAYLOAD_MEMFD: - if (!header) /* memfd cannot be first part */ - return -EBADMSG; - - n_bytes += d->memfd.size; - last_was_memfd = true; - break; - - case KDBUS_ITEM_FDS: { - int *f; - unsigned j; - - j = l / sizeof(int); - f = realloc(fds, sizeof(int) * (n_fds + j)); - if (!f) - return -ENOMEM; - - fds = f; - memcpy(fds + n_fds, d->fds, sizeof(int) * j); - n_fds += j; - break; - } - - case KDBUS_ITEM_SECLABEL: - seclabel = d->str; - break; - } - } - - if (last_was_memfd) /* memfd cannot be last part */ - return -EBADMSG; - - if (!header) - return -EBADMSG; - - if (header_size < sizeof(struct bus_header)) - return -EBADMSG; - - /* on kdbus we only speak native endian gvariant, never dbus1 - * marshalling or reverse endian */ - if (header->version != 2 || - header->endian != BUS_NATIVE_ENDIAN) - return -EPROTOTYPE; - - r = bus_message_from_header( - bus, - header, header_size, - footer, footer_size, - n_bytes, - fds, n_fds, - seclabel, 0, &m); - if (r < 0) - return r; - - /* The well-known names list is different from the other - credentials. If we asked for it, but nothing is there, this - means that the list of well-known names is simply empty, not - that we lack any data */ - - m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask; - - KDBUS_ITEM_FOREACH(d, k, items) { - size_t l; - - l = d->size - offsetof(struct kdbus_item, data); - - switch (d->type) { - - case KDBUS_ITEM_PAYLOAD_OFF: { - size_t begin_body; - - begin_body = BUS_MESSAGE_BODY_BEGIN(m); - - if (idx + d->vec.size > begin_body) { - struct bus_body_part *part; - - /* Contains body material */ - - part = message_append_part(m); - if (!part) { - r = -ENOMEM; - goto fail; - } - - /* A -1 offset is NUL padding. */ - part->is_zero = d->vec.offset == ~0ULL; - - if (idx >= begin_body) { - if (!part->is_zero) - part->data = (uint8_t* )k + d->vec.offset; - part->size = d->vec.size; - } else { - if (!part->is_zero) - part->data = (uint8_t*) k + d->vec.offset + (begin_body - idx); - part->size = d->vec.size - (begin_body - idx); - } - - part->sealed = true; - } - - idx += d->vec.size; - break; - } - - case KDBUS_ITEM_PAYLOAD_MEMFD: { - struct bus_body_part *part; - - if (idx < BUS_MESSAGE_BODY_BEGIN(m)) { - r = -EBADMSG; - goto fail; - } - - part = message_append_part(m); - if (!part) { - r = -ENOMEM; - goto fail; - } - - part->memfd = d->memfd.fd; - part->memfd_offset = d->memfd.start; - part->size = d->memfd.size; - part->sealed = true; - - idx += d->memfd.size; - break; - } - - case KDBUS_ITEM_PIDS: - - /* The PID/TID might be missing, when the data - * is faked by a bus proxy and it lacks that - * information about the real client (since - * SO_PEERCRED is used for that). Also kernel - * namespacing might make some of this data - * unavailable when untranslatable. */ - - if (d->pids.pid > 0) { - m->creds.pid = (pid_t) d->pids.pid; - m->creds.mask |= SD_BUS_CREDS_PID & bus->creds_mask; - } - - if (d->pids.tid > 0) { - m->creds.tid = (pid_t) d->pids.tid; - m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask; - } - - if (d->pids.ppid > 0) { - m->creds.ppid = (pid_t) d->pids.ppid; - m->creds.mask |= SD_BUS_CREDS_PPID & bus->creds_mask; - } else if (d->pids.pid == 1) { - m->creds.ppid = 0; - m->creds.mask |= SD_BUS_CREDS_PPID & bus->creds_mask; - } - - break; - - case KDBUS_ITEM_CREDS: - - /* EUID/SUID/FSUID/EGID/SGID/FSGID might be - * missing too (see above). */ - - if ((uid_t) d->creds.uid != UID_INVALID) { - m->creds.uid = (uid_t) d->creds.uid; - m->creds.mask |= SD_BUS_CREDS_UID & bus->creds_mask; - } - - if ((uid_t) d->creds.euid != UID_INVALID) { - m->creds.euid = (uid_t) d->creds.euid; - m->creds.mask |= SD_BUS_CREDS_EUID & bus->creds_mask; - } - - if ((uid_t) d->creds.suid != UID_INVALID) { - m->creds.suid = (uid_t) d->creds.suid; - m->creds.mask |= SD_BUS_CREDS_SUID & bus->creds_mask; - } - - if ((uid_t) d->creds.fsuid != UID_INVALID) { - m->creds.fsuid = (uid_t) d->creds.fsuid; - m->creds.mask |= SD_BUS_CREDS_FSUID & bus->creds_mask; - } - - if ((gid_t) d->creds.gid != GID_INVALID) { - m->creds.gid = (gid_t) d->creds.gid; - m->creds.mask |= SD_BUS_CREDS_GID & bus->creds_mask; - } - - if ((gid_t) d->creds.egid != GID_INVALID) { - m->creds.egid = (gid_t) d->creds.egid; - m->creds.mask |= SD_BUS_CREDS_EGID & bus->creds_mask; - } - - if ((gid_t) d->creds.sgid != GID_INVALID) { - m->creds.sgid = (gid_t) d->creds.sgid; - m->creds.mask |= SD_BUS_CREDS_SGID & bus->creds_mask; - } - - if ((gid_t) d->creds.fsgid != GID_INVALID) { - m->creds.fsgid = (gid_t) d->creds.fsgid; - m->creds.mask |= SD_BUS_CREDS_FSGID & bus->creds_mask; - } - - break; - - case KDBUS_ITEM_TIMESTAMP: - message_set_timestamp(bus, m, &d->timestamp); - break; - - case KDBUS_ITEM_PID_COMM: - m->creds.comm = d->str; - m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask; - break; - - case KDBUS_ITEM_TID_COMM: - m->creds.tid_comm = d->str; - m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask; - break; - - case KDBUS_ITEM_EXE: - m->creds.exe = d->str; - m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask; - break; - - case KDBUS_ITEM_CMDLINE: - m->creds.cmdline = d->str; - m->creds.cmdline_size = l; - m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask; - break; - - case KDBUS_ITEM_CGROUP: - m->creds.cgroup = d->str; - m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask; - - r = bus_get_root_path(bus); - if (r < 0) - goto fail; - - m->creds.cgroup_root = bus->cgroup_root; - break; - - case KDBUS_ITEM_AUDIT: - m->creds.audit_session_id = (uint32_t) d->audit.sessionid; - m->creds.mask |= SD_BUS_CREDS_AUDIT_SESSION_ID & bus->creds_mask; - - m->creds.audit_login_uid = (uid_t) d->audit.loginuid; - m->creds.mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID & bus->creds_mask; - break; - - case KDBUS_ITEM_CAPS: - if (d->caps.last_cap != cap_last_cap() || - d->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(d->caps.last_cap, 32U) * 4 * 4) { - r = -EBADMSG; - goto fail; - } - - m->creds.capability = d->caps.caps; - m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask; - break; - - case KDBUS_ITEM_DST_NAME: - if (!service_name_is_valid(d->str)) { - r = -EBADMSG; - goto fail; - } - - destination = d->str; - break; - - case KDBUS_ITEM_OWNED_NAME: - if (!service_name_is_valid(d->name.name)) { - r = -EBADMSG; - goto fail; - } - - if (bus->creds_mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) { - char **wkn; - size_t n; - - /* We just extend the array here, but - * do not allocate the strings inside - * of it, instead we just point to our - * buffer directly. */ - n = strv_length(m->creds.well_known_names); - wkn = realloc(m->creds.well_known_names, (n + 2) * sizeof(char*)); - if (!wkn) { - r = -ENOMEM; - goto fail; - } - - wkn[n] = d->name.name; - wkn[n+1] = NULL; - m->creds.well_known_names = wkn; - - m->creds.mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES; - } - break; - - case KDBUS_ITEM_CONN_DESCRIPTION: - m->creds.description = d->str; - m->creds.mask |= SD_BUS_CREDS_DESCRIPTION & bus->creds_mask; - break; - - case KDBUS_ITEM_AUXGROUPS: - - if (bus->creds_mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) { - size_t i, n; - gid_t *g; - - n = (d->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t); - g = new(gid_t, n); - if (!g) { - r = -ENOMEM; - goto fail; - } - - for (i = 0; i < n; i++) - g[i] = d->data64[i]; - - m->creds.supplementary_gids = g; - m->creds.n_supplementary_gids = n; - m->creds.mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS; - } - - break; - - case KDBUS_ITEM_FDS: - case KDBUS_ITEM_SECLABEL: - case KDBUS_ITEM_BLOOM_FILTER: - break; - - default: - log_debug("Got unknown field from kernel %llu", d->type); - } - } - - /* If we requested the list of well-known names to be appended - * and the sender had none no item for it will be - * attached. However, this does *not* mean that the kernel - * didn't want to provide this information to us. Hence, let's - * explicitly mark this information as available if it was - * requested. */ - m->creds.mask |= bus->creds_mask & SD_BUS_CREDS_WELL_KNOWN_NAMES; - - r = bus_message_parse_fields(m); - if (r < 0) - goto fail; - - /* Refuse messages if kdbus and dbus1 cookie doesn't match up */ - if ((uint64_t) m->header->dbus2.cookie != k->cookie) { - r = -EBADMSG; - goto fail; - } - - /* Refuse messages where the reply flag doesn't match up */ - if (!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) != !!(k->flags & KDBUS_MSG_EXPECT_REPLY)) { - r = -EBADMSG; - goto fail; - } - - /* Refuse reply messages where the reply cookie doesn't match up */ - if ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) && m->reply_cookie != k->cookie_reply) { - r = -EBADMSG; - goto fail; - } - - /* Refuse messages where the autostart flag doesn't match up */ - if (!(m->header->flags & BUS_MESSAGE_NO_AUTO_START) != !(k->flags & KDBUS_MSG_NO_AUTO_START)) { - r = -EBADMSG; - goto fail; - } - - /* Override information from the user header with data from the kernel */ - if (k->src_id == KDBUS_SRC_ID_KERNEL) - bus_message_set_sender_driver(bus, m); - else { - xsprintf(m->sender_buffer, ":1.%llu", k->src_id); - m->sender = m->creds.unique_name = m->sender_buffer; - } - - if (destination) - m->destination = destination; - else if (k->dst_id == KDBUS_DST_ID_BROADCAST) - m->destination = NULL; - else if (k->dst_id == KDBUS_DST_ID_NAME) - m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */ - else { - xsprintf(m->destination_buffer, ":1.%llu", k->dst_id); - m->destination = m->destination_buffer; - } - - /* We take possession of the kmsg struct now */ - m->kdbus = k; - m->release_kdbus = true; - m->free_fds = true; - fds = NULL; - - bus->rqueue[bus->rqueue_size++] = m; - - return 1; - -fail: - unset_memfds(m); - sd_bus_message_unref(m); - - return r; -} - -int bus_kernel_take_fd(sd_bus *b) { - struct kdbus_bloom_parameter *bloom = NULL; - struct kdbus_item *items, *item; - struct kdbus_cmd_hello *hello; - _cleanup_free_ char *g = NULL; - const char *name; - size_t l = 0, m = 0, sz; - int r; - - assert(b); - - if (b->is_server) - return -EINVAL; - - b->use_memfd = 1; - - if (b->description) { - g = bus_label_escape(b->description); - if (!g) - return -ENOMEM; - - name = g; - } else { - char pr[17] = {}; - - /* If no name is explicitly set, we'll include a hint - * indicating the library implementation, a hint which - * kind of bus this is and the thread name */ - - assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0); - - if (isempty(pr)) { - name = b->is_system ? "sd-system" : - b->is_user ? "sd-user" : "sd"; - } else { - _cleanup_free_ char *e = NULL; - - e = bus_label_escape(pr); - if (!e) - return -ENOMEM; - - g = strappend(b->is_system ? "sd-system-" : - b->is_user ? "sd-user-" : "sd-", - e); - if (!g) - return -ENOMEM; - - name = g; - } - - b->description = bus_label_unescape(name); - if (!b->description) - return -ENOMEM; - } - - m = strlen(name); - - sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items)) + - ALIGN8(offsetof(struct kdbus_item, str) + m + 1); - - if (b->fake_creds_valid) - sz += ALIGN8(offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds)); - - if (b->fake_pids_valid) - sz += ALIGN8(offsetof(struct kdbus_item, pids) + sizeof(struct kdbus_pids)); - - if (b->fake_label) { - l = strlen(b->fake_label); - sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1); - } - - hello = alloca0_align(sz, 8); - hello->size = sz; - hello->flags = b->hello_flags; - hello->attach_flags_send = _KDBUS_ATTACH_ANY; - hello->attach_flags_recv = b->attach_flags; - hello->pool_size = KDBUS_POOL_SIZE; - - item = hello->items; - - item->size = offsetof(struct kdbus_item, str) + m + 1; - item->type = KDBUS_ITEM_CONN_DESCRIPTION; - memcpy(item->str, name, m + 1); - item = KDBUS_ITEM_NEXT(item); - - if (b->fake_creds_valid) { - item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds); - item->type = KDBUS_ITEM_CREDS; - item->creds = b->fake_creds; - - item = KDBUS_ITEM_NEXT(item); - } - - if (b->fake_pids_valid) { - item->size = offsetof(struct kdbus_item, pids) + sizeof(struct kdbus_pids); - item->type = KDBUS_ITEM_PIDS; - item->pids = b->fake_pids; - - item = KDBUS_ITEM_NEXT(item); - } - - if (b->fake_label) { - item->size = offsetof(struct kdbus_item, str) + l + 1; - item->type = KDBUS_ITEM_SECLABEL; - memcpy(item->str, b->fake_label, l+1); - } - - r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello); - if (r < 0) { - if (errno == ENOTTY) - /* If the ioctl is not supported we assume that the - * API version changed in a major incompatible way, - * let's indicate an API incompatibility in this - * case. */ - return -ESOCKTNOSUPPORT; - - return -errno; - } - - if (!b->kdbus_buffer) { - b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0); - if (b->kdbus_buffer == MAP_FAILED) { - b->kdbus_buffer = NULL; - r = -errno; - goto fail; - } - } - - /* The higher 32bit of the bus_flags fields are considered - * 'incompatible flags'. Refuse them all for now. */ - if (hello->bus_flags > 0xFFFFFFFFULL) { - r = -ESOCKTNOSUPPORT; - goto fail; - } - - /* extract bloom parameters from items */ - items = (void*)((uint8_t*)b->kdbus_buffer + hello->offset); - KDBUS_FOREACH(item, items, hello->items_size) { - switch (item->type) { - case KDBUS_ITEM_BLOOM_PARAMETER: - bloom = &item->bloom_parameter; - break; - } - } - - if (!bloom || !bloom_validate_parameters((size_t) bloom->size, (unsigned) bloom->n_hash)) { - r = -EOPNOTSUPP; - goto fail; - } - - b->bloom_size = (size_t) bloom->size; - b->bloom_n_hash = (unsigned) bloom->n_hash; - - if (asprintf(&b->unique_name, ":1.%llu", hello->id) < 0) { - r = -ENOMEM; - goto fail; - } - - b->unique_id = hello->id; - - b->is_kernel = true; - b->bus_client = true; - b->can_fds = !!(hello->flags & KDBUS_HELLO_ACCEPT_FD); - b->message_version = 2; - b->message_endian = BUS_NATIVE_ENDIAN; - - /* the kernel told us the UUID of the underlying bus */ - memcpy(b->server_id.bytes, hello->id128, sizeof(b->server_id.bytes)); - - /* free returned items */ - (void) bus_kernel_cmd_free(b, hello->offset); - return bus_start_running(b); - -fail: - (void) bus_kernel_cmd_free(b, hello->offset); - return r; -} - -int bus_kernel_connect(sd_bus *b) { - assert(b); - assert(b->input_fd < 0); - assert(b->output_fd < 0); - assert(b->kernel); - - if (b->is_server) - return -EINVAL; - - b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (b->input_fd < 0) - return -errno; - - b->output_fd = b->input_fd; - - return bus_kernel_take_fd(b); -} - -int bus_kernel_cmd_free(sd_bus *bus, uint64_t offset) { - struct kdbus_cmd_free cmd = { - .size = sizeof(cmd), - .offset = offset, - }; - int r; - - assert(bus); - assert(bus->is_kernel); - - r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd); - if (r < 0) - return -errno; - - return 0; -} - -static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) { - struct kdbus_item *d; - - assert(bus); - assert(k); - - KDBUS_ITEM_FOREACH(d, k, items) { - if (d->type == KDBUS_ITEM_FDS) - close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int)); - else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD) - safe_close(d->memfd.fd); - } - - bus_kernel_cmd_free(bus, (uint8_t*) k - (uint8_t*) bus->kdbus_buffer); -} - -int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call) { - struct kdbus_cmd_send cmd = { }; - int r; - - assert(bus); - assert(m); - assert(bus->state == BUS_RUNNING); - - /* If we can't deliver, we want room for the error message */ - r = bus_rqueue_make_room(bus); - if (r < 0) - return r; - - r = bus_message_setup_kmsg(bus, m); - if (r < 0) - return r; - - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)m->kdbus; - - /* If this is a synchronous method call, then let's tell the - * kernel, so that it can pass CPU time/scheduling to the - * destination for the time, if it wants to. If we - * synchronously wait for the result anyway, we won't need CPU - * anyway. */ - if (hint_sync_call) { - m->kdbus->flags |= KDBUS_MSG_EXPECT_REPLY; - cmd.flags |= KDBUS_SEND_SYNC_REPLY; - } - - r = ioctl(bus->output_fd, KDBUS_CMD_SEND, &cmd); - if (r < 0) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - sd_bus_message *reply; - - if (errno == EAGAIN || errno == EINTR) - return 0; - else if (errno == ENXIO || errno == ESRCH) { - - /* ENXIO: unique name not known - * ESRCH: well-known name not known */ - - if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) - sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination); - else { - log_debug("Could not deliver message to %s as destination is not known. Ignoring.", m->destination); - return 0; - } - - } else if (errno == EADDRNOTAVAIL) { - - /* EADDRNOTAVAIL: activation is possible, but turned off in request flags */ - - if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) - sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination); - else { - log_debug("Could not deliver message to %s as destination is not activated. Ignoring.", m->destination); - return 0; - } - } else - return -errno; - - r = bus_message_new_synthetic_error( - bus, - BUS_MESSAGE_COOKIE(m), - &error, - &reply); - - if (r < 0) - return r; - - r = bus_seal_synthetic_message(bus, reply); - if (r < 0) - return r; - - bus->rqueue[bus->rqueue_size++] = reply; - - } else if (hint_sync_call) { - struct kdbus_msg *k; - - k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + cmd.reply.offset); - assert(k); - - if (k->payload_type == KDBUS_PAYLOAD_DBUS) { - - r = bus_kernel_make_message(bus, k); - if (r < 0) { - close_kdbus_msg(bus, k); - - /* Anybody can send us invalid messages, let's just drop them. */ - if (r == -EBADMSG || r == -EPROTOTYPE) - log_debug_errno(r, "Ignoring invalid synchronous reply: %m"); - else - return r; - } - } else { - log_debug("Ignoring message with unknown payload type %llu.", k->payload_type); - close_kdbus_msg(bus, k); - } - } - - return 1; -} - -static int push_name_owner_changed( - sd_bus *bus, - const char *name, - const char *old_owner, - const char *new_owner, - const struct kdbus_timestamp *ts) { - - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - int r; - - assert(bus); - - r = sd_bus_message_new_signal( - bus, - &m, - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "NameOwnerChanged"); - if (r < 0) - return r; - - r = sd_bus_message_append(m, "sss", name, old_owner, new_owner); - if (r < 0) - return r; - - bus_message_set_sender_driver(bus, m); - message_set_timestamp(bus, m, ts); - - r = bus_seal_synthetic_message(bus, m); - if (r < 0) - return r; - - bus->rqueue[bus->rqueue_size++] = m; - m = NULL; - - return 1; -} - -static int translate_name_change( - sd_bus *bus, - const struct kdbus_msg *k, - const struct kdbus_item *d, - const struct kdbus_timestamp *ts) { - - char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX]; - - assert(bus); - assert(k); - assert(d); - - if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) - old_owner[0] = 0; - else - sprintf(old_owner, ":1.%llu", d->name_change.old_id.id); - - if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) { - - if (isempty(old_owner)) - return 0; - - new_owner[0] = 0; - } else - sprintf(new_owner, ":1.%llu", d->name_change.new_id.id); - - return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner, ts); -} - -static int translate_id_change( - sd_bus *bus, - const struct kdbus_msg *k, - const struct kdbus_item *d, - const struct kdbus_timestamp *ts) { - - char owner[UNIQUE_NAME_MAX]; - - assert(bus); - assert(k); - assert(d); - - sprintf(owner, ":1.%llu", d->id_change.id); - - return push_name_owner_changed( - bus, owner, - d->type == KDBUS_ITEM_ID_ADD ? NULL : owner, - d->type == KDBUS_ITEM_ID_ADD ? owner : NULL, - ts); -} - -static int translate_reply( - sd_bus *bus, - const struct kdbus_msg *k, - const struct kdbus_item *d, - const struct kdbus_timestamp *ts) { - - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - int r; - - assert(bus); - assert(k); - assert(d); - - r = bus_message_new_synthetic_error( - bus, - k->cookie_reply, - d->type == KDBUS_ITEM_REPLY_TIMEOUT ? - &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") : - &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"), - &m); - if (r < 0) - return r; - - message_set_timestamp(bus, m, ts); - - r = bus_seal_synthetic_message(bus, m); - if (r < 0) - return r; - - bus->rqueue[bus->rqueue_size++] = m; - m = NULL; - - return 1; -} - -static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) { - static int (* const translate[])(sd_bus *bus, const struct kdbus_msg *k, const struct kdbus_item *d, const struct kdbus_timestamp *ts) = { - [KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change, - [KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change, - [KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change, - - [KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change, - [KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change, - - [KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply, - [KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply, - }; - - struct kdbus_item *d, *found = NULL; - struct kdbus_timestamp *ts = NULL; - - assert(bus); - assert(k); - assert(k->payload_type == KDBUS_PAYLOAD_KERNEL); - - KDBUS_ITEM_FOREACH(d, k, items) { - if (d->type == KDBUS_ITEM_TIMESTAMP) - ts = &d->timestamp; - else if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) { - if (found) - return -EBADMSG; - found = d; - } else - log_debug("Got unknown field from kernel %llu", d->type); - } - - if (!found) { - log_debug("Didn't find a kernel message to translate."); - return 0; - } - - return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found, ts); -} - -int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority) { - struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; - struct kdbus_msg *k; - int r; - - assert(bus); - - r = bus_rqueue_make_room(bus); - if (r < 0) - return r; - - if (hint_priority) { - recv.flags |= KDBUS_RECV_USE_PRIORITY; - recv.priority = priority; - } - - r = ioctl(bus->input_fd, KDBUS_CMD_RECV, &recv); - if (recv.return_flags & KDBUS_RECV_RETURN_DROPPED_MSGS) - log_debug("%s: kdbus reports %" PRIu64 " dropped broadcast messages, ignoring.", strna(bus->description), (uint64_t) recv.dropped_msgs); - if (r < 0) { - if (errno == EAGAIN) - return 0; - - return -errno; - } - - k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + recv.msg.offset); - if (k->payload_type == KDBUS_PAYLOAD_DBUS) { - r = bus_kernel_make_message(bus, k); - - /* Anybody can send us invalid messages, let's just drop them. */ - if (r == -EBADMSG || r == -EPROTOTYPE) { - log_debug_errno(r, "Ignoring invalid message: %m"); - r = 0; - } - - if (r <= 0) - close_kdbus_msg(bus, k); - } else if (k->payload_type == KDBUS_PAYLOAD_KERNEL) { - r = bus_kernel_translate_message(bus, k); - close_kdbus_msg(bus, k); - } else { - log_debug("Ignoring message with unknown payload type %llu.", k->payload_type); - r = 0; - close_kdbus_msg(bus, k); - } - - return r < 0 ? r : 1; -} - -int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated) { - struct memfd_cache *c; - int fd; - - assert(address); - assert(mapped); - assert(allocated); - - if (!bus || !bus->is_kernel) - return -EOPNOTSUPP; - - assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); - - if (bus->n_memfd_cache <= 0) { - int r; - - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); - - r = memfd_new(bus->description); - if (r < 0) - return r; - - *address = NULL; - *mapped = 0; - *allocated = 0; - return r; - } - - c = &bus->memfd_cache[--bus->n_memfd_cache]; - - assert(c->fd >= 0); - assert(c->mapped == 0 || c->address); - - *address = c->address; - *mapped = c->mapped; - *allocated = c->allocated; - fd = c->fd; - - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); - - return fd; -} - -static void close_and_munmap(int fd, void *address, size_t size) { +void close_and_munmap(int fd, void *address, size_t size) { if (size > 0) assert_se(munmap(address, PAGE_ALIGN(size)) >= 0); safe_close(fd); } -void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated) { - struct memfd_cache *c; - uint64_t max_mapped = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX); - - assert(fd >= 0); - assert(mapped == 0 || address); - - if (!bus || !bus->is_kernel) { - close_and_munmap(fd, address, mapped); - return; - } - - assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); - - if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) { - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); - - close_and_munmap(fd, address, mapped); - return; - } - - c = &bus->memfd_cache[bus->n_memfd_cache++]; - c->fd = fd; - c->address = address; - - /* If overly long, let's return a bit to the OS */ - if (mapped > max_mapped) { - assert_se(memfd_set_size(fd, max_mapped) >= 0); - assert_se(munmap((uint8_t*) address + max_mapped, PAGE_ALIGN(mapped - max_mapped)) >= 0); - c->mapped = c->allocated = max_mapped; - } else { - c->mapped = mapped; - c->allocated = allocated; - } - - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); -} - -void bus_kernel_flush_memfd(sd_bus *b) { +void bus_flush_memfd(sd_bus *b) { unsigned i; assert(b); @@ -1523,262 +50,5 @@ void bus_kernel_flush_memfd(sd_bus *b) { for (i = 0; i < b->n_memfd_cache; i++) close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].mapped); } - -uint64_t request_name_flags_to_kdbus(uint64_t flags) { - uint64_t f = 0; - - if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT) - f |= KDBUS_NAME_ALLOW_REPLACEMENT; - - if (flags & SD_BUS_NAME_REPLACE_EXISTING) - f |= KDBUS_NAME_REPLACE_EXISTING; - - if (flags & SD_BUS_NAME_QUEUE) - f |= KDBUS_NAME_QUEUE; - - return f; -} - -uint64_t attach_flags_to_kdbus(uint64_t mask) { - uint64_t m = 0; - - if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| - SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) - m |= KDBUS_ATTACH_CREDS; - - if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_PPID)) - m |= KDBUS_ATTACH_PIDS; - - if (mask & SD_BUS_CREDS_COMM) - m |= KDBUS_ATTACH_PID_COMM; - - if (mask & SD_BUS_CREDS_TID_COMM) - m |= KDBUS_ATTACH_TID_COMM; - - if (mask & SD_BUS_CREDS_EXE) - m |= KDBUS_ATTACH_EXE; - - if (mask & SD_BUS_CREDS_CMDLINE) - m |= KDBUS_ATTACH_CMDLINE; - - if (mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) - m |= KDBUS_ATTACH_CGROUP; - - if (mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) - m |= KDBUS_ATTACH_CAPS; - - if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) - m |= KDBUS_ATTACH_SECLABEL; - - if (mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) - m |= KDBUS_ATTACH_AUDIT; - - if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) - m |= KDBUS_ATTACH_NAMES; - - if (mask & SD_BUS_CREDS_DESCRIPTION) - m |= KDBUS_ATTACH_CONN_DESCRIPTION; - - if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) - m |= KDBUS_ATTACH_AUXGROUPS; - - return m; -} - -int bus_kernel_create_bus(const char *name, bool world, char **s) { - struct kdbus_cmd *make; - struct kdbus_item *n; - size_t l; - int fd; - - assert(name); - assert(s); - - fd = open("/sys/fs/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return -errno; - - l = strlen(name); - make = alloca0_align(offsetof(struct kdbus_cmd, items) + - ALIGN8(offsetof(struct kdbus_item, bloom_parameter) + sizeof(struct kdbus_bloom_parameter)) + - ALIGN8(offsetof(struct kdbus_item, data64) + sizeof(uint64_t)) + - ALIGN8(offsetof(struct kdbus_item, str) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1), - 8); - - make->size = offsetof(struct kdbus_cmd, items); - - /* Set the bloom parameters */ - n = make->items; - n->size = offsetof(struct kdbus_item, bloom_parameter) + - sizeof(struct kdbus_bloom_parameter); - n->type = KDBUS_ITEM_BLOOM_PARAMETER; - n->bloom_parameter.size = DEFAULT_BLOOM_SIZE; - n->bloom_parameter.n_hash = DEFAULT_BLOOM_N_HASH; - - assert_cc(DEFAULT_BLOOM_SIZE > 0); - assert_cc(DEFAULT_BLOOM_N_HASH > 0); - - make->size += ALIGN8(n->size); - - /* Provide all metadata via bus-owner queries */ - n = KDBUS_ITEM_NEXT(n); - n->type = KDBUS_ITEM_ATTACH_FLAGS_SEND; - n->size = offsetof(struct kdbus_item, data64) + sizeof(uint64_t); - n->data64[0] = _KDBUS_ATTACH_ANY; - make->size += ALIGN8(n->size); - - /* Set the a good name */ - n = KDBUS_ITEM_NEXT(n); - sprintf(n->str, UID_FMT "-%s", getuid(), name); - n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1; - n->type = KDBUS_ITEM_MAKE_NAME; - make->size += ALIGN8(n->size); - - make->flags = world ? KDBUS_MAKE_ACCESS_WORLD : 0; - - if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) { - safe_close(fd); - - /* Major API change? then the ioctls got shuffled around. */ - if (errno == ENOTTY) - return -ESOCKTNOSUPPORT; - - return -errno; - } - - if (s) { - char *p; - - p = strjoin("/sys/fs/kdbus/", n->str, "/bus"); - if (!p) { - safe_close(fd); - return -ENOMEM; - } - - *s = p; - } - - return fd; -} - -int bus_kernel_open_bus_fd(const char *bus, char **path) { - char *p; - int fd; - size_t len; - - assert(bus); - - len = strlen("/sys/fs/kdbus/") + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + strlen("/bus") + 1; - - if (path) { - p = new(char, len); - if (!p) - return -ENOMEM; - } else - p = newa(char, len); - - sprintf(p, "/sys/fs/kdbus/" UID_FMT "-%s/bus", getuid(), bus); - - fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) { - if (path) - free(p); - - return -errno; - } - - if (path) - *path = p; - - return fd; -} - -int bus_kernel_try_close(sd_bus *bus) { - struct kdbus_cmd byebye = { .size = sizeof(byebye) }; - - assert(bus); - assert(bus->is_kernel); - - if (ioctl(bus->input_fd, KDBUS_CMD_BYEBYE, &byebye) < 0) - return -errno; - - return 0; -} - #if 0 /// UNNEEDED by elogind -int bus_kernel_drop_one(int fd) { - struct kdbus_cmd_recv recv = { - .size = sizeof(recv), - .flags = KDBUS_RECV_DROP, - }; - - assert(fd >= 0); - - if (ioctl(fd, KDBUS_CMD_RECV, &recv) < 0) - return -errno; - - return 0; -} #endif // 0 - -int bus_kernel_realize_attach_flags(sd_bus *bus) { - struct kdbus_cmd *update; - struct kdbus_item *n; - - assert(bus); - assert(bus->is_kernel); - - update = alloca0_align(offsetof(struct kdbus_cmd, items) + - ALIGN8(offsetof(struct kdbus_item, data64) + sizeof(uint64_t)), - 8); - - n = update->items; - n->type = KDBUS_ITEM_ATTACH_FLAGS_RECV; - n->size = offsetof(struct kdbus_item, data64) + sizeof(uint64_t); - n->data64[0] = bus->attach_flags; - - update->size = - offsetof(struct kdbus_cmd, items) + - ALIGN8(n->size); - - if (ioctl(bus->input_fd, KDBUS_CMD_UPDATE, update) < 0) - return -errno; - - return 0; -} - -int bus_kernel_get_bus_name(sd_bus *bus, char **name) { - struct kdbus_cmd_info cmd = { - .size = sizeof(struct kdbus_cmd_info), - }; - struct kdbus_info *info; - struct kdbus_item *item; - char *n = NULL; - int r; - - assert(bus); - assert(name); - assert(bus->is_kernel); - - r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd); - if (r < 0) - return -errno; - - info = (struct kdbus_info*) ((uint8_t*) bus->kdbus_buffer + cmd.offset); - - KDBUS_ITEM_FOREACH(item, info, items) - if (item->type == KDBUS_ITEM_MAKE_NAME) { - r = free_and_strdup(&n, item->str); - break; - } - - bus_kernel_cmd_free(bus, cmd.offset); - - if (r < 0) - return r; - if (!n) - return -EIO; - - *name = n; - return 0; -} diff --git a/src/libelogind/sd-bus/bus-kernel.h b/src/libelogind/sd-bus/bus-kernel.h index eac75253c..9fcbeb0e3 100644 --- a/src/libelogind/sd-bus/bus-kernel.h +++ b/src/libelogind/sd-bus/bus-kernel.h @@ -1,45 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> - #include "sd-bus.h" -#define KDBUS_ITEM_NEXT(item) \ - (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size)) - -#define KDBUS_ITEM_FOREACH(part, head, first) \ - for (part = (head)->first; \ - ((uint8_t *)(part) < (uint8_t *)(head) + (head)->size) && \ - ((uint8_t *) part >= (uint8_t *) head); \ - part = KDBUS_ITEM_NEXT(part)) -#define KDBUS_FOREACH(iter, first, _size) \ - for (iter = (first); \ - ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \ - ((uint8_t *)(iter) >= (uint8_t *)(first)); \ - iter = (void*)(((uint8_t *)iter) + ALIGN8((iter)->size))) - -#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) -#define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE) - #define MEMFD_CACHE_MAX 32 /* When we cache a memfd block for reuse, we will truncate blocks @@ -50,10 +16,6 @@ * sending vectors */ #define MEMFD_MIN_SIZE (512*1024) -/* The size of the per-connection memory pool that we set up and where - * the kernel places our incoming messages */ -#define KDBUS_POOL_SIZE (16*1024*1024) - struct memfd_cache { int fd; void *address; @@ -61,37 +23,9 @@ struct memfd_cache { size_t allocated; }; -int bus_kernel_connect(sd_bus *b); -int bus_kernel_take_fd(sd_bus *b); - -int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call); -int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority); - -int bus_kernel_open_bus_fd(const char *bus, char **path); - -int bus_kernel_create_bus(const char *name, bool world, char **s); #if 0 /// UNNEEDED by elogind -int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **path); #endif // 0 - -int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated); -void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated); - -void bus_kernel_flush_memfd(sd_bus *bus); - -int bus_kernel_parse_unique_name(const char *s, uint64_t *id); - -uint64_t request_name_flags_to_kdbus(uint64_t sd_bus_flags); -uint64_t attach_flags_to_kdbus(uint64_t sd_bus_flags); - -int bus_kernel_try_close(sd_bus *bus); - +void close_and_munmap(int fd, void *address, size_t size); +void bus_flush_memfd(sd_bus *bus); #if 0 /// UNNEEDED by elogind -int bus_kernel_drop_one(int fd); #endif // 0 - -int bus_kernel_realize_attach_flags(sd_bus *bus); - -int bus_kernel_get_bus_name(sd_bus *bus, char **name); - -int bus_kernel_cmd_free(sd_bus *bus, uint64_t offset); diff --git a/src/libelogind/sd-bus/bus-match.c b/src/libelogind/sd-bus/bus-match.c index 3e6930a0d..2ef6e191c 100644 --- a/src/libelogind/sd-bus/bus-match.c +++ b/src/libelogind/sd-bus/bus-match.c @@ -1,22 +1,9 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +//#include <stdio_ext.h> + #include "alloc-util.h" #include "bus-internal.h" #include "bus-match.h" @@ -453,7 +440,7 @@ static int bus_match_add_compare_value( int r; assert(where); - assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); + assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE)); assert(BUS_MATCH_IS_COMPARE(t)); assert(ret); @@ -567,7 +554,7 @@ static int bus_match_find_compare_value( struct bus_match_node *c, *n; assert(where); - assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); + assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE)); assert(BUS_MATCH_IS_COMPARE(t)); assert(ret); @@ -601,7 +588,7 @@ static int bus_match_add_leaf( struct bus_match_node *n; assert(where); - assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); + assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE)); assert(callback); n = new0(struct bus_match_node, 1); @@ -631,7 +618,7 @@ static int bus_match_find_leaf( struct bus_match_node *c; assert(where); - assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); + assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE)); assert(ret); for (c = where->child; c; c = c->next) { @@ -900,12 +887,10 @@ int bus_match_parse( } components[n_components].type = t; - components[n_components].value_str = value; + components[n_components].value_str = TAKE_PTR(value); components[n_components].value_u8 = u; n_components++; - value = NULL; - if (q[quoted] == 0) break; @@ -954,6 +939,8 @@ char *bus_match_to_string(struct bus_match_component *components, unsigned n_com if (!f) return NULL; + __fsetlocking(f, FSETLOCKING_BYCALLER); + for (i = 0; i < n_components; i++) { char buf[32]; diff --git a/src/libelogind/sd-bus/bus-match.h b/src/libelogind/sd-bus/bus-match.h index 9985db133..0891d62e1 100644 --- a/src/libelogind/sd-bus/bus-match.h +++ b/src/libelogind/sd-bus/bus-match.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "sd-bus.h" diff --git a/src/libelogind/sd-bus/bus-message.c b/src/libelogind/sd-bus/bus-message.c index a9853e326..4fb06c2a1 100644 --- a/src/libelogind/sd-bus/bus-message.c +++ b/src/libelogind/sd-bus/bus-message.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <errno.h> @@ -62,22 +47,9 @@ static void message_free_part(sd_bus_message *m, struct bus_body_part *part) { assert(m); assert(part); - if (part->memfd >= 0) { - /* If we can reuse the memfd, try that. For that it - * can't be sealed yet. */ - - if (!part->sealed) { - assert(part->memfd_offset == 0); - assert(part->data == part->mmap_begin); - bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated); - } else { - if (part->mapped > 0) - assert_se(munmap(part->mmap_begin, part->mapped) == 0); - - safe_close(part->memfd); - } - - } else if (part->munmap_this) + if (part->memfd >= 0) + close_and_munmap(part->memfd, part->mmap_begin, part->mapped); + else if (part->munmap_this) munmap(part->mmap_begin, part->mapped); else if (part->free_this) free(part->data); @@ -121,7 +93,7 @@ static void message_reset_containers(sd_bus_message *m) { m->root_container.index = 0; } -static void message_free(sd_bus_message *m) { +static sd_bus_message* message_free(sd_bus_message *m) { assert(m); if (m->free_header) @@ -129,12 +101,6 @@ static void message_free(sd_bus_message *m) { message_reset_parts(m); - if (m->release_kdbus) - bus_kernel_cmd_free(m->bus, (uint8_t *) m->kdbus - (uint8_t *) m->bus->kdbus_buffer); - - if (m->free_kdbus) - free(m->kdbus); - sd_bus_unref(m->bus); if (m->free_fds) { @@ -145,7 +111,6 @@ static void message_free(sd_bus_message *m) { if (m->iovec != m->iovec_fixed) free(m->iovec); - m->destination_ptr = mfree(m->destination_ptr); message_reset_containers(m); free(m->root_container.signature); free(m->root_container.offsets); @@ -153,9 +118,11 @@ static void message_free(sd_bus_message *m) { free(m->root_container.peeked_signature); bus_creds_done(&m->creds); - free(m); + return mfree(m); } +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, message_free); + static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) { void *op, *np; size_t old_size, new_size, start; @@ -431,7 +398,7 @@ int bus_message_from_header( size_t footer_accessible, size_t message_size, int *fds, - unsigned n_fds, + size_t n_fds, const char *label, size_t extra, sd_bus_message **ret) { @@ -532,8 +499,7 @@ int bus_message_from_header( } m->bus = sd_bus_ref(bus); - *ret = m; - m = NULL; + *ret = TAKE_PTR(m); return 0; } @@ -543,11 +509,11 @@ int bus_message_from_malloc( void *buffer, size_t length, int *fds, - unsigned n_fds, + size_t n_fds, const char *label, sd_bus_message **ret) { - sd_bus_message *m; + _cleanup_(message_freep) sd_bus_message *m = NULL; size_t sz; int r; @@ -578,42 +544,46 @@ int bus_message_from_malloc( r = bus_message_parse_fields(m); if (r < 0) - goto fail; + return r; /* We take possession of the memory and fds now */ m->free_header = true; m->free_fds = true; - *ret = m; + *ret = TAKE_PTR(m); return 0; - -fail: - message_free(m); - return r; } -static sd_bus_message *message_new(sd_bus *bus, uint8_t type) { - sd_bus_message *m; +_public_ int sd_bus_message_new( + sd_bus *bus, + sd_bus_message **m, + uint8_t type) { + + sd_bus_message *t; - assert(bus); + assert_return(bus, -ENOTCONN); + assert_return(bus->state != BUS_UNSET, -ENOTCONN); + assert_return(m, -EINVAL); + assert_return(type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL); - m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header)); - if (!m) - return NULL; + t = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header)); + if (!t) + return -ENOMEM; - m->n_ref = 1; - m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message))); - m->header->endian = BUS_NATIVE_ENDIAN; - m->header->type = type; - m->header->version = bus->message_version; - m->allow_fds = bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING); - m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m); - m->bus = sd_bus_ref(bus); + t->n_ref = 1; + t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message))); + t->header->endian = BUS_NATIVE_ENDIAN; + t->header->type = type; + t->header->version = bus->message_version; + t->allow_fds = bus->can_fds || !IN_SET(bus->state, BUS_HELLO, BUS_RUNNING); + t->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(t); + t->bus = sd_bus_ref(bus); if (bus->allow_interactive_authorization) - m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION; + t->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION; - return m; + *m = t; + return 0; } _public_ int sd_bus_message_new_signal( @@ -623,7 +593,7 @@ _public_ int sd_bus_message_new_signal( const char *interface, const char *member) { - sd_bus_message *t; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL; int r; assert_return(bus, -ENOTCONN); @@ -633,28 +603,26 @@ _public_ int sd_bus_message_new_signal( assert_return(member_name_is_valid(member), -EINVAL); assert_return(m, -EINVAL); - t = message_new(bus, SD_BUS_MESSAGE_SIGNAL); - if (!t) + r = sd_bus_message_new(bus, &t, SD_BUS_MESSAGE_SIGNAL); + if (r < 0) return -ENOMEM; + assert(t); + t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path); if (r < 0) - goto fail; + return r; r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface); if (r < 0) - goto fail; + return r; r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member); if (r < 0) - goto fail; + return r; - *m = t; + *m = TAKE_PTR(t); return 0; - -fail: - sd_bus_message_unref(t); - return r; } _public_ int sd_bus_message_new_method_call( @@ -665,7 +633,7 @@ _public_ int sd_bus_message_new_method_call( const char *interface, const char *member) { - sd_bus_message *t; + _cleanup_(message_freep) sd_bus_message *t = NULL; int r; assert_return(bus, -ENOTCONN); @@ -676,35 +644,33 @@ _public_ int sd_bus_message_new_method_call( assert_return(member_name_is_valid(member), -EINVAL); assert_return(m, -EINVAL); - t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL); - if (!t) + r = sd_bus_message_new(bus, &t, SD_BUS_MESSAGE_METHOD_CALL); + if (r < 0) return -ENOMEM; + assert(t); + r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path); if (r < 0) - goto fail; + return r; r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member); if (r < 0) - goto fail; + return r; if (interface) { r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface); if (r < 0) - goto fail; + return r; } if (destination) { r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination); if (r < 0) - goto fail; + return r; } - *m = t; + *m = TAKE_PTR(t); return 0; - -fail: - message_free(t); - return r; } static int message_new_reply( @@ -712,7 +678,8 @@ static int message_new_reply( uint8_t type, sd_bus_message **m) { - sd_bus_message *t; + _cleanup_(message_freep) sd_bus_message *t = NULL; + uint64_t cookie; int r; assert_return(call, -EINVAL); @@ -721,34 +688,33 @@ static int message_new_reply( assert_return(call->bus->state != BUS_UNSET, -ENOTCONN); assert_return(m, -EINVAL); - t = message_new(call->bus, type); - if (!t) + cookie = BUS_MESSAGE_COOKIE(call); + if (cookie == 0) + return -EOPNOTSUPP; + + r = sd_bus_message_new(call->bus, &t, type); + if (r < 0) return -ENOMEM; - t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; - t->reply_cookie = BUS_MESSAGE_COOKIE(call); - if (t->reply_cookie == 0) - return -EOPNOTSUPP; + assert(t); + t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + t->reply_cookie = cookie; r = message_append_reply_cookie(t, t->reply_cookie); if (r < 0) - goto fail; + return r; if (call->sender) { r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination); if (r < 0) - goto fail; + return r; } t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED); t->enforced_reply_signature = call->enforced_reply_signature; - *m = t; + *m = TAKE_PTR(t); return 0; - -fail: - message_free(t); - return r; } _public_ int sd_bus_message_new_method_return( @@ -763,7 +729,7 @@ _public_ int sd_bus_message_new_method_error( sd_bus_message **m, const sd_bus_error *e) { - sd_bus_message *t; + _cleanup_(message_freep) sd_bus_message *t = NULL; int r; assert_return(sd_bus_error_is_set(e), -EINVAL); @@ -775,22 +741,18 @@ _public_ int sd_bus_message_new_method_error( r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name); if (r < 0) - goto fail; + return r; if (e->message) { r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message); if (r < 0) - goto fail; + return r; } t->error._need_free = -1; - *m = t; + *m = TAKE_PTR(t); return 0; - -fail: - message_free(t); - return r; } _public_ int sd_bus_message_new_method_errorf( @@ -870,50 +832,48 @@ int bus_message_new_synthetic_error( const sd_bus_error *e, sd_bus_message **m) { - sd_bus_message *t; + _cleanup_(message_freep) sd_bus_message *t = NULL; int r; assert(bus); assert(sd_bus_error_is_set(e)); assert(m); - t = message_new(bus, SD_BUS_MESSAGE_METHOD_ERROR); - if (!t) + r = sd_bus_message_new(bus, &t, SD_BUS_MESSAGE_METHOD_ERROR); + if (r < 0) return -ENOMEM; + assert(t); + t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; t->reply_cookie = cookie; r = message_append_reply_cookie(t, t->reply_cookie); if (r < 0) - goto fail; + return r; if (bus && bus->unique_name) { r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination); if (r < 0) - goto fail; + return r; } r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name); if (r < 0) - goto fail; + return r; if (e->message) { r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message); if (r < 0) - goto fail; + return r; } t->error._need_free = -1; bus_message_set_sender_driver(bus, t); - *m = t; + *m = TAKE_PTR(t); return 0; - -fail: - message_free(t); - return r; } _public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) { @@ -938,8 +898,7 @@ _public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) { if (m->n_ref > 0) return NULL; - message_free(m); - return NULL; + return message_free(m); } _public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) { @@ -1086,10 +1045,10 @@ _public_ int sd_bus_message_is_signal( if (m->header->type != SD_BUS_MESSAGE_SIGNAL) return 0; - if (interface && (!m->interface || !streq(m->interface, interface))) + if (interface && !streq_ptr(m->interface, interface)) return 0; - if (member && (!m->member || !streq(m->member, member))) + if (member && !streq_ptr(m->member, member)) return 0; return 1; @@ -1105,10 +1064,10 @@ _public_ int sd_bus_message_is_method_call( if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL) return 0; - if (interface && (!m->interface || !streq(m->interface, interface))) + if (interface && !streq_ptr(m->interface, interface)) return 0; - if (member && (!m->member || !streq(m->member, member))) + if (member && !streq_ptr(m->member, member)) return 0; return 1; @@ -1120,7 +1079,7 @@ _public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) return 0; - if (name && (!m->error.name || !streq(m->error.name, name))) + if (name && !streq_ptr(m->error.name, name)) return 0; return 1; @@ -1215,7 +1174,6 @@ static int part_make_space( void **q) { void *n; - int r; assert(m); assert(part); @@ -1224,61 +1182,19 @@ static int part_make_space( if (m->poisoned) return -ENOMEM; - if (!part->data && part->memfd < 0) { - part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated); - part->mmap_begin = part->data; - } - - if (part->memfd >= 0) { - - if (part->allocated == 0 || sz > part->allocated) { - uint64_t new_allocated; - - new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1); - r = memfd_set_size(part->memfd, new_allocated); - if (r < 0) { - m->poisoned = true; - return r; - } - - part->allocated = new_allocated; - } - - if (!part->data || sz > part->mapped) { - size_t psz; - - psz = PAGE_ALIGN(sz > 0 ? sz : 1); - if (part->mapped <= 0) - n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0); - else - n = mremap(part->mmap_begin, part->mapped, psz, MREMAP_MAYMOVE); - - if (n == MAP_FAILED) { - m->poisoned = true; - return -errno; - } + if (part->allocated == 0 || sz > part->allocated) { + size_t new_allocated; - part->mmap_begin = part->data = n; - part->mapped = psz; - part->memfd_offset = 0; + new_allocated = sz > 0 ? 2 * sz : 64; + n = realloc(part->data, new_allocated); + if (!n) { + m->poisoned = true; + return -ENOMEM; } - part->munmap_this = true; - } else { - if (part->allocated == 0 || sz > part->allocated) { - size_t new_allocated; - - new_allocated = sz > 0 ? 2 * sz : 64; - n = realloc(part->data, new_allocated); - if (!n) { - m->poisoned = true; - return -ENOMEM; - } - - part->data = n; - part->allocated = new_allocated; - part->free_this = true; - } + part->data = n; + part->allocated = new_allocated; + part->free_this = true; } if (q) @@ -1364,7 +1280,9 @@ static void *message_extend_body( m->n_body_parts <= 0 || m->body_end->sealed || (padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size) || - (force_inline && m->body_end->size > MEMFD_MIN_SIZE); /* if this must be an inlined extension, let's create a new part if the previous part is large enough to be inlined */ + (force_inline && m->body_end->size > MEMFD_MIN_SIZE); + /* If this must be an inlined extension, let's create a new part if + * the previous part is large enough to be inlined. */ if (add_new_part) { if (padding > 0) { @@ -1411,7 +1329,7 @@ static void *message_extend_body( } } else /* Return something that is not NULL and is aligned */ - p = (uint8_t *) NULL + align; + p = (uint8_t*) align; m->body_size = end_body; message_extend_containers(m, added); @@ -1442,7 +1360,7 @@ static int message_push_fd(sd_bus_message *m, int fd) { if (copy < 0) return -errno; - f = realloc(m->fds, sizeof(int) * (m->n_fds + 1)); + f = reallocarray(m->fds, sizeof(int), m->n_fds + 1); if (!f) { m->poisoned = true; safe_close(copy); @@ -1498,7 +1416,7 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void case SD_BUS_TYPE_STRING: p = strempty(p); - /* Fall through... */ + _fallthrough_; case SD_BUS_TYPE_OBJECT_PATH: if (!p) return -EINVAL; @@ -1558,7 +1476,7 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void * into the empty string */ p = strempty(p); - /* Fall through... */ + _fallthrough_; case SD_BUS_TYPE_OBJECT_PATH: if (!p) @@ -1612,7 +1530,7 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void if (!a) return -ENOMEM; - if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) { + if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) { *(uint32_t*) a = sz - 5; memcpy((uint8_t*) a + 4, p, sz - 4); @@ -1707,7 +1625,7 @@ _public_ int sd_bus_message_append_string_space( _public_ int sd_bus_message_append_string_iovec( sd_bus_message *m, const struct iovec *iov, - unsigned n) { + unsigned n /* should be size_t, but is API now… 😞 */) { size_t size; unsigned i; @@ -2033,7 +1951,7 @@ _public_ int sd_bus_message_open_container( struct bus_container *c, *w; uint32_t *array_size = NULL; - char *signature; + _cleanup_free_ char *signature = NULL; size_t before, begin = 0; bool need_offsets = false; int r; @@ -2072,16 +1990,13 @@ _public_ int sd_bus_message_open_container( r = bus_message_open_dict_entry(m, c, contents, &begin, &need_offsets); else r = -EINVAL; - - if (r < 0) { - free(signature); + if (r < 0) return r; - } /* OK, let's fill it in */ w = m->containers + m->n_containers++; w->enclosing = type; - w->signature = signature; + w->signature = TAKE_PTR(signature); w->index = 0; w->array_size = array_size; w->before = before; @@ -2291,7 +2206,7 @@ _public_ int sd_bus_message_close_container(sd_bus_message *m) { r = bus_message_close_array(m, c); else if (c->enclosing == SD_BUS_TYPE_VARIANT) r = bus_message_close_variant(m, c); - else if (c->enclosing == SD_BUS_TYPE_STRUCT || c->enclosing == SD_BUS_TYPE_DICT_ENTRY) + else if (IN_SET(c->enclosing, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) r = bus_message_close_struct(m, c, true); else assert_not_reached("Unknown container type"); @@ -2631,7 +2546,7 @@ _public_ int sd_bus_message_append_array_iovec( sd_bus_message *m, char type, const struct iovec *iov, - unsigned n) { + unsigned n /* should be size_t, but is API now… 😞 */) { size_t size; unsigned i; @@ -2688,7 +2603,7 @@ _public_ int sd_bus_message_append_array_memfd( if (r < 0) return r; - copy_fd = dup(memfd); + copy_fd = fcntl(memfd, F_DUPFD_CLOEXEC, 3); if (copy_fd < 0) return copy_fd; @@ -2763,7 +2678,7 @@ _public_ int sd_bus_message_append_string_memfd( if (r < 0) return r; - copy_fd = dup(memfd); + copy_fd = fcntl(memfd, FD_CLOEXEC, 3); if (copy_fd < 0) return copy_fd; @@ -2919,13 +2834,13 @@ static int bus_message_close_header(sd_bus_message *m) { return 0; } -int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) { +_public_ int sd_bus_message_seal(sd_bus_message *m, uint64_t cookie, uint64_t timeout_usec) { struct bus_body_part *part; size_t a; unsigned i; int r; - assert(m); + assert_return(m, -EINVAL); if (m->sealed) return -EPERM; @@ -2975,7 +2890,7 @@ int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) { else m->header->dbus1.serial = (uint32_t) cookie; - m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout; + m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout_usec; /* Add padding at the end of the fields part, since we know * the body needs to start at an 8 byte alignment. We made @@ -3233,9 +3148,7 @@ static int container_next_item(sd_bus_message *m, struct bus_container *c, size_ c->offset_index++; - } else if (c->enclosing == 0 || - c->enclosing == SD_BUS_TYPE_STRUCT || - c->enclosing == SD_BUS_TYPE_DICT_ENTRY) { + } else if (IN_SET(c->enclosing, 0, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) { int alignment; size_t n, j; @@ -3279,7 +3192,6 @@ end: return 0; } - static int message_peek_body( sd_bus_message *m, size_t *rindex, @@ -4056,9 +3968,9 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m, const char *contents) { struct bus_container *c, *w; uint32_t *array_size = NULL; - char *signature; + _cleanup_free_ char *signature = NULL; size_t before; - size_t *offsets = NULL; + _cleanup_free_ size_t *offsets = NULL; size_t n_offsets = 0, item_size = 0; int r; @@ -4132,17 +4044,13 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m, r = bus_message_enter_dict_entry(m, c, contents, &item_size, &offsets, &n_offsets); else r = -EINVAL; - - if (r <= 0) { - free(signature); - free(offsets); + if (r <= 0) return r; - } /* OK, let's fill it in */ w = m->containers + m->n_containers++; w->enclosing = type; - w->signature = signature; + w->signature = TAKE_PTR(signature); w->peeked_signature = NULL; w->index = 0; @@ -4159,7 +4067,7 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m, w->array_size = array_size; w->item_size = item_size; - w->offsets = offsets; + w->offsets = TAKE_PTR(offsets); w->n_offsets = n_offsets; w->offset_index = 0; @@ -4283,8 +4191,7 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char return 1; } - if (c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN || - c->signature[c->index] == SD_BUS_TYPE_DICT_ENTRY_BEGIN) { + if (IN_SET(c->signature[c->index], SD_BUS_TYPE_STRUCT_BEGIN, SD_BUS_TYPE_DICT_ENTRY_BEGIN)) { if (contents) { size_t l; @@ -4429,7 +4336,7 @@ static int message_read_ap( /* Ideally, we'd just call ourselves recursively on every * complex type. However, the state of a va_list that is * passed to a function is undefined after that function - * returns. This means we need to docode the va_list linearly + * returns. This means we need to decode the va_list linearly * in a single stackframe. We hence implement our own * home-grown stack in an array. */ @@ -4825,7 +4732,7 @@ _public_ int sd_bus_message_read_array( if (sz == 0) /* Zero length array, let's return some aligned * pointer that is not NULL */ - p = (uint8_t*) NULL + align; + p = (uint8_t*) align; else { r = message_peek_body(m, &m->rindex, align, sz, &p); if (r < 0) @@ -5122,8 +5029,7 @@ static int message_skip_fields( (*signature)++; - } else if (t == SD_BUS_TYPE_STRUCT || - t == SD_BUS_TYPE_DICT_ENTRY) { + } else if (IN_SET(t, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) { r = signature_element_length(*signature, &l); if (r < 0) @@ -5368,14 +5274,13 @@ int bus_message_parse_fields(sd_bus_message *m) { r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender); - if (r >= 0 && m->sender[0] == ':' && m->bus->bus_client && !m->bus->is_kernel) { + if (r >= 0 && m->sender[0] == ':' && m->bus->bus_client) { m->creds.unique_name = (char*) m->sender; m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask; } break; - case BUS_MESSAGE_HEADER_SIGNATURE: { const char *s; char *c; @@ -5397,8 +5302,7 @@ int bus_message_parse_fields(sd_bus_message *m) { if (!c) return -ENOMEM; - free(m->root_container.signature); - m->root_container.signature = c; + free_and_replace(m->root_container.signature, c); break; } @@ -5535,11 +5439,20 @@ _public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *desti return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination); } +_public_ int sd_bus_message_set_sender(sd_bus_message *m, const char *sender) { + assert_return(m, -EINVAL); + assert_return(sender, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(!m->sender, -EEXIST); + + return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender); +} + #if 0 /// UNNEEDED by elogind int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) { size_t total; void *p, *e; - unsigned i; + size_t i; struct bus_body_part *part; assert(m); @@ -5592,7 +5505,7 @@ int bus_message_read_strv_extend(sd_bus_message *m, char ***l) { } _public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) { - char **strv = NULL; + _cleanup_strv_free_ char **strv = NULL; int r; assert_return(m, -EINVAL); @@ -5600,12 +5513,10 @@ _public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) { assert_return(l, -EINVAL); r = bus_message_read_strv_extend(m, &strv); - if (r <= 0) { - strv_free(strv); + if (r <= 0) return r; - } - *l = strv; + *l = TAKE_PTR(strv); return 1; } @@ -5783,9 +5694,7 @@ _public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int assert(r > 0); - if (type == SD_BUS_TYPE_OBJECT_PATH || - type == SD_BUS_TYPE_SIGNATURE || - type == SD_BUS_TYPE_STRING) + if (IN_SET(type, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE, SD_BUS_TYPE_STRING)) r = sd_bus_message_append_basic(m, type, basic.string); else r = sd_bus_message_append_basic(m, type, &basic); @@ -5857,10 +5766,12 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) { case SD_BUS_MESSAGE_METHOD_RETURN: case SD_BUS_MESSAGE_METHOD_ERROR: - n = message_new(bus, (*m)->header->type); - if (!n) + r = sd_bus_message_new(bus, &n, (*m)->header->type); + if (r < 0) return -ENOMEM; + assert(n); + n->reply_cookie = (*m)->reply_cookie; r = message_append_reply_cookie(n, n->reply_cookie); @@ -5903,13 +5814,12 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) { if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)) timeout = BUS_DEFAULT_TIMEOUT; - r = bus_message_seal(n, BUS_MESSAGE_COOKIE(*m), timeout); + r = sd_bus_message_seal(n, BUS_MESSAGE_COOKIE(*m), timeout); if (r < 0) return r; sd_bus_message_unref(*m); - *m = n; - n = NULL; + *m = TAKE_PTR(n); return 0; } diff --git a/src/libelogind/sd-bus/bus-message.h b/src/libelogind/sd-bus/bus-message.h index df501d316..bb6eb786c 100644 --- a/src/libelogind/sd-bus/bus-message.h +++ b/src/libelogind/sd-bus/bus-message.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <byteswap.h> @@ -92,9 +77,7 @@ struct sd_bus_message { bool dont_send:1; bool allow_fds:1; bool free_header:1; - bool free_kdbus:1; bool free_fds:1; - bool release_kdbus:1; bool poisoned:1; /* The first and last bytes of the message */ @@ -128,8 +111,6 @@ struct sd_bus_message { struct iovec iovec_fixed[2]; unsigned n_iovec; - struct kdbus_msg *kdbus; - char *peeked_signature; /* If set replies to this message must carry the signature @@ -139,10 +120,6 @@ struct sd_bus_message { usec_t timeout; - char sender_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1]; - char destination_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1]; - char *destination_ptr; - size_t header_offsets[_BUS_MESSAGE_HEADER_MAX]; unsigned n_header_offsets; }; @@ -191,7 +168,6 @@ static inline bool BUS_MESSAGE_IS_GVARIANT(sd_bus_message *m) { return m->header->version == 2; } -int bus_message_seal(sd_bus_message *m, uint64_t serial, usec_t timeout); #if 0 /// UNNEEDED by elogind int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz); #endif // 0 @@ -205,7 +181,7 @@ int bus_message_from_header( size_t footer_accessible, size_t message_size, int *fds, - unsigned n_fds, + size_t n_fds, const char *label, size_t extra, sd_bus_message **ret); @@ -215,7 +191,7 @@ int bus_message_from_malloc( void *buffer, size_t length, int *fds, - unsigned n_fds, + size_t n_fds, const char *label, sd_bus_message **ret); diff --git a/src/libelogind/sd-bus/bus-objects.c b/src/libelogind/sd-bus/bus-objects.c index 98911d520..9609834fa 100644 --- a/src/libelogind/sd-bus/bus-objects.c +++ b/src/libelogind/sd-bus/bus-objects.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "alloc-util.h" @@ -38,7 +23,7 @@ static int node_vtable_get_userdata( sd_bus_error *error) { sd_bus_slot *s; - void *u; + void *u, *found_u; int r; assert(bus); @@ -50,7 +35,7 @@ static int node_vtable_get_userdata( if (c->find) { bus->current_slot = sd_bus_slot_ref(s); bus->current_userdata = u; - r = c->find(bus, path, c->interface, u, &u, error); + r = c->find(bus, path, c->interface, u, &found_u, error); bus->current_userdata = NULL; bus->current_slot = sd_bus_slot_unref(s); @@ -60,10 +45,11 @@ static int node_vtable_get_userdata( return -sd_bus_error_get_errno(error); if (r == 0) return r; - } + } else + found_u = u; if (userdata) - *userdata = u; + *userdata = found_u; return 1; } @@ -171,9 +157,9 @@ static int add_enumerated_to_set( enum { /* if set, add_subtree() works recursively */ - CHILDREN_RECURSIVE = (1U << 1), + CHILDREN_RECURSIVE = 1 << 0, /* if set, add_subtree() scans object-manager hierarchies recursively */ - CHILDREN_SUBHIERARCHIES = (1U << 0), + CHILDREN_SUBHIERARCHIES = 1 << 1, }; static int add_subtree_to_set( @@ -752,7 +738,7 @@ static int vtable_append_all_properties( return 1; for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) { - if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) + if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY)) continue; if (v->flags & SD_BUS_VTABLE_HIDDEN) @@ -829,6 +815,9 @@ static int property_get_all_callbacks_run( return 0; } + if (!*found_object) + return 0; + if (!found_interface) { r = sd_bus_reply_method_errorf( m, @@ -1364,7 +1353,7 @@ int bus_process_object(sd_bus *bus, sd_bus_message *m) { assert(bus); assert(m); - if (bus->hello_flags & KDBUS_HELLO_MONITOR) + if (bus->is_monitor) return 0; if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL) @@ -1465,14 +1454,12 @@ static struct node *bus_node_allocate(sd_bus *bus, const char *path) { return NULL; n->parent = parent; - n->path = s; - s = NULL; /* do not free */ + n->path = TAKE_PTR(s); r = hashmap_put(bus->nodes, n->path, n); if (r < 0) { free(n->path); - free(n); - return NULL; + return mfree(n); } if (parent) @@ -1494,7 +1481,7 @@ void bus_node_gc(sd_bus *b, struct node *n) { n->object_managers) return; - assert(hashmap_remove(b->nodes, n->path) == n); + assert_se(hashmap_remove(b->nodes, n->path) == n); if (n->parent) LIST_REMOVE(siblings, n->parent->child, n); @@ -1543,6 +1530,7 @@ static int bus_add_object( int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(callback, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -1646,6 +1634,7 @@ static int add_object_vtable_internal( int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(interface_name_is_valid(interface), -EINVAL); assert_return(vtable, -EINVAL); @@ -1751,8 +1740,7 @@ static int add_object_vtable_internal( goto fail; } - /* Fall through */ - + _fallthrough_; case _SD_BUS_VTABLE_PROPERTY: { struct vtable_member *m; @@ -1856,6 +1844,7 @@ _public_ int sd_bus_add_node_enumerator( int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(callback, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -1996,7 +1985,7 @@ static int emit_properties_changed_on_interface( * as changing in the message. */ for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) { - if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) + if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY)) continue; if (v->flags & SD_BUS_VTABLE_HIDDEN) @@ -2067,7 +2056,7 @@ static int emit_properties_changed_on_interface( const sd_bus_vtable *v; for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) { - if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) + if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY)) continue; if (v->flags & SD_BUS_VTABLE_HIDDEN) @@ -2107,6 +2096,7 @@ _public_ int sd_bus_emit_properties_changed_strv( int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(interface_name_is_valid(interface), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -2153,6 +2143,7 @@ _public_ int sd_bus_emit_properties_changed( char **names; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(interface_name_is_valid(interface), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -2337,6 +2328,7 @@ _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) { */ assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -2507,6 +2499,7 @@ _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) { */ assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -2660,6 +2653,7 @@ _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, ch int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -2726,6 +2720,7 @@ _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const c char **interfaces; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -2743,6 +2738,7 @@ _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -2777,6 +2773,7 @@ _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char **interfaces; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -2794,6 +2791,7 @@ _public_ int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const ch int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); diff --git a/src/libelogind/sd-bus/bus-objects.h b/src/libelogind/sd-bus/bus-objects.h index e0b8c534e..e8e1a522c 100644 --- a/src/libelogind/sd-bus/bus-objects.h +++ b/src/libelogind/sd-bus/bus-objects.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "bus-internal.h" diff --git a/src/libelogind/sd-bus/bus-protocol.h b/src/libelogind/sd-bus/bus-protocol.h index 9d180cb28..20d19d402 100644 --- a/src/libelogind/sd-bus/bus-protocol.h +++ b/src/libelogind/sd-bus/bus-protocol.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <endian.h> diff --git a/src/libelogind/sd-bus/bus-signature.c b/src/libelogind/sd-bus/bus-signature.c index 7bc243494..18c91e870 100644 --- a/src/libelogind/sd-bus/bus-signature.c +++ b/src/libelogind/sd-bus/bus-signature.c @@ -1,24 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <util.h> +#include "sd-bus.h" + #include "bus-signature.h" #include "bus-type.h" @@ -106,7 +93,6 @@ static int signature_element_length_internal( return -EINVAL; } - int signature_element_length(const char *s, size_t *l) { return signature_element_length_internal(s, true, 0, 0, l); } diff --git a/src/libelogind/sd-bus/bus-signature.h b/src/libelogind/sd-bus/bus-signature.h index 1e0cd7f58..d4b43bac0 100644 --- a/src/libelogind/sd-bus/bus-signature.h +++ b/src/libelogind/sd-bus/bus-signature.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <stdbool.h> diff --git a/src/libelogind/sd-bus/bus-slot.c b/src/libelogind/sd-bus/bus-slot.c index 33590c31a..fbf37320d 100644 --- a/src/libelogind/sd-bus/bus-slot.c +++ b/src/libelogind/sd-bus/bus-slot.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "sd-bus.h" @@ -80,7 +65,7 @@ void bus_slot_disconnect(sd_bus_slot *slot) { if (slot->reply_callback.cookie != 0) ordered_hashmap_remove(slot->bus->reply_callbacks, &slot->reply_callback.cookie); - if (slot->reply_callback.timeout != 0) + if (slot->reply_callback.timeout_usec != 0) prioq_remove(slot->bus->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx); break; @@ -93,12 +78,17 @@ void bus_slot_disconnect(sd_bus_slot *slot) { case BUS_MATCH_CALLBACK: if (slot->match_added) - bus_remove_match_internal(slot->bus, slot->match_callback.match_string, slot->match_callback.cookie); + (void) bus_remove_match_internal(slot->bus, slot->match_callback.match_string); + + if (slot->match_callback.install_slot) { + bus_slot_disconnect(slot->match_callback.install_slot); + slot->match_callback.install_slot = sd_bus_slot_unref(slot->match_callback.install_slot); + } slot->bus->match_callbacks_modified = true; bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback); - free(slot->match_callback.match_string); + slot->match_callback.match_string = mfree(slot->match_callback.match_string); break; @@ -164,7 +154,6 @@ void bus_slot_disconnect(sd_bus_slot *slot) { key.interface = slot->node_vtable.interface; key.member = v->x.method.member; - x = hashmap_remove(slot->bus->vtable_properties, &key); break; }} @@ -173,7 +162,7 @@ void bus_slot_disconnect(sd_bus_slot *slot) { } } - free(slot->node_vtable.interface); + slot->node_vtable.interface = mfree(slot->node_vtable.interface); if (slot->node_vtable.node) { LIST_REMOVE(vtables, slot->node_vtable.node->vtables, &slot->node_vtable); @@ -211,6 +200,10 @@ _public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) { } bus_slot_disconnect(slot); + + if (slot->destroy_callback) + slot->destroy_callback(slot->userdata); + free(slot->description); return mfree(slot); } @@ -238,6 +231,22 @@ _public_ void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata) { return ret; } +_public_ int sd_bus_slot_set_destroy_callback(sd_bus_slot *slot, sd_bus_destroy_t callback) { + assert_return(slot, -EINVAL); + + slot->destroy_callback = callback; + return 0; +} + +_public_ int sd_bus_slot_get_destroy_callback(sd_bus_slot *slot, sd_bus_destroy_t *callback) { + assert_return(slot, -EINVAL); + + if (callback) + *callback = slot->destroy_callback; + + return !!slot->destroy_callback; +} + _public_ sd_bus_message *sd_bus_slot_get_current_message(sd_bus_slot *slot) { assert_return(slot, NULL); assert_return(slot->type >= 0, NULL); @@ -268,6 +277,37 @@ _public_ void* sd_bus_slot_get_current_userdata(sd_bus_slot *slot) { return slot->bus->current_userdata; } +_public_ int sd_bus_slot_get_floating(sd_bus_slot *slot) { + assert_return(slot, -EINVAL); + + return slot->floating; +} + +_public_ int sd_bus_slot_set_floating(sd_bus_slot *slot, int b) { + assert_return(slot, -EINVAL); + + if (slot->floating == !!b) + return 0; + + if (!slot->bus) /* already disconnected slots can't be reconnected */ + return -ESTALE; + + slot->floating = b; + + /* When a slot is "floating" then the bus references the slot. Otherwise the slot references the bus. Hence, + * when we move from one to the other, let's increase one reference and decrease the other. */ + + if (b) { + sd_bus_slot_ref(slot); + sd_bus_unref(slot->bus); + } else { + sd_bus_ref(slot->bus); + sd_bus_slot_unref(slot); + } + + return 1; +} + _public_ int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description) { assert_return(slot, -EINVAL); @@ -277,8 +317,13 @@ _public_ int sd_bus_slot_set_description(sd_bus_slot *slot, const char *descript _public_ int sd_bus_slot_get_description(sd_bus_slot *slot, const char **description) { assert_return(slot, -EINVAL); assert_return(description, -EINVAL); - assert_return(slot->description, -ENXIO); - *description = slot->description; + if (slot->description) + *description = slot->description; + else if (slot->type == BUS_MATCH_CALLBACK) + *description = slot->match_callback.match_string; + else + return -ENXIO; + return 0; } diff --git a/src/libelogind/sd-bus/bus-slot.h b/src/libelogind/sd-bus/bus-slot.h index 3b8b94dc6..f1e1e23ac 100644 --- a/src/libelogind/sd-bus/bus-slot.h +++ b/src/libelogind/sd-bus/bus-slot.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "sd-bus.h" diff --git a/src/libelogind/sd-bus/bus-socket.c b/src/libelogind/sd-bus/bus-socket.c index 8b25002f0..b147a3843 100644 --- a/src/libelogind/sd-bus/bus-socket.c +++ b/src/libelogind/sd-bus/bus-socket.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <endian.h> @@ -31,9 +16,13 @@ #include "bus-socket.h" #include "fd-util.h" #include "format-util.h" +#include "fs-util.h" #include "hexdecoct.h" +#include "io-util.h" #include "macro.h" #include "missing.h" +#include "path-util.h" +#include "process-util.h" #include "selinux-util.h" #include "signal-util.h" #include "stdio-util.h" @@ -187,7 +176,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) { if (!e) return 0; - if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD) { + if (b->accept_fd) { f = memmem(e + 2, b->rbuffer_size - (e - (char*) b->rbuffer) - 2, "\r\n", 2); if (!f) return 0; @@ -231,8 +220,9 @@ static int bus_socket_auth_verify_client(sd_bus *b) { if (f) b->can_fds = - (f - e == strlen("\r\nAGREE_UNIX_FD")) && - memcmp(e + 2, "AGREE_UNIX_FD", strlen("AGREE_UNIX_FD")) == 0; + (f - e == STRLEN("\r\nAGREE_UNIX_FD")) && + memcmp(e + 2, "AGREE_UNIX_FD", + STRLEN("AGREE_UNIX_FD")) == 0; b->rbuffer_size -= (start - (char*) b->rbuffer); memmove(b->rbuffer, start, b->rbuffer_size); @@ -255,16 +245,13 @@ static bool line_equals(const char *s, size_t m, const char *line) { } static bool line_begins(const char *s, size_t m, const char *word) { - size_t l; - - l = strlen(word); - if (m < l) - return false; + const char *p; - if (memcmp(s, word, l) != 0) + p = memory_startswith(s, m, word); + if (!p) return false; - return m == l || (m > l && s[l] == ' '); + return IN_SET(*p, 0, ' '); } static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) { @@ -343,7 +330,7 @@ static int bus_socket_auth_write(sd_bus *b, const char *t) { assert(t); /* We only make use of the first iovec */ - assert(b->auth_index == 0 || b->auth_index == 1); + assert(IN_SET(b->auth_index, 0, 1)); l = strlen(t); p = malloc(b->auth_iovec[0].iov_len + l); @@ -473,7 +460,7 @@ static int bus_socket_auth_verify_server(sd_bus *b) { r = bus_socket_auth_write_ok(b); } } else if (line_equals(line, l, "NEGOTIATE_UNIX_FD")) { - if (b->auth == _BUS_AUTH_INVALID || !(b->hello_flags & KDBUS_HELLO_ACCEPT_FD)) + if (b->auth == _BUS_AUTH_INVALID || !b->accept_fd) r = bus_socket_auth_write(b, "ERROR\r\n"); else { b->can_fds = true; @@ -546,7 +533,7 @@ static int bus_socket_read_auth(sd_bus *b) { mh.msg_control = &control; mh.msg_controllen = sizeof(control); - k = recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + k = recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); if (k < 0 && errno == ENOTSOCK) { b->prefer_readv = true; k = readv(b->input_fd, &iov, 1); @@ -590,10 +577,9 @@ void bus_socket_setup(sd_bus *b) { assert(b); /* Increase the buffers to 8 MB */ - fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE); - fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE); + (void) fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE); + (void) fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE); - b->is_kernel = false; b->message_version = 1; b->message_endian = 0; } @@ -602,16 +588,24 @@ static void bus_get_peercred(sd_bus *b) { int r; assert(b); + assert(!b->ucred_valid); + assert(!b->label); + assert(b->n_groups == (size_t) -1); /* Get the peer for socketpair() sockets */ b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0; /* Get the SELinux context of the peer */ - if (mac_selinux_use()) { - r = getpeersec(b->input_fd, &b->label); - if (r < 0 && r != -EOPNOTSUPP) - log_debug_errno(r, "Failed to determine peer security context: %m"); - } + r = getpeersec(b->input_fd, &b->label); + if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT)) + log_debug_errno(r, "Failed to determine peer security context: %m"); + + /* Get the list of auxiliary groups of the peer */ + r = getpeergroups(b->input_fd, &b->groups); + if (r >= 0) + 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"); } static int bus_socket_start_auth_client(sd_bus *b) { @@ -640,7 +634,7 @@ static int bus_socket_start_auth_client(sd_bus *b) { if (!b->auth_buffer) return -ENOMEM; - if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD) + if (b->accept_fd) auth_suffix = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n"; else auth_suffix = "\r\nBEGIN\r\n"; @@ -660,15 +654,15 @@ int bus_socket_start_auth(sd_bus *b) { bus_get_peercred(b); - b->state = BUS_AUTHENTICATING; - b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_DEFAULT_TIMEOUT; + bus_set_state(b, BUS_AUTHENTICATING); + b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_AUTH_TIMEOUT; if (sd_is_socket(b->input_fd, AF_UNIX, 0, 0) <= 0) - b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD; + b->accept_fd = false; if (b->output_fd != b->input_fd) if (sd_is_socket(b->output_fd, AF_UNIX, 0, 0) <= 0) - b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD; + b->accept_fd = false; if (b->is_server) return bus_socket_read_auth(b); @@ -676,69 +670,279 @@ int bus_socket_start_auth(sd_bus *b) { return bus_socket_start_auth_client(b); } +static int bus_socket_inotify_setup(sd_bus *b) { + _cleanup_free_ int *new_watches = NULL; + _cleanup_free_ char *absolute = NULL; + size_t n_allocated = 0, n = 0, done = 0, i; + unsigned max_follow = 32; + const char *p; + int wd, r; + + assert(b); + assert(b->watch_bind); + assert(b->sockaddr.sa.sa_family == AF_UNIX); + assert(b->sockaddr.un.sun_path[0] != 0); + + /* Sets up an inotify fd in case watch_bind is enabled: wait until the configured AF_UNIX file system socket + * appears before connecting to it. The implemented is pretty simplistic: we just subscribe to relevant changes + * to all prefix components of the path, and every time we get an event for that we try to reconnect again, + * without actually caring what precisely the event we got told us. If we still can't connect we re-subscribe + * to all relevant changes of anything in the path, so that our watches include any possibly newly created path + * components. */ + + if (b->inotify_fd < 0) { + b->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (b->inotify_fd < 0) + return -errno; + + b->inotify_fd = fd_move_above_stdio(b->inotify_fd); + } + + /* Make sure the path is NUL terminated */ + p = strndupa(b->sockaddr.un.sun_path, sizeof(b->sockaddr.un.sun_path)); + + /* Make sure the path is absolute */ + r = path_make_absolute_cwd(p, &absolute); + if (r < 0) + goto fail; + + /* Watch all parent directories, and don't mind any prefix that doesn't exist yet. For the innermost directory + * that exists we want to know when files are created or moved into it. For all parents of it we just care if + * they are removed or renamed. */ + + if (!GREEDY_REALLOC(new_watches, n_allocated, n + 1)) { + r = -ENOMEM; + goto fail; + } + + /* Start with the top-level directory, which is a bit simpler than the rest, since it can't be a symlink, and + * always exists */ + wd = inotify_add_watch(b->inotify_fd, "/", IN_CREATE|IN_MOVED_TO); + if (wd < 0) { + r = log_debug_errno(errno, "Failed to add inotify watch on /: %m"); + goto fail; + } else + new_watches[n++] = wd; + + for (;;) { + _cleanup_free_ char *component = NULL, *prefix = NULL, *destination = NULL; + size_t n_slashes, n_component; + char *c = NULL; + + n_slashes = strspn(absolute + done, "/"); + n_component = n_slashes + strcspn(absolute + done + n_slashes, "/"); + + if (n_component == 0) /* The end */ + break; + + component = strndup(absolute + done, n_component); + if (!component) { + r = -ENOMEM; + goto fail; + } + + /* A trailing slash? That's a directory, and not a socket then */ + if (path_equal(component, "/")) { + r = -EISDIR; + goto fail; + } + + /* A single dot? Let's eat this up */ + if (path_equal(component, "/.")) { + done += n_component; + continue; + } + + prefix = strndup(absolute, done + n_component); + if (!prefix) { + r = -ENOMEM; + goto fail; + } + + if (!GREEDY_REALLOC(new_watches, n_allocated, n + 1)) { + r = -ENOMEM; + goto fail; + } + + wd = inotify_add_watch(b->inotify_fd, prefix, IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO|IN_DONT_FOLLOW); + log_debug("Added inotify watch for %s on bus %s: %i", prefix, strna(b->description), wd); + + if (wd < 0) { + if (IN_SET(errno, ENOENT, ELOOP)) + break; /* This component doesn't exist yet, or the path contains a cyclic symlink right now */ + + r = log_debug_errno(errno, "Failed to add inotify watch on %s: %m", empty_to_root(prefix)); + goto fail; + } else + new_watches[n++] = wd; + + /* Check if this is possibly a symlink. If so, let's follow it and watch it too. */ + r = readlink_malloc(prefix, &destination); + if (r == -EINVAL) { /* not a symlink */ + done += n_component; + continue; + } + if (r < 0) + goto fail; + + if (isempty(destination)) { /* Empty symlink target? Yuck! */ + r = -EINVAL; + goto fail; + } + + if (max_follow <= 0) { /* Let's make sure we don't follow symlinks forever */ + r = -ELOOP; + goto fail; + } + + if (path_is_absolute(destination)) { + /* For absolute symlinks we build the new path and start anew */ + c = strjoin(destination, absolute + done + n_component); + done = 0; + } else { + _cleanup_free_ char *t = NULL; + + /* For relative symlinks we replace the last component, and try again */ + t = strndup(absolute, done); + if (!t) + return -ENOMEM; + + c = strjoin(t, "/", destination, absolute + done + n_component); + } + if (!c) { + r = -ENOMEM; + goto fail; + } + + free(absolute); + absolute = c; + + max_follow--; + } + + /* And now, let's remove all watches from the previous iteration we don't need anymore */ + for (i = 0; i < b->n_inotify_watches; i++) { + bool found = false; + size_t j; + + for (j = 0; j < n; j++) + if (new_watches[j] == b->inotify_watches[i]) { + found = true; + break; + } + + if (found) + continue; + + (void) inotify_rm_watch(b->inotify_fd, b->inotify_watches[i]); + } + + free_and_replace(b->inotify_watches, new_watches); + b->n_inotify_watches = n; + + return 0; + +fail: + bus_close_inotify_fd(b); + return r; +} + int bus_socket_connect(sd_bus *b) { + bool inotify_done = false; int r; assert(b); - assert(b->input_fd < 0); - assert(b->output_fd < 0); - assert(b->sockaddr.sa.sa_family != AF_UNSPEC); - b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (b->input_fd < 0) - return -errno; + for (;;) { + assert(b->input_fd < 0); + assert(b->output_fd < 0); + assert(b->sockaddr.sa.sa_family != AF_UNSPEC); - b->output_fd = b->input_fd; + b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (b->input_fd < 0) + return -errno; - bus_socket_setup(b); + b->input_fd = fd_move_above_stdio(b->input_fd); - r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); - if (r < 0) { - if (errno == EINPROGRESS) - return 1; + b->output_fd = b->input_fd; + bus_socket_setup(b); - return -errno; + if (connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size) < 0) { + if (errno == EINPROGRESS) { + + /* If we have any inotify watches open, close them now, we don't need them anymore, as + * we have successfully initiated a connection */ + bus_close_inotify_fd(b); + + /* Note that very likely we are already in BUS_OPENING state here, as we enter it when + * we start parsing the address string. The only reason we set the state explicitly + * here, is to undo BUS_WATCH_BIND, in case we did the inotify magic. */ + bus_set_state(b, BUS_OPENING); + return 1; + } + + if (IN_SET(errno, ENOENT, ECONNREFUSED) && /* ENOENT → unix socket doesn't exist at all; ECONNREFUSED → unix socket stale */ + b->watch_bind && + b->sockaddr.sa.sa_family == AF_UNIX && + b->sockaddr.un.sun_path[0] != 0) { + + /* This connection attempt failed, let's release the socket for now, and start with a + * fresh one when reconnecting. */ + bus_close_io_fds(b); + + if (inotify_done) { + /* inotify set up already, don't do it again, just return now, and remember + * that we are waiting for inotify events now. */ + bus_set_state(b, BUS_WATCH_BIND); + return 1; + } + + /* This is a file system socket, and the inotify logic is enabled. Let's create the necessary inotify fd. */ + r = bus_socket_inotify_setup(b); + if (r < 0) + return r; + + /* Let's now try to connect a second time, because in theory there's otherwise a race + * here: the socket might have been created in the time between our first connect() and + * the time we set up the inotify logic. But let's remember that we set up inotify now, + * so that we don't do the connect() more than twice. */ + inotify_done = true; + + } else + return -errno; + } else + break; } + /* Yay, established, we don't need no inotify anymore! */ + bus_close_inotify_fd(b); + return bus_socket_start_auth(b); } int bus_socket_exec(sd_bus *b) { int s[2], r; - pid_t pid; assert(b); assert(b->input_fd < 0); assert(b->output_fd < 0); assert(b->exec_path); + assert(b->busexec_pid == 0); r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s); if (r < 0) return -errno; - pid = fork(); - if (pid < 0) { + r = safe_fork_full("(sd-busexec)", s+1, 1, FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &b->busexec_pid); + if (r < 0) { safe_close_pair(s); - return -errno; + return r; } - if (pid == 0) { + if (r == 0) { /* Child */ - (void) reset_all_signal_handlers(); - (void) reset_signal_mask(); - - close_all_fds(s+1, 1); - - assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO); - assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO); - - if (s[1] != STDIN_FILENO && s[1] != STDOUT_FILENO) - safe_close(s[1]); - - fd_cloexec(STDIN_FILENO, false); - fd_cloexec(STDOUT_FILENO, false); - fd_nonblock(STDIN_FILENO, false); - fd_nonblock(STDOUT_FILENO, false); + if (rearrange_stdio(s[1], s[1], STDERR_FILENO) < 0) + _exit(EXIT_FAILURE); if (b->exec_argv) execvp(b->exec_path, b->exec_argv); @@ -751,7 +955,7 @@ int bus_socket_exec(sd_bus *b) { } safe_close(s[1]); - b->output_fd = b->input_fd = s[0]; + b->output_fd = b->input_fd = fd_move_above_stdio(s[0]); bus_socket_setup(b); @@ -776,7 +980,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { assert(bus); assert(m); assert(idx); - assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)); if (*idx >= BUS_MESSAGE_SIZE(m)) return 0; @@ -800,7 +1004,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { .msg_iovlen = m->n_iovec, }; - if (m->n_fds > 0) { + if (m->n_fds > 0 && *idx == 0) { struct cmsghdr *control; mh.msg_control = control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds)); @@ -831,7 +1035,7 @@ static int bus_socket_read_message_need(sd_bus *bus, size_t *need) { assert(bus); assert(need); - assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)); if (bus->rbuffer_size < sizeof(struct bus_header)) { *need = sizeof(struct bus_header) + 8; @@ -883,7 +1087,7 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) { assert(bus); assert(bus->rbuffer_size >= size); - assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)); r = bus_rqueue_make_room(bus); if (r < 0) @@ -932,7 +1136,7 @@ int bus_socket_read_message(sd_bus *bus) { bool handle_cmsg = false; assert(bus); - assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)); r = bus_socket_read_message_need(bus, &need); if (r < 0) @@ -959,7 +1163,7 @@ int bus_socket_read_message(sd_bus *bus) { mh.msg_control = &control; mh.msg_controllen = sizeof(control); - k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); if (k < 0 && errno == ENOTSOCK) { bus->prefer_readv = true; k = readv(bus->input_fd, &iov, 1); @@ -979,7 +1183,7 @@ int bus_socket_read_message(sd_bus *bus) { CMSG_FOREACH(cmsg, &mh) if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - int n, *f; + int n, *f, i; n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); @@ -992,15 +1196,15 @@ int bus_socket_read_message(sd_bus *bus) { return -EIO; } - f = realloc(bus->fds, sizeof(int) * (bus->n_fds + n)); + f = reallocarray(bus->fds, bus->n_fds + n, sizeof(int)); if (!f) { close_many((int*) CMSG_DATA(cmsg), n); return -ENOMEM; } - memcpy_safe(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); + for (i = 0; i < n; i++) + f[bus->n_fds++] = fd_move_above_stdio(((int*) CMSG_DATA(cmsg))[i]); bus->fds = f; - bus->n_fds += n; } else log_debug("Got unexpected auxiliary data with level=%d and type=%d", cmsg->cmsg_level, cmsg->cmsg_type); @@ -1062,3 +1266,34 @@ int bus_socket_process_authenticating(sd_bus *b) { return bus_socket_read_auth(b); } + +int bus_socket_process_watch_bind(sd_bus *b) { + int r, q; + + assert(b); + assert(b->state == BUS_WATCH_BIND); + assert(b->inotify_fd >= 0); + + r = flush_fd(b->inotify_fd); + if (r <= 0) + return r; + + log_debug("Got inotify event on bus %s.", strna(b->description)); + + /* We flushed events out of the inotify fd. In that case, maybe the socket is valid now? Let's try to connect + * to it again */ + + r = bus_socket_connect(b); + if (r < 0) + return r; + + q = bus_attach_io_events(b); + if (q < 0) + return q; + + q = bus_attach_inotify_event(b); + if (q < 0) + return q; + + return r; +} diff --git a/src/libelogind/sd-bus/bus-socket.h b/src/libelogind/sd-bus/bus-socket.h index 684feead7..d1118ca1d 100644 --- a/src/libelogind/sd-bus/bus-socket.h +++ b/src/libelogind/sd-bus/bus-socket.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "sd-bus.h" @@ -33,5 +18,6 @@ int bus_socket_read_message(sd_bus *bus); int bus_socket_process_opening(sd_bus *b); int bus_socket_process_authenticating(sd_bus *b); +int bus_socket_process_watch_bind(sd_bus *b); bool bus_socket_auth_needs_write(sd_bus *b); diff --git a/src/libelogind/sd-bus/bus-track.c b/src/libelogind/sd-bus/bus-track.c index 4acaf2479..16bf615f5 100644 --- a/src/libelogind/sd-bus/bus-track.c +++ b/src/libelogind/sd-bus/bus-track.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "sd-bus.h" @@ -43,29 +28,18 @@ struct sd_bus_track { bool in_queue:1; /* In bus->track_queue? */ bool modified:1; bool recursive:1; + sd_bus_destroy_t destroy_callback; LIST_FIELDS(sd_bus_track, tracks); }; -#define MATCH_PREFIX \ - "type='signal'," \ - "sender='org.freedesktop.DBus'," \ - "path='/org/freedesktop/DBus'," \ - "interface='org.freedesktop.DBus'," \ - "member='NameOwnerChanged'," \ - "arg0='" - -#define MATCH_SUFFIX \ - "'" - -#define MATCH_FOR_NAME(name) \ - ({ \ - char *_x; \ - size_t _l = strlen(name); \ - _x = alloca(strlen(MATCH_PREFIX)+_l+strlen(MATCH_SUFFIX)+1); \ - strcpy(stpcpy(stpcpy(_x, MATCH_PREFIX), name), MATCH_SUFFIX); \ - _x; \ - }) +#define MATCH_FOR_NAME(name) \ + strjoina("type='signal'," \ + "sender='org.freedesktop.DBus'," \ + "path='/org/freedesktop/DBus'," \ + "interface='org.freedesktop.DBus'," \ + "member='NameOwnerChanged'," \ + "arg0='", name, "'") static struct track_item* track_item_free(struct track_item *i) { @@ -147,6 +121,7 @@ _public_ int sd_bus_track_new( sd_bus_track *t; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(track, -EINVAL); if (!bus->bus_client) @@ -183,27 +158,25 @@ _public_ sd_bus_track* sd_bus_track_ref(sd_bus_track *track) { } _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) { - struct track_item *i; - if (!track) return NULL; assert(track->n_ref > 0); + track->n_ref--; - if (track->n_ref > 1) { - track->n_ref--; + if (track->n_ref > 0) return NULL; - } - - while ((i = hashmap_steal_first(track->names))) - track_item_free(i); if (track->in_list) LIST_REMOVE(tracks, track->bus->tracks, track); bus_track_remove_from_queue(track); - hashmap_free(track->names); - sd_bus_unref(track->bus); + track->names = hashmap_free_with_destructor(track->names, track_item_free); + track->bus = sd_bus_unref(track->bus); + + if (track->destroy_callback) + track->destroy_callback(track->userdata); + return mfree(track); } @@ -263,9 +236,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { bus_track_remove_from_queue(track); /* don't dispatch this while we work in it */ - track->n_adding++; /* make sure we aren't dispatched while we synchronously add this match */ - r = sd_bus_add_match(track->bus, &n->slot, match, on_name_owner_changed, track); - track->n_adding--; + r = sd_bus_add_match_async(track->bus, &n->slot, match, on_name_owner_changed, NULL, track); if (r < 0) { bus_track_add_to_queue(track); return r; @@ -428,8 +399,6 @@ void bus_track_dispatch(sd_bus_track *track) { } void bus_track_close(sd_bus_track *track) { - struct track_item *i; - assert(track); /* Called whenever our bus connected is closed. If so, and our track object is non-empty, dispatch it @@ -447,8 +416,7 @@ void bus_track_close(sd_bus_track *track) { return; /* Let's flush out all names */ - while ((i = hashmap_steal_first(track->names))) - track_item_free(i); + hashmap_clear_with_destructor(track->names, track_item_free); /* Invoke handler */ if (track->handler) @@ -472,6 +440,22 @@ _public_ void *sd_bus_track_set_userdata(sd_bus_track *track, void *userdata) { return ret; } +_public_ int sd_bus_track_set_destroy_callback(sd_bus_track *track, sd_bus_destroy_t callback) { + assert_return(track, -EINVAL); + + track->destroy_callback = callback; + return 0; +} + +_public_ int sd_bus_track_get_destroy_callback(sd_bus_track *track, sd_bus_destroy_t *ret) { + assert_return(track, -EINVAL); + + if (ret) + *ret = track->destroy_callback; + + return !!track->destroy_callback; +} + _public_ int sd_bus_track_set_recursive(sd_bus_track *track, int b) { assert_return(track, -EINVAL); diff --git a/src/libelogind/sd-bus/bus-track.h b/src/libelogind/sd-bus/bus-track.h index 26bd05f5c..f9590265d 100644 --- a/src/libelogind/sd-bus/bus-track.h +++ b/src/libelogind/sd-bus/bus-track.h @@ -1,22 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ void bus_track_dispatch(sd_bus_track *track); diff --git a/src/libelogind/sd-bus/bus-type.c b/src/libelogind/sd-bus/bus-type.c index 27014eed2..d4482e10c 100644 --- a/src/libelogind/sd-bus/bus-type.c +++ b/src/libelogind/sd-bus/bus-type.c @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. +***/ - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. +#include <errno.h> - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ +#include "sd-bus.h" #include "bus-type.h" diff --git a/src/libelogind/sd-bus/bus-type.h b/src/libelogind/sd-bus/bus-type.h index 5c87eb5f0..cdac55c62 100644 --- a/src/libelogind/sd-bus/bus-type.h +++ b/src/libelogind/sd-bus/bus-type.h @@ -1,28 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <stdbool.h> -#include "sd-bus.h" - #include "macro.h" bool bus_type_is_valid(char c) _const_; diff --git a/src/libelogind/sd-bus/kdbus.h b/src/libelogind/sd-bus/kdbus.h deleted file mode 100644 index ecffc6b13..000000000 --- a/src/libelogind/sd-bus/kdbus.h +++ /dev/null @@ -1,980 +0,0 @@ -/* - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef _UAPI_KDBUS_H_ -#define _UAPI_KDBUS_H_ - -#include <linux/ioctl.h> -#include <linux/types.h> - -#define KDBUS_IOCTL_MAGIC 0x95 -#define KDBUS_SRC_ID_KERNEL (0) -#define KDBUS_DST_ID_NAME (0) -#define KDBUS_MATCH_ID_ANY (~0ULL) -#define KDBUS_DST_ID_BROADCAST (~0ULL) -#define KDBUS_FLAG_NEGOTIATE (1ULL << 63) - -/** - * struct kdbus_notify_id_change - name registry change message - * @id: New or former owner of the name - * @flags: flags field from KDBUS_HELLO_* - * - * Sent from kernel to userspace when the owner or activator of - * a well-known name changes. - * - * Attached to: - * KDBUS_ITEM_ID_ADD - * KDBUS_ITEM_ID_REMOVE - */ -struct kdbus_notify_id_change { - __u64 id; - __u64 flags; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_notify_name_change - name registry change message - * @old_id: ID and flags of former owner of a name - * @new_id: ID and flags of new owner of a name - * @name: Well-known name - * - * Sent from kernel to userspace when the owner or activator of - * a well-known name changes. - * - * Attached to: - * KDBUS_ITEM_NAME_ADD - * KDBUS_ITEM_NAME_REMOVE - * KDBUS_ITEM_NAME_CHANGE - */ -struct kdbus_notify_name_change { - struct kdbus_notify_id_change old_id; - struct kdbus_notify_id_change new_id; - char name[0]; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_creds - process credentials - * @uid: User ID - * @euid: Effective UID - * @suid: Saved UID - * @fsuid: Filesystem UID - * @gid: Group ID - * @egid: Effective GID - * @sgid: Saved GID - * @fsgid: Filesystem GID - * - * Attached to: - * KDBUS_ITEM_CREDS - */ -struct kdbus_creds { - __u64 uid; - __u64 euid; - __u64 suid; - __u64 fsuid; - __u64 gid; - __u64 egid; - __u64 sgid; - __u64 fsgid; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_pids - process identifiers - * @pid: Process ID - * @tid: Thread ID - * @ppid: Parent process ID - * - * The PID and TID of a process. - * - * Attached to: - * KDBUS_ITEM_PIDS - */ -struct kdbus_pids { - __u64 pid; - __u64 tid; - __u64 ppid; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_caps - process capabilities - * @last_cap: Highest currently known capability bit - * @caps: Variable number of 32-bit capabilities flags - * - * Contains a variable number of 32-bit capabilities flags. - * - * Attached to: - * KDBUS_ITEM_CAPS - */ -struct kdbus_caps { - __u32 last_cap; - __u32 caps[0]; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_audit - audit information - * @sessionid: The audit session ID - * @loginuid: The audit login uid - * - * Attached to: - * KDBUS_ITEM_AUDIT - */ -struct kdbus_audit { - __u32 sessionid; - __u32 loginuid; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_timestamp - * @seqnum: Global per-domain message sequence number - * @monotonic_ns: Monotonic timestamp, in nanoseconds - * @realtime_ns: Realtime timestamp, in nanoseconds - * - * Attached to: - * KDBUS_ITEM_TIMESTAMP - */ -struct kdbus_timestamp { - __u64 seqnum; - __u64 monotonic_ns; - __u64 realtime_ns; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_vec - I/O vector for kdbus payload items - * @size: The size of the vector - * @address: Memory address of data buffer - * @offset: Offset in the in-message payload memory, - * relative to the message head - * - * Attached to: - * KDBUS_ITEM_PAYLOAD_VEC, KDBUS_ITEM_PAYLOAD_OFF - */ -struct kdbus_vec { - __u64 size; - union { - __u64 address; - __u64 offset; - }; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_bloom_parameter - bus-wide bloom parameters - * @size: Size of the bit field in bytes (m / 8) - * @n_hash: Number of hash functions used (k) - */ -struct kdbus_bloom_parameter { - __u64 size; - __u64 n_hash; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_bloom_filter - bloom filter containing n elements - * @generation: Generation of the element set in the filter - * @data: Bit field, multiple of 8 bytes - */ -struct kdbus_bloom_filter { - __u64 generation; - __u64 data[0]; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_memfd - a kdbus memfd - * @start: The offset into the memfd where the segment starts - * @size: The size of the memfd segment - * @fd: The file descriptor number - * @__pad: Padding to ensure proper alignment and size - * - * Attached to: - * KDBUS_ITEM_PAYLOAD_MEMFD - */ -struct kdbus_memfd { - __u64 start; - __u64 size; - int fd; - __u32 __pad; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_name - a registered well-known name with its flags - * @flags: Flags from KDBUS_NAME_* - * @name: Well-known name - * - * Attached to: - * KDBUS_ITEM_OWNED_NAME - */ -struct kdbus_name { - __u64 flags; - char name[0]; -} __attribute__((__aligned__(8))); - -/** - * enum kdbus_policy_access_type - permissions of a policy record - * @_KDBUS_POLICY_ACCESS_NULL: Uninitialized/invalid - * @KDBUS_POLICY_ACCESS_USER: Grant access to a uid - * @KDBUS_POLICY_ACCESS_GROUP: Grant access to gid - * @KDBUS_POLICY_ACCESS_WORLD: World-accessible - */ -enum kdbus_policy_access_type { - _KDBUS_POLICY_ACCESS_NULL, - KDBUS_POLICY_ACCESS_USER, - KDBUS_POLICY_ACCESS_GROUP, - KDBUS_POLICY_ACCESS_WORLD, -}; - -/** - * enum kdbus_policy_access_flags - mode flags - * @KDBUS_POLICY_OWN: Allow to own a well-known name - * Implies KDBUS_POLICY_TALK and KDBUS_POLICY_SEE - * @KDBUS_POLICY_TALK: Allow communication to a well-known name - * Implies KDBUS_POLICY_SEE - * @KDBUS_POLICY_SEE: Allow to see a well-known name - */ -enum kdbus_policy_type { - KDBUS_POLICY_SEE = 0, - KDBUS_POLICY_TALK, - KDBUS_POLICY_OWN, -}; - -/** - * struct kdbus_policy_access - policy access item - * @type: One of KDBUS_POLICY_ACCESS_* types - * @access: Access to grant - * @id: For KDBUS_POLICY_ACCESS_USER, the uid - * For KDBUS_POLICY_ACCESS_GROUP, the gid - */ -struct kdbus_policy_access { - __u64 type; /* USER, GROUP, WORLD */ - __u64 access; /* OWN, TALK, SEE */ - __u64 id; /* uid, gid, 0 */ -} __attribute__((__aligned__(8))); - -/** - * enum kdbus_attach_flags - flags for metadata attachments - * @KDBUS_ATTACH_TIMESTAMP: Timestamp - * @KDBUS_ATTACH_CREDS: Credentials - * @KDBUS_ATTACH_PIDS: PIDs - * @KDBUS_ATTACH_AUXGROUPS: Auxiliary groups - * @KDBUS_ATTACH_NAMES: Well-known names - * @KDBUS_ATTACH_TID_COMM: The "comm" process identifier of the TID - * @KDBUS_ATTACH_PID_COMM: The "comm" process identifier of the PID - * @KDBUS_ATTACH_EXE: The path of the executable - * @KDBUS_ATTACH_CMDLINE: The process command line - * @KDBUS_ATTACH_CGROUP: The croup membership - * @KDBUS_ATTACH_CAPS: The process capabilities - * @KDBUS_ATTACH_SECLABEL: The security label - * @KDBUS_ATTACH_AUDIT: The audit IDs - * @KDBUS_ATTACH_CONN_DESCRIPTION: The human-readable connection name - * @_KDBUS_ATTACH_ALL: All of the above - * @_KDBUS_ATTACH_ANY: Wildcard match to enable any kind of - * metatdata. - */ -enum kdbus_attach_flags { - KDBUS_ATTACH_TIMESTAMP = 1ULL << 0, - KDBUS_ATTACH_CREDS = 1ULL << 1, - KDBUS_ATTACH_PIDS = 1ULL << 2, - KDBUS_ATTACH_AUXGROUPS = 1ULL << 3, - KDBUS_ATTACH_NAMES = 1ULL << 4, - KDBUS_ATTACH_TID_COMM = 1ULL << 5, - KDBUS_ATTACH_PID_COMM = 1ULL << 6, - KDBUS_ATTACH_EXE = 1ULL << 7, - KDBUS_ATTACH_CMDLINE = 1ULL << 8, - KDBUS_ATTACH_CGROUP = 1ULL << 9, - KDBUS_ATTACH_CAPS = 1ULL << 10, - KDBUS_ATTACH_SECLABEL = 1ULL << 11, - KDBUS_ATTACH_AUDIT = 1ULL << 12, - KDBUS_ATTACH_CONN_DESCRIPTION = 1ULL << 13, - _KDBUS_ATTACH_ALL = (1ULL << 14) - 1, - _KDBUS_ATTACH_ANY = ~0ULL -}; - -/** - * enum kdbus_item_type - item types to chain data in a list - * @_KDBUS_ITEM_NULL: Uninitialized/invalid - * @_KDBUS_ITEM_USER_BASE: Start of user items - * @KDBUS_ITEM_NEGOTIATE: Negotiate supported items - * @KDBUS_ITEM_PAYLOAD_VEC: Vector to data - * @KDBUS_ITEM_PAYLOAD_OFF: Data at returned offset to message head - * @KDBUS_ITEM_PAYLOAD_MEMFD: Data as sealed memfd - * @KDBUS_ITEM_FDS: Attached file descriptors - * @KDBUS_ITEM_CANCEL_FD: FD used to cancel a synchronous - * operation by writing to it from - * userspace - * @KDBUS_ITEM_BLOOM_PARAMETER: Bus-wide bloom parameters, used with - * KDBUS_CMD_BUS_MAKE, carries a - * struct kdbus_bloom_parameter - * @KDBUS_ITEM_BLOOM_FILTER: Bloom filter carried with a message, - * used to match against a bloom mask of a - * connection, carries a struct - * kdbus_bloom_filter - * @KDBUS_ITEM_BLOOM_MASK: Bloom mask used to match against a - * message'sbloom filter - * @KDBUS_ITEM_DST_NAME: Destination's well-known name - * @KDBUS_ITEM_MAKE_NAME: Name of domain, bus, endpoint - * @KDBUS_ITEM_ATTACH_FLAGS_SEND: Attach-flags, used for updating which - * metadata a connection opts in to send - * @KDBUS_ITEM_ATTACH_FLAGS_RECV: Attach-flags, used for updating which - * metadata a connection requests to - * receive for each reeceived message - * @KDBUS_ITEM_ID: Connection ID - * @KDBUS_ITEM_NAME: Well-know name with flags - * @_KDBUS_ITEM_ATTACH_BASE: Start of metadata attach items - * @KDBUS_ITEM_TIMESTAMP: Timestamp - * @KDBUS_ITEM_CREDS: Process credentials - * @KDBUS_ITEM_PIDS: Process identifiers - * @KDBUS_ITEM_AUXGROUPS: Auxiliary process groups - * @KDBUS_ITEM_OWNED_NAME: A name owned by the associated - * connection - * @KDBUS_ITEM_TID_COMM: Thread ID "comm" identifier - * (Don't trust this, see below.) - * @KDBUS_ITEM_PID_COMM: Process ID "comm" identifier - * (Don't trust this, see below.) - * @KDBUS_ITEM_EXE: The path of the executable - * (Don't trust this, see below.) - * @KDBUS_ITEM_CMDLINE: The process command line - * (Don't trust this, see below.) - * @KDBUS_ITEM_CGROUP: The croup membership - * @KDBUS_ITEM_CAPS: The process capabilities - * @KDBUS_ITEM_SECLABEL: The security label - * @KDBUS_ITEM_AUDIT: The audit IDs - * @KDBUS_ITEM_CONN_DESCRIPTION: The connection's human-readable name - * (debugging) - * @_KDBUS_ITEM_POLICY_BASE: Start of policy items - * @KDBUS_ITEM_POLICY_ACCESS: Policy access block - * @_KDBUS_ITEM_KERNEL_BASE: Start of kernel-generated message items - * @KDBUS_ITEM_NAME_ADD: Notification in kdbus_notify_name_change - * @KDBUS_ITEM_NAME_REMOVE: Notification in kdbus_notify_name_change - * @KDBUS_ITEM_NAME_CHANGE: Notification in kdbus_notify_name_change - * @KDBUS_ITEM_ID_ADD: Notification in kdbus_notify_id_change - * @KDBUS_ITEM_ID_REMOVE: Notification in kdbus_notify_id_change - * @KDBUS_ITEM_REPLY_TIMEOUT: Timeout has been reached - * @KDBUS_ITEM_REPLY_DEAD: Destination died - * - * N.B: The process and thread COMM fields, as well as the CMDLINE and - * EXE fields may be altered by unprivileged processes und should - * hence *not* used for security decisions. Peers should make use of - * these items only for informational purposes, such as generating log - * records. - */ -enum kdbus_item_type { - _KDBUS_ITEM_NULL, - _KDBUS_ITEM_USER_BASE, - KDBUS_ITEM_NEGOTIATE = _KDBUS_ITEM_USER_BASE, - KDBUS_ITEM_PAYLOAD_VEC, - KDBUS_ITEM_PAYLOAD_OFF, - KDBUS_ITEM_PAYLOAD_MEMFD, - KDBUS_ITEM_FDS, - KDBUS_ITEM_CANCEL_FD, - KDBUS_ITEM_BLOOM_PARAMETER, - KDBUS_ITEM_BLOOM_FILTER, - KDBUS_ITEM_BLOOM_MASK, - KDBUS_ITEM_DST_NAME, - KDBUS_ITEM_MAKE_NAME, - KDBUS_ITEM_ATTACH_FLAGS_SEND, - KDBUS_ITEM_ATTACH_FLAGS_RECV, - KDBUS_ITEM_ID, - KDBUS_ITEM_NAME, - KDBUS_ITEM_DST_ID, - - /* keep these item types in sync with KDBUS_ATTACH_* flags */ - _KDBUS_ITEM_ATTACH_BASE = 0x1000, - KDBUS_ITEM_TIMESTAMP = _KDBUS_ITEM_ATTACH_BASE, - KDBUS_ITEM_CREDS, - KDBUS_ITEM_PIDS, - KDBUS_ITEM_AUXGROUPS, - KDBUS_ITEM_OWNED_NAME, - KDBUS_ITEM_TID_COMM, - KDBUS_ITEM_PID_COMM, - KDBUS_ITEM_EXE, - KDBUS_ITEM_CMDLINE, - KDBUS_ITEM_CGROUP, - KDBUS_ITEM_CAPS, - KDBUS_ITEM_SECLABEL, - KDBUS_ITEM_AUDIT, - KDBUS_ITEM_CONN_DESCRIPTION, - - _KDBUS_ITEM_POLICY_BASE = 0x2000, - KDBUS_ITEM_POLICY_ACCESS = _KDBUS_ITEM_POLICY_BASE, - - _KDBUS_ITEM_KERNEL_BASE = 0x8000, - KDBUS_ITEM_NAME_ADD = _KDBUS_ITEM_KERNEL_BASE, - KDBUS_ITEM_NAME_REMOVE, - KDBUS_ITEM_NAME_CHANGE, - KDBUS_ITEM_ID_ADD, - KDBUS_ITEM_ID_REMOVE, - KDBUS_ITEM_REPLY_TIMEOUT, - KDBUS_ITEM_REPLY_DEAD, -}; - -/** - * struct kdbus_item - chain of data blocks - * @size: Overall data record size - * @type: Kdbus_item type of data - * @data: Generic bytes - * @data32: Generic 32 bit array - * @data64: Generic 64 bit array - * @str: Generic string - * @id: Connection ID - * @vec: KDBUS_ITEM_PAYLOAD_VEC - * @creds: KDBUS_ITEM_CREDS - * @audit: KDBUS_ITEM_AUDIT - * @timestamp: KDBUS_ITEM_TIMESTAMP - * @name: KDBUS_ITEM_NAME - * @bloom_parameter: KDBUS_ITEM_BLOOM_PARAMETER - * @bloom_filter: KDBUS_ITEM_BLOOM_FILTER - * @memfd: KDBUS_ITEM_PAYLOAD_MEMFD - * @name_change: KDBUS_ITEM_NAME_ADD - * KDBUS_ITEM_NAME_REMOVE - * KDBUS_ITEM_NAME_CHANGE - * @id_change: KDBUS_ITEM_ID_ADD - * KDBUS_ITEM_ID_REMOVE - * @policy: KDBUS_ITEM_POLICY_ACCESS - */ -struct kdbus_item { - __u64 size; - __u64 type; - union { - __u8 data[0]; - __u32 data32[0]; - __u64 data64[0]; - char str[0]; - - __u64 id; - struct kdbus_vec vec; - struct kdbus_creds creds; - struct kdbus_pids pids; - struct kdbus_audit audit; - struct kdbus_caps caps; - struct kdbus_timestamp timestamp; - struct kdbus_name name; - struct kdbus_bloom_parameter bloom_parameter; - struct kdbus_bloom_filter bloom_filter; - struct kdbus_memfd memfd; - int fds[0]; - struct kdbus_notify_name_change name_change; - struct kdbus_notify_id_change id_change; - struct kdbus_policy_access policy_access; - }; -} __attribute__((__aligned__(8))); - -/** - * enum kdbus_msg_flags - type of message - * @KDBUS_MSG_EXPECT_REPLY: Expect a reply message, used for - * method calls. The userspace-supplied - * cookie identifies the message and the - * respective reply carries the cookie - * in cookie_reply - * @KDBUS_MSG_NO_AUTO_START: Do not start a service if the addressed - * name is not currently active. This flag is - * not looked at by the kernel but only - * serves as hint for userspace implementations. - * @KDBUS_MSG_SIGNAL: Treat this message as signal - */ -enum kdbus_msg_flags { - KDBUS_MSG_EXPECT_REPLY = 1ULL << 0, - KDBUS_MSG_NO_AUTO_START = 1ULL << 1, - KDBUS_MSG_SIGNAL = 1ULL << 2, -}; - -/** - * enum kdbus_payload_type - type of payload carried by message - * @KDBUS_PAYLOAD_KERNEL: Kernel-generated simple message - * @KDBUS_PAYLOAD_DBUS: D-Bus marshalling "DBusDBus" - * - * Any payload-type is accepted. Common types will get added here once - * established. - */ -enum kdbus_payload_type { - KDBUS_PAYLOAD_KERNEL, - KDBUS_PAYLOAD_DBUS = 0x4442757344427573ULL, -}; - -/** - * struct kdbus_msg - the representation of a kdbus message - * @size: Total size of the message - * @flags: Message flags (KDBUS_MSG_*), userspace → kernel - * @priority: Message queue priority value - * @dst_id: 64-bit ID of the destination connection - * @src_id: 64-bit ID of the source connection - * @payload_type: Payload type (KDBUS_PAYLOAD_*) - * @cookie: Userspace-supplied cookie, for the connection - * to identify its messages - * @timeout_ns: The time to wait for a message reply from the peer. - * If there is no reply, and the send command is - * executed asynchronously, a kernel-generated message - * with an attached KDBUS_ITEM_REPLY_TIMEOUT item - * is sent to @src_id. For synchronously executed send - * command, the value denotes the maximum time the call - * blocks to wait for a reply. The timeout is expected in - * nanoseconds and as absolute CLOCK_MONOTONIC value. - * @cookie_reply: A reply to the requesting message with the same - * cookie. The requesting connection can match its - * request and the reply with this value - * @items: A list of kdbus_items containing the message payload - */ -struct kdbus_msg { - __u64 size; - __u64 flags; - __s64 priority; - __u64 dst_id; - __u64 src_id; - __u64 payload_type; - __u64 cookie; - union { - __u64 timeout_ns; - __u64 cookie_reply; - }; - struct kdbus_item items[0]; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_msg_info - returned message container - * @offset: Offset of kdbus_msg slice in pool - * @msg_size: Copy of the kdbus_msg.size field - * @return_flags: Command return flags, kernel → userspace - */ -struct kdbus_msg_info { - __u64 offset; - __u64 msg_size; - __u64 return_flags; -} __attribute__((__aligned__(8))); - -/** - * enum kdbus_send_flags - flags for sending messages - * @KDBUS_SEND_SYNC_REPLY: Wait for destination connection to - * reply to this message. The - * KDBUS_CMD_SEND ioctl() will block - * until the reply is received, and - * reply in struct kdbus_cmd_send will - * yield the offset in the sender's pool - * where the reply can be found. - * This flag is only valid if - * @KDBUS_MSG_EXPECT_REPLY is set as well. - */ -enum kdbus_send_flags { - KDBUS_SEND_SYNC_REPLY = 1ULL << 0, -}; - -/** - * struct kdbus_cmd_send - send message - * @size: Overall size of this structure - * @flags: Flags to change send behavior (KDBUS_SEND_*) - * @return_flags: Command return flags, kernel → userspace - * @msg_address: Storage address of the kdbus_msg to send - * @reply: Storage for message reply if KDBUS_SEND_SYNC_REPLY - * was given - * @items: Additional items for this command - */ -struct kdbus_cmd_send { - __u64 size; - __u64 flags; - __u64 return_flags; - __u64 msg_address; - struct kdbus_msg_info reply; - struct kdbus_item items[0]; -} __attribute__((__aligned__(8))); - -/** - * enum kdbus_recv_flags - flags for de-queuing messages - * @KDBUS_RECV_PEEK: Return the next queued message without - * actually de-queuing it, and without installing - * any file descriptors or other resources. It is - * usually used to determine the activating - * connection of a bus name. - * @KDBUS_RECV_DROP: Drop and free the next queued message and all - * its resources without actually receiving it. - * @KDBUS_RECV_USE_PRIORITY: Only de-queue messages with the specified or - * higher priority (lowest values); if not set, - * the priority value is ignored. - */ -enum kdbus_recv_flags { - KDBUS_RECV_PEEK = 1ULL << 0, - KDBUS_RECV_DROP = 1ULL << 1, - KDBUS_RECV_USE_PRIORITY = 1ULL << 2, -}; - -/** - * enum kdbus_recv_return_flags - return flags for message receive commands - * @KDBUS_RECV_RETURN_INCOMPLETE_FDS: One or more file descriptors could not - * be installed. These descriptors in - * KDBUS_ITEM_FDS will carry the value -1. - * @KDBUS_RECV_RETURN_DROPPED_MSGS: There have been dropped messages since - * the last time a message was received. - * The 'dropped_msgs' counter contains the - * number of messages dropped pool - * overflows or other missed broadcasts. - */ -enum kdbus_recv_return_flags { - KDBUS_RECV_RETURN_INCOMPLETE_FDS = 1ULL << 0, - KDBUS_RECV_RETURN_DROPPED_MSGS = 1ULL << 1, -}; - -/** - * struct kdbus_cmd_recv - struct to de-queue a buffered message - * @size: Overall size of this object - * @flags: KDBUS_RECV_* flags, userspace → kernel - * @return_flags: Command return flags, kernel → userspace - * @priority: Minimum priority of the messages to de-queue. Lowest - * values have the highest priority. - * @dropped_msgs: In case there were any dropped messages since the last - * time a message was received, this will be set to the - * number of lost messages and - * KDBUS_RECV_RETURN_DROPPED_MSGS will be set in - * 'return_flags'. This can only happen if the ioctl - * returns 0 or EAGAIN. - * @msg: Return storage for received message. - * @items: Additional items for this command. - * - * This struct is used with the KDBUS_CMD_RECV ioctl. - */ -struct kdbus_cmd_recv { - __u64 size; - __u64 flags; - __u64 return_flags; - __s64 priority; - __u64 dropped_msgs; - struct kdbus_msg_info msg; - struct kdbus_item items[0]; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_cmd_free - struct to free a slice of memory in the pool - * @size: Overall size of this structure - * @flags: Flags for the free command, userspace → kernel - * @return_flags: Command return flags, kernel → userspace - * @offset: The offset of the memory slice, as returned by other - * ioctls - * @items: Additional items to modify the behavior - * - * This struct is used with the KDBUS_CMD_FREE ioctl. - */ -struct kdbus_cmd_free { - __u64 size; - __u64 flags; - __u64 return_flags; - __u64 offset; - struct kdbus_item items[0]; -} __attribute__((__aligned__(8))); - -/** - * enum kdbus_hello_flags - flags for struct kdbus_cmd_hello - * @KDBUS_HELLO_ACCEPT_FD: The connection allows the reception of - * any passed file descriptors - * @KDBUS_HELLO_ACTIVATOR: Special-purpose connection which registers - * a well-know name for a process to be started - * when traffic arrives - * @KDBUS_HELLO_POLICY_HOLDER: Special-purpose connection which registers - * policy entries for a name. The provided name - * is not activated and not registered with the - * name database, it only allows unprivileged - * connections to acquire a name, talk or discover - * a service - * @KDBUS_HELLO_MONITOR: Special-purpose connection to monitor - * bus traffic - */ -enum kdbus_hello_flags { - KDBUS_HELLO_ACCEPT_FD = 1ULL << 0, - KDBUS_HELLO_ACTIVATOR = 1ULL << 1, - KDBUS_HELLO_POLICY_HOLDER = 1ULL << 2, - KDBUS_HELLO_MONITOR = 1ULL << 3, -}; - -/** - * struct kdbus_cmd_hello - struct to say hello to kdbus - * @size: The total size of the structure - * @flags: Connection flags (KDBUS_HELLO_*), userspace → kernel - * @return_flags: Command return flags, kernel → userspace - * @attach_flags_send: Mask of metadata to attach to each message sent - * off by this connection (KDBUS_ATTACH_*) - * @attach_flags_recv: Mask of metadata to attach to each message receieved - * by the new connection (KDBUS_ATTACH_*) - * @bus_flags: The flags field copied verbatim from the original - * KDBUS_CMD_BUS_MAKE ioctl. It's intended to be useful - * to do negotiation of features of the payload that is - * transferred (kernel → userspace) - * @id: The ID of this connection (kernel → userspace) - * @pool_size: Size of the connection's buffer where the received - * messages are placed - * @offset: Pool offset where items are returned to report - * additional information about the bus and the newly - * created connection. - * @items_size: Size of buffer returned in the pool slice at @offset. - * @id128: Unique 128-bit ID of the bus (kernel → userspace) - * @items: A list of items - * - * This struct is used with the KDBUS_CMD_HELLO ioctl. - */ -struct kdbus_cmd_hello { - __u64 size; - __u64 flags; - __u64 return_flags; - __u64 attach_flags_send; - __u64 attach_flags_recv; - __u64 bus_flags; - __u64 id; - __u64 pool_size; - __u64 offset; - __u64 items_size; - __u8 id128[16]; - struct kdbus_item items[0]; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_info - connection information - * @size: total size of the struct - * @id: 64bit object ID - * @flags: object creation flags - * @items: list of items - * - * Note that the user is responsible for freeing the allocated memory with - * the KDBUS_CMD_FREE ioctl. - */ -struct kdbus_info { - __u64 size; - __u64 id; - __u64 flags; - struct kdbus_item items[0]; -} __attribute__((__aligned__(8))); - -/** - * enum kdbus_list_flags - what to include into the returned list - * @KDBUS_LIST_UNIQUE: active connections - * @KDBUS_LIST_ACTIVATORS: activator connections - * @KDBUS_LIST_NAMES: known well-known names - * @KDBUS_LIST_QUEUED: queued-up names - */ -enum kdbus_list_flags { - KDBUS_LIST_UNIQUE = 1ULL << 0, - KDBUS_LIST_NAMES = 1ULL << 1, - KDBUS_LIST_ACTIVATORS = 1ULL << 2, - KDBUS_LIST_QUEUED = 1ULL << 3, -}; - -/** - * struct kdbus_cmd_list - list connections - * @size: overall size of this object - * @flags: flags for the query (KDBUS_LIST_*), userspace → kernel - * @return_flags: command return flags, kernel → userspace - * @offset: Offset in the caller's pool buffer where an array of - * kdbus_info objects is stored. - * The user must use KDBUS_CMD_FREE to free the - * allocated memory. - * @list_size: size of returned list in bytes - * @items: Items for the command. Reserved for future use. - * - * This structure is used with the KDBUS_CMD_LIST ioctl. - */ -struct kdbus_cmd_list { - __u64 size; - __u64 flags; - __u64 return_flags; - __u64 offset; - __u64 list_size; - struct kdbus_item items[0]; -} __attribute__((__aligned__(8))); - -/** - * struct kdbus_cmd_info - struct used for KDBUS_CMD_CONN_INFO ioctl - * @size: The total size of the struct - * @flags: Flags for this ioctl, userspace → kernel - * @return_flags: Command return flags, kernel → userspace - * @id: The 64-bit ID of the connection. If set to zero, passing - * @name is required. kdbus will look up the name to - * determine the ID in this case. - * @attach_flags: Set of attach flags to specify the set of information - * to receive, userspace → kernel - * @offset: Returned offset in the caller's pool buffer where the - * kdbus_info struct result is stored. The user must - * use KDBUS_CMD_FREE to free the allocated memory. - * @info_size: Output buffer to report size of data at @offset. - * @items: The optional item list, containing the - * well-known name to look up as a KDBUS_ITEM_NAME. - * Only needed in case @id is zero. - * - * On success, the KDBUS_CMD_CONN_INFO ioctl will return 0 and @offset will - * tell the user the offset in the connection pool buffer at which to find the - * result in a struct kdbus_info. - */ -struct kdbus_cmd_info { - __u64 size; - __u64 flags; - __u64 return_flags; - __u64 id; - __u64 attach_flags; - __u64 offset; - __u64 info_size; - struct kdbus_item items[0]; -} __attribute__((__aligned__(8))); - -/** - * enum kdbus_cmd_match_flags - flags to control the KDBUS_CMD_MATCH_ADD ioctl - * @KDBUS_MATCH_REPLACE: If entries with the supplied cookie already - * exists, remove them before installing the new - * matches. - */ -enum kdbus_cmd_match_flags { - KDBUS_MATCH_REPLACE = 1ULL << 0, -}; - -/** - * struct kdbus_cmd_match - struct to add or remove matches - * @size: The total size of the struct - * @flags: Flags for match command (KDBUS_MATCH_*), - * userspace → kernel - * @return_flags: Command return flags, kernel → userspace - * @cookie: Userspace supplied cookie. When removing, the cookie - * identifies the match to remove - * @items: A list of items for additional information - * - * This structure is used with the KDBUS_CMD_MATCH_ADD and - * KDBUS_CMD_MATCH_REMOVE ioctl. - */ -struct kdbus_cmd_match { - __u64 size; - __u64 flags; - __u64 return_flags; - __u64 cookie; - struct kdbus_item items[0]; -} __attribute__((__aligned__(8))); - -/** - * enum kdbus_make_flags - Flags for KDBUS_CMD_{BUS,ENDPOINT}_MAKE - * @KDBUS_MAKE_ACCESS_GROUP: Make the bus or endpoint node group-accessible - * @KDBUS_MAKE_ACCESS_WORLD: Make the bus or endpoint node world-accessible - */ -enum kdbus_make_flags { - KDBUS_MAKE_ACCESS_GROUP = 1ULL << 0, - KDBUS_MAKE_ACCESS_WORLD = 1ULL << 1, -}; - -/** - * enum kdbus_name_flags - flags for KDBUS_CMD_NAME_ACQUIRE - * @KDBUS_NAME_REPLACE_EXISTING: Try to replace name of other connections - * @KDBUS_NAME_ALLOW_REPLACEMENT: Allow the replacement of the name - * @KDBUS_NAME_QUEUE: Name should be queued if busy - * @KDBUS_NAME_IN_QUEUE: Name is queued - * @KDBUS_NAME_ACTIVATOR: Name is owned by a activator connection - */ -enum kdbus_name_flags { - KDBUS_NAME_REPLACE_EXISTING = 1ULL << 0, - KDBUS_NAME_ALLOW_REPLACEMENT = 1ULL << 1, - KDBUS_NAME_QUEUE = 1ULL << 2, - KDBUS_NAME_IN_QUEUE = 1ULL << 3, - KDBUS_NAME_ACTIVATOR = 1ULL << 4, -}; - -/** - * struct kdbus_cmd - generic ioctl payload - * @size: Overall size of this structure - * @flags: Flags for this ioctl, userspace → kernel - * @return_flags: Ioctl return flags, kernel → userspace - * @items: Additional items to modify the behavior - * - * This is a generic ioctl payload object. It's used by all ioctls that only - * take flags and items as input. - */ -struct kdbus_cmd { - __u64 size; - __u64 flags; - __u64 return_flags; - struct kdbus_item items[0]; -} __attribute__((__aligned__(8))); - -/** - * Ioctl API - * - * KDBUS_CMD_BUS_MAKE: After opening the "control" node, this command - * creates a new bus with the specified - * name. The bus is immediately shut down and - * cleaned up when the opened file descriptor is - * closed. - * - * KDBUS_CMD_ENDPOINT_MAKE: Creates a new named special endpoint to talk to - * the bus. Such endpoints usually carry a more - * restrictive policy and grant restricted access - * to specific applications. - * KDBUS_CMD_ENDPOINT_UPDATE: Update the properties of a custom enpoint. Used - * to update the policy. - * - * KDBUS_CMD_HELLO: By opening the bus node, a connection is - * created. After a HELLO the opened connection - * becomes an active peer on the bus. - * KDBUS_CMD_UPDATE: Update the properties of a connection. Used to - * update the metadata subscription mask and - * policy. - * KDBUS_CMD_BYEBYE: Disconnect a connection. If there are no - * messages queued up in the connection's pool, - * the call succeeds, and the handle is rendered - * unusable. Otherwise, -EBUSY is returned without - * any further side-effects. - * KDBUS_CMD_FREE: Release the allocated memory in the receiver's - * pool. - * KDBUS_CMD_CONN_INFO: Retrieve credentials and properties of the - * initial creator of the connection. The data was - * stored at registration time and does not - * necessarily represent the connected process or - * the actual state of the process. - * KDBUS_CMD_BUS_CREATOR_INFO: Retrieve information of the creator of the bus - * a connection is attached to. - * - * KDBUS_CMD_SEND: Send a message and pass data from userspace to - * the kernel. - * KDBUS_CMD_RECV: Receive a message from the kernel which is - * placed in the receiver's pool. - * - * KDBUS_CMD_NAME_ACQUIRE: Request a well-known bus name to associate with - * the connection. Well-known names are used to - * address a peer on the bus. - * KDBUS_CMD_NAME_RELEASE: Release a well-known name the connection - * currently owns. - * KDBUS_CMD_LIST: Retrieve the list of all currently registered - * well-known and unique names. - * - * KDBUS_CMD_MATCH_ADD: Install a match which broadcast messages should - * be delivered to the connection. - * KDBUS_CMD_MATCH_REMOVE: Remove a current match for broadcast messages. - */ -enum kdbus_ioctl_type { - /* bus owner (00-0f) */ - KDBUS_CMD_BUS_MAKE = _IOW(KDBUS_IOCTL_MAGIC, 0x00, - struct kdbus_cmd), - - /* endpoint owner (10-1f) */ - KDBUS_CMD_ENDPOINT_MAKE = _IOW(KDBUS_IOCTL_MAGIC, 0x10, - struct kdbus_cmd), - KDBUS_CMD_ENDPOINT_UPDATE = _IOW(KDBUS_IOCTL_MAGIC, 0x11, - struct kdbus_cmd), - - /* connection owner (80-ff) */ - KDBUS_CMD_HELLO = _IOWR(KDBUS_IOCTL_MAGIC, 0x80, - struct kdbus_cmd_hello), - KDBUS_CMD_UPDATE = _IOW(KDBUS_IOCTL_MAGIC, 0x81, - struct kdbus_cmd), - KDBUS_CMD_BYEBYE = _IOW(KDBUS_IOCTL_MAGIC, 0x82, - struct kdbus_cmd), - KDBUS_CMD_FREE = _IOW(KDBUS_IOCTL_MAGIC, 0x83, - struct kdbus_cmd_free), - KDBUS_CMD_CONN_INFO = _IOR(KDBUS_IOCTL_MAGIC, 0x84, - struct kdbus_cmd_info), - KDBUS_CMD_BUS_CREATOR_INFO = _IOR(KDBUS_IOCTL_MAGIC, 0x85, - struct kdbus_cmd_info), - KDBUS_CMD_LIST = _IOR(KDBUS_IOCTL_MAGIC, 0x86, - struct kdbus_cmd_list), - - KDBUS_CMD_SEND = _IOW(KDBUS_IOCTL_MAGIC, 0x90, - struct kdbus_cmd_send), - KDBUS_CMD_RECV = _IOR(KDBUS_IOCTL_MAGIC, 0x91, - struct kdbus_cmd_recv), - - KDBUS_CMD_NAME_ACQUIRE = _IOW(KDBUS_IOCTL_MAGIC, 0xa0, - struct kdbus_cmd), - KDBUS_CMD_NAME_RELEASE = _IOW(KDBUS_IOCTL_MAGIC, 0xa1, - struct kdbus_cmd), - - KDBUS_CMD_MATCH_ADD = _IOW(KDBUS_IOCTL_MAGIC, 0xb0, - struct kdbus_cmd_match), - KDBUS_CMD_MATCH_REMOVE = _IOW(KDBUS_IOCTL_MAGIC, 0xb1, - struct kdbus_cmd_match), -}; - -#endif /* _UAPI_KDBUS_H_ */ diff --git a/src/libelogind/sd-bus/sd-bus.c b/src/libelogind/sd-bus/sd-bus.c index fda12a384..2a490405e 100644 --- a/src/libelogind/sd-bus/sd-bus.c +++ b/src/libelogind/sd-bus/sd-bus.c @@ -1,28 +1,15 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <endian.h> #include <netdb.h> #include <poll.h> #include <pthread.h> +//#include <signal.h> #include <stdlib.h> #include <sys/mman.h> +//#include <sys/wait.h> #include <unistd.h> #include "sd-bus.h" @@ -49,14 +36,18 @@ #include "macro.h" #include "missing.h" #include "parse-util.h" +//#include "process-util.h" #include "string-util.h" #include "strv.h" #include "util.h" +/// Additional includes needed by elogind +#include "process-util.h" + #define log_debug_bus_message(m) \ do { \ sd_bus_message *_mm = (m); \ - log_debug("Got message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " error=%s", \ + log_debug("Got message type=%s sender=%s destination=%s path=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " signature=%s error-name=%s error-message=%s", \ bus_message_type_to_string(_mm->header->type), \ strna(sd_bus_message_get_sender(_mm)), \ strna(sd_bus_message_get_destination(_mm)), \ @@ -65,29 +56,97 @@ strna(sd_bus_message_get_member(_mm)), \ BUS_MESSAGE_COOKIE(_mm), \ _mm->reply_cookie, \ + strna(_mm->root_container.signature), \ + strna(_mm->error.name), \ strna(_mm->error.message)); \ } while (false) static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec); -static int attach_io_events(sd_bus *b); -static void detach_io_events(sd_bus *b); +static void bus_detach_io_events(sd_bus *b); +static void bus_detach_inotify_event(sd_bus *b); static thread_local sd_bus *default_system_bus = NULL; -#if 0 /// UNNEEDED by elogind static thread_local sd_bus *default_user_bus = NULL; -#endif // 0 static thread_local sd_bus *default_starter_bus = NULL; -static void bus_close_fds(sd_bus *b) { +static sd_bus **bus_choose_default(int (**bus_open)(sd_bus **)) { + const char *e; + + /* Let's try our best to reuse another cached connection. If + * the starter bus type is set, connect via our normal + * connection logic, ignoring $DBUS_STARTER_ADDRESS, so that + * we can share the connection with the user/system default + * bus. */ + + e = secure_getenv("DBUS_STARTER_BUS_TYPE"); + if (e) { + if (streq(e, "system")) { + if (bus_open) + *bus_open = sd_bus_open_system; + return &default_system_bus; + } else if (STR_IN_SET(e, "user", "session")) { + if (bus_open) + *bus_open = sd_bus_open_user; + return &default_user_bus; + } + } + + /* No type is specified, so we have not other option than to + * use the starter address if it is set. */ + e = secure_getenv("DBUS_STARTER_ADDRESS"); + if (e) { + if (bus_open) + *bus_open = sd_bus_open; + return &default_starter_bus; + } + + /* Finally, if nothing is set use the cached connection for + * the right scope */ + + if (cg_pid_get_owner_uid(0, NULL) >= 0) { + if (bus_open) + *bus_open = sd_bus_open_user; + return &default_user_bus; + } else { + if (bus_open) + *bus_open = sd_bus_open_system; + return &default_system_bus; + } +} + +sd_bus *bus_resolve(sd_bus *bus) { + switch ((uintptr_t) bus) { + case (uintptr_t) SD_BUS_DEFAULT: + return *(bus_choose_default(NULL)); + case (uintptr_t) SD_BUS_DEFAULT_USER: + return default_user_bus; + case (uintptr_t) SD_BUS_DEFAULT_SYSTEM: + return default_system_bus; + default: + return bus; + } +} + +void bus_close_io_fds(sd_bus *b) { assert(b); - detach_io_events(b); + bus_detach_io_events(b); if (b->input_fd != b->output_fd) safe_close(b->output_fd); b->output_fd = b->input_fd = safe_close(b->input_fd); } +void bus_close_inotify_fd(sd_bus *b) { + assert(b); + + bus_detach_inotify_event(b); + + b->inotify_fd = safe_close(b->inotify_fd); + b->inotify_watches = mfree(b->inotify_watches); + b->n_inotify_watches = 0; +} + static void bus_reset_queues(sd_bus *b) { assert(b); @@ -104,7 +163,7 @@ static void bus_reset_queues(sd_bus *b) { b->wqueue_allocated = 0; } -static void bus_free(sd_bus *b) { +static sd_bus* bus_free(sd_bus *b) { sd_bus_slot *s; assert(b); @@ -131,21 +190,19 @@ static void bus_free(sd_bus *b) { if (b->default_bus_ptr) *b->default_bus_ptr = NULL; - bus_close_fds(b); - - if (b->kdbus_buffer) - munmap(b->kdbus_buffer, KDBUS_POOL_SIZE); + bus_close_io_fds(b); + bus_close_inotify_fd(b); free(b->label); + free(b->groups); free(b->rbuffer); free(b->unique_name); free(b->auth_buffer); free(b->address); - free(b->kernel); free(b->machine); - free(b->fake_label); free(b->cgroup_root); free(b->description); + free(b->patch_sender); free(b->exec_path); strv_free(b->exec_argv); @@ -167,63 +224,56 @@ static void bus_free(sd_bus *b) { assert(hashmap_isempty(b->nodes)); hashmap_free(b->nodes); - bus_kernel_flush_memfd(b); + bus_flush_memfd(b); assert_se(pthread_mutex_destroy(&b->memfd_cache_mutex) == 0); - free(b); + return mfree(b); } +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, bus_free); + _public_ int sd_bus_new(sd_bus **ret) { - sd_bus *r; + _cleanup_free_ sd_bus *b = NULL; assert_return(ret, -EINVAL); - r = new0(sd_bus, 1); - if (!r) + b = new0(sd_bus, 1); + if (!b) return -ENOMEM; - r->n_ref = REFCNT_INIT; - r->input_fd = r->output_fd = -1; - r->message_version = 1; - r->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME; - r->hello_flags |= KDBUS_HELLO_ACCEPT_FD; - r->attach_flags |= KDBUS_ATTACH_NAMES; - r->original_pid = getpid(); + b->n_ref = REFCNT_INIT; + b->input_fd = b->output_fd = -1; + b->inotify_fd = -1; + b->message_version = 1; + b->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME; + b->accept_fd = true; + b->original_pid = getpid_cached(); + b->n_groups = (size_t) -1; - assert_se(pthread_mutex_init(&r->memfd_cache_mutex, NULL) == 0); + assert_se(pthread_mutex_init(&b->memfd_cache_mutex, NULL) == 0); - /* We guarantee that wqueue always has space for at least one - * entry */ - if (!GREEDY_REALLOC(r->wqueue, r->wqueue_allocated, 1)) { - free(r); + /* We guarantee that wqueue always has space for at least one entry */ + if (!GREEDY_REALLOC(b->wqueue, b->wqueue_allocated, 1)) return -ENOMEM; - } - *ret = r; + *ret = TAKE_PTR(b); return 0; } _public_ int sd_bus_set_address(sd_bus *bus, const char *address) { - char *a; - assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(address, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); - a = strdup(address); - if (!a) - return -ENOMEM; - - free(bus->address); - bus->address = a; - - return 0; + return free_and_strdup(&bus->address, address); } _public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(input_fd >= 0, -EBADF); assert_return(output_fd >= 0, -EBADF); @@ -235,36 +285,32 @@ _public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) { } _public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) { - char *p, **a; + _cleanup_strv_free_ char **a = NULL; + int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(path, -EINVAL); assert_return(!strv_isempty(argv), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); - p = strdup(path); - if (!p) - return -ENOMEM; - a = strv_copy(argv); - if (!a) { - free(p); + if (!a) return -ENOMEM; - } - - free(bus->exec_path); - strv_free(bus->exec_argv); - bus->exec_path = p; - bus->exec_argv = a; + r = free_and_strdup(&bus->exec_path, path); + if (r < 0) + return r; - return 0; + return strv_free_and_replace(bus->exec_argv, a); } _public_ int sd_bus_set_bus_client(sd_bus *bus, int b) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus->patch_sender, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); bus->bus_client = !!b; @@ -273,45 +319,40 @@ _public_ int sd_bus_set_bus_client(sd_bus *bus, int b) { _public_ int sd_bus_set_monitor(sd_bus *bus, int b) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); - SET_FLAG(bus->hello_flags, KDBUS_HELLO_MONITOR, b); + bus->is_monitor = !!b; return 0; } _public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); - SET_FLAG(bus->hello_flags, KDBUS_HELLO_ACCEPT_FD, b); + bus->accept_fd = !!b; return 0; } _public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) { - uint64_t new_flags; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); - new_flags = bus->attach_flags; - SET_FLAG(new_flags, KDBUS_ATTACH_TIMESTAMP, b); - - if (bus->attach_flags == new_flags) - return 0; - - bus->attach_flags = new_flags; - if (bus->state != BUS_UNSET && bus->is_kernel) - bus_kernel_realize_attach_flags(bus); + /* This is not actually supported by any of our transports these days, but we do honour it for synthetic + * replies, and maybe one day classic D-Bus learns this too */ + bus->attach_timestamp = !!b; return 0; } _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) { - uint64_t new_flags; - assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(mask <= _SD_BUS_CREDS_ALL, -EINVAL); assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -321,20 +362,12 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) { /* The well knowns we need unconditionally, so that matches can work */ bus->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME; - /* Make sure we don't lose the timestamp flag */ - new_flags = (bus->attach_flags & KDBUS_ATTACH_TIMESTAMP) | attach_flags_to_kdbus(bus->creds_mask); - if (bus->attach_flags == new_flags) - return 0; - - bus->attach_flags = new_flags; - if (bus->state != BUS_UNSET && bus->is_kernel) - bus_kernel_realize_attach_flags(bus); - return 0; } _public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(b || sd_id128_equal(server_id, SD_ID128_NULL), -EINVAL); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -346,6 +379,7 @@ _public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) { _public_ int sd_bus_set_anonymous(sd_bus *bus, int b) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -355,6 +389,7 @@ _public_ int sd_bus_set_anonymous(sd_bus *bus, int b) { _public_ int sd_bus_set_trusted(sd_bus *bus, int b) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -364,6 +399,7 @@ _public_ int sd_bus_set_trusted(sd_bus *bus, int b) { _public_ int sd_bus_set_description(sd_bus *bus, const char *description) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -372,6 +408,7 @@ _public_ int sd_bus_set_description(sd_bus *bus, const char *description) { _public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); bus->allow_interactive_authorization = !!b; @@ -380,11 +417,114 @@ _public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) { _public_ int sd_bus_get_allow_interactive_authorization(sd_bus *bus) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); return bus->allow_interactive_authorization; } +_public_ int sd_bus_set_watch_bind(sd_bus *bus, int b) { + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + bus->watch_bind = !!b; + return 0; +} + +_public_ int sd_bus_get_watch_bind(sd_bus *bus) { + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(!bus_pid_changed(bus), -ECHILD); + + return bus->watch_bind; +} + +_public_ int sd_bus_set_connected_signal(sd_bus *bus, int b) { + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + bus->connected_signal = !!b; + return 0; +} + +_public_ int sd_bus_get_connected_signal(sd_bus *bus) { + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(!bus_pid_changed(bus), -ECHILD); + + return bus->connected_signal; +} + +static int synthesize_connected_signal(sd_bus *bus) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + int r; + + assert(bus); + + /* If enabled, synthesizes a local "Connected" signal mirroring the local "Disconnected" signal. This is called + * whenever we fully established a connection, i.e. after the authorization phase, and after receiving the + * Hello() reply. Or in other words, whenver we enter BUS_RUNNING state. + * + * This is useful so that clients can start doing stuff whenver the connection is fully established in a way + * that works independently from whether we connected to a full bus or just a direct connection. */ + + if (!bus->connected_signal) + return 0; + + r = sd_bus_message_new_signal( + bus, + &m, + "/org/freedesktop/DBus/Local", + "org.freedesktop.DBus.Local", + "Connected"); + if (r < 0) + return r; + + bus_message_set_sender_local(bus, m); + + r = bus_seal_synthetic_message(bus, m); + if (r < 0) + return r; + + r = bus_rqueue_make_room(bus); + if (r < 0) + return r; + + /* Insert at the very front */ + memmove(bus->rqueue + 1, bus->rqueue, sizeof(sd_bus_message*) * bus->rqueue_size); + bus->rqueue[0] = TAKE_PTR(m); + bus->rqueue_size++; + + return 0; +} + +void bus_set_state(sd_bus *bus, enum bus_state state) { + + static const char * const table[_BUS_STATE_MAX] = { + [BUS_UNSET] = "UNSET", + [BUS_WATCH_BIND] = "WATCH_BIND", + [BUS_OPENING] = "OPENING", + [BUS_AUTHENTICATING] = "AUTHENTICATING", + [BUS_HELLO] = "HELLO", + [BUS_RUNNING] = "RUNNING", + [BUS_CLOSING] = "CLOSING", + [BUS_CLOSED] = "CLOSED", + }; + + assert(bus); + assert(state < _BUS_STATE_MAX); + + if (state == bus->state) + return; + + log_debug("Bus %s: changing state %s → %s", strna(bus->description), table[bus->state], table[state]); + bus->state = state; +} + static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) { const char *s; sd_bus *bus; @@ -393,7 +533,7 @@ static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *e assert(reply); bus = reply->bus; assert(bus); - assert(bus->state == BUS_HELLO || bus->state == BUS_CLOSING); + assert(IN_SET(bus->state, BUS_HELLO, BUS_CLOSING)); r = sd_bus_message_get_errno(reply); if (r > 0) @@ -406,12 +546,17 @@ static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *e if (!service_name_is_valid(s) || s[0] != ':') return -EBADMSG; - bus->unique_name = strdup(s); - if (!bus->unique_name) - return -ENOMEM; + r = free_and_strdup(&bus->unique_name, s); + if (r < 0) + return r; - if (bus->state == BUS_HELLO) - bus->state = BUS_RUNNING; + if (bus->state == BUS_HELLO) { + bus_set_state(bus, BUS_RUNNING); + + r = synthesize_connected_signal(bus); + if (r < 0) + return r; + } return 1; } @@ -422,7 +567,7 @@ static int bus_send_hello(sd_bus *bus) { assert(bus); - if (!bus->bus_client || bus->is_kernel) + if (!bus->bus_client) return 0; r = sd_bus_message_new_method_call( @@ -439,21 +584,44 @@ static int bus_send_hello(sd_bus *bus) { } int bus_start_running(sd_bus *bus) { + struct reply_callback *c; + Iterator i; + usec_t n; + int r; + assert(bus); + assert(bus->state < BUS_HELLO); - if (bus->bus_client && !bus->is_kernel) { - bus->state = BUS_HELLO; + /* We start all method call timeouts when we enter BUS_HELLO or BUS_RUNNING mode. At this point let's convert + * all relative to absolute timestamps. Note that we do not reshuffle the reply callback priority queue since + * adding a fixed value to all entries should not alter the internal order. */ + + n = now(CLOCK_MONOTONIC); + ORDERED_HASHMAP_FOREACH(c, bus->reply_callbacks, i) { + if (c->timeout_usec == 0) + continue; + + c->timeout_usec = usec_add(n, c->timeout_usec); + } + + if (bus->bus_client) { + bus_set_state(bus, BUS_HELLO); return 1; } - bus->state = BUS_RUNNING; + bus_set_state(bus, BUS_RUNNING); + + r = synthesize_connected_signal(bus); + if (r < 0) + return r; + return 1; } static int parse_address_key(const char **p, const char *key, char **value) { size_t l, n = 0, allocated = 0; + _cleanup_free_ char *r = NULL; const char *a; - char *r = NULL; assert(p); assert(*p); @@ -474,23 +642,19 @@ static int parse_address_key(const char **p, const char *key, char **value) { } else a = *p; - while (*a != ';' && *a != ',' && *a != 0) { + while (!IN_SET(*a, ';', ',', 0)) { char c; if (*a == '%') { int x, y; x = unhexchar(a[1]); - if (x < 0) { - free(r); + if (x < 0) return x; - } y = unhexchar(a[2]); - if (y < 0) { - free(r); + if (y < 0) return y; - } c = (char) ((x << 4) | y); a += 3; @@ -517,8 +681,7 @@ static int parse_address_key(const char **p, const char *key, char **value) { *p = a; - free(*value); - *value = r; + free_and_replace(*value, r); return 1; } @@ -543,7 +706,7 @@ static int parse_unix_address(sd_bus *b, const char **p, char **guid) { assert(*p); assert(guid); - while (**p != 0 && **p != ';') { + while (!IN_SET(**p, 0, ';')) { r = parse_address_key(p, "guid", guid); if (r < 0) return r; @@ -608,7 +771,7 @@ static int parse_tcp_address(sd_bus *b, const char **p, char **guid) { assert(*p); assert(guid); - while (**p != 0 && **p != ';') { + while (!IN_SET(**p, 0, ';')) { r = parse_address_key(p, "guid", guid); if (r < 0) return r; @@ -676,7 +839,7 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) { assert(*p); assert(guid); - while (**p != 0 && **p != ';') { + while (!IN_SET(**p, 0, ';')) { r = parse_address_key(p, "guid", guid); if (r < 0) goto fail; @@ -757,43 +920,6 @@ fail: return r; } -static int parse_kernel_address(sd_bus *b, const char **p, char **guid) { - _cleanup_free_ char *path = NULL; - int r; - - assert(b); - assert(p); - assert(*p); - assert(guid); - - while (**p != 0 && **p != ';') { - r = parse_address_key(p, "guid", guid); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_address_key(p, "path", &path); - if (r < 0) - return r; - else if (r > 0) - continue; - - skip_address_key(p); - } - - if (!path) - return -EINVAL; - - free(b->kernel); - b->kernel = path; - path = NULL; - - b->is_local = true; - - return 0; -} - static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) { _cleanup_free_ char *machine = NULL, *pid = NULL; int r; @@ -803,7 +929,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) assert(*p); assert(guid); - while (**p != 0 && **p != ';') { + while (!IN_SET(**p, 0, ';')) { r = parse_address_key(p, "guid", guid); if (r < 0) return r; @@ -832,9 +958,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) if (!machine_name_is_valid(machine)) return -EINVAL; - free(b->machine); - b->machine = machine; - machine = NULL; + free_and_replace(b->machine, machine); } else { b->machine = mfree(b->machine); } @@ -847,6 +971,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) b->nspid = 0; b->sockaddr.un.sun_family = AF_UNIX; + /* Note that we use the old /var/run prefix here, to increase compatibility with really old containers */ strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path)); b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un); b->is_local = false; @@ -854,67 +979,6 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) return 0; } -static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid) { - _cleanup_free_ char *machine = NULL, *pid = NULL; - int r; - - assert(b); - assert(p); - assert(*p); - assert(guid); - - while (**p != 0 && **p != ';') { - r = parse_address_key(p, "guid", guid); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_address_key(p, "machine", &machine); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_address_key(p, "pid", &pid); - if (r < 0) - return r; - else if (r > 0) - continue; - - skip_address_key(p); - } - - if (!machine == !pid) - return -EINVAL; - - if (machine) { - if (!machine_name_is_valid(machine)) - return -EINVAL; - - free(b->machine); - b->machine = machine; - machine = NULL; - } else { - b->machine = mfree(b->machine); - } - - if (pid) { - r = parse_pid(pid, &b->nspid); - if (r < 0) - return r; - } else - b->nspid = 0; - - r = free_and_strdup(&b->kernel, "/sys/fs/kdbus/0-system/bus"); - if (r < 0) - return r; - - b->is_local = false; - - return 0; -} - static void bus_reset_parsed_address(sd_bus *b) { assert(b); @@ -923,7 +987,6 @@ static void bus_reset_parsed_address(sd_bus *b) { b->exec_argv = strv_free(b->exec_argv); b->exec_path = mfree(b->exec_path); b->server_id = SD_ID128_NULL; - b->kernel = mfree(b->kernel); b->machine = mfree(b->machine); b->nspid = 0; } @@ -977,14 +1040,6 @@ static int bus_parse_next_address(sd_bus *b) { break; - } else if (startswith(a, "kernel:")) { - - a += 7; - r = parse_kernel_address(b, &a, &guid); - if (r < 0) - return r; - - break; } else if (startswith(a, "x-machine-unix:")) { a += 15; @@ -993,14 +1048,6 @@ static int bus_parse_next_address(sd_bus *b) { return r; break; - } else if (startswith(a, "x-machine-kernel:")) { - - a += 17; - r = parse_container_kernel_address(b, &a, &guid); - if (r < 0) - return r; - - break; } a = strchr(a, ';'); @@ -1018,69 +1065,59 @@ static int bus_parse_next_address(sd_bus *b) { return 1; } +static void bus_kill_exec(sd_bus *bus) { + if (pid_is_valid(bus->busexec_pid) > 0) { + sigterm_wait(bus->busexec_pid); + bus->busexec_pid = 0; + } +} + static int bus_start_address(sd_bus *b) { - bool container_kdbus_available = false; - bool kdbus_available = false; int r; assert(b); for (;;) { - bool skipped = false; + bus_close_io_fds(b); + bus_close_inotify_fd(b); - bus_close_fds(b); + bus_kill_exec(b); - /* - * Usually, if you provide multiple different bus-addresses, we - * try all of them in order. We use the first one that - * succeeds. However, if you mix kernel and unix addresses, we - * never try unix-addresses if a previous kernel address was - * tried and kdbus was available. This is required to prevent - * clients to fallback to the bus-proxy if kdbus is available - * but failed (eg., too many connections). - */ + /* If you provide multiple different bus-addresses, we + * try all of them in order and use the first one that + * succeeds. */ if (b->exec_path) r = bus_socket_exec(b); - else if ((b->nspid > 0 || b->machine) && b->kernel) { - r = bus_container_connect_kernel(b); - if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT)) - container_kdbus_available = true; - - } else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC) { - if (!container_kdbus_available) - r = bus_container_connect_socket(b); - else - skipped = true; - - } else if (b->kernel) { - r = bus_kernel_connect(b); - if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT)) - kdbus_available = true; - - } else if (b->sockaddr.sa.sa_family != AF_UNSPEC) { - if (!kdbus_available) - r = bus_socket_connect(b); - else - skipped = true; - } else - skipped = true; + else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC) + r = bus_container_connect_socket(b); + else if (b->sockaddr.sa.sa_family != AF_UNSPEC) + r = bus_socket_connect(b); + else + goto next; - if (!skipped) { - if (r >= 0) { - r = attach_io_events(b); - if (r >= 0) - return r; - } + if (r >= 0) { + int q; + + q = bus_attach_io_events(b); + if (q < 0) + return q; - b->last_connect_error = -r; + q = bus_attach_inotify_event(b); + if (q < 0) + return q; + + return r; } + b->last_connect_error = -r; + + next: r = bus_parse_next_address(b); if (r < 0) return r; if (r == 0) - return b->last_connect_error ? -b->last_connect_error : -ECONNREFUSED; + return b->last_connect_error > 0 ? -b->last_connect_error : -ECONNREFUSED; } } @@ -1120,27 +1157,25 @@ static int bus_start_fd(sd_bus *b) { if (fstat(b->input_fd, &st) < 0) return -errno; - if (S_ISCHR(b->input_fd)) - return bus_kernel_take_fd(b); - else - return bus_socket_take_fd(b); + return bus_socket_take_fd(b); } _public_ int sd_bus_start(sd_bus *bus) { int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); - bus->state = BUS_OPENING; + bus_set_state(bus, BUS_OPENING); if (bus->is_server && bus->bus_client) return -EINVAL; if (bus->input_fd >= 0) r = bus_start_fd(bus); - else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->kernel || bus->machine) + else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->machine) r = bus_start_address(bus); else return -EINVAL; @@ -1153,9 +1188,9 @@ _public_ int sd_bus_start(sd_bus *bus) { return bus_send_hello(bus); } -_public_ int sd_bus_open(sd_bus **ret) { +_public_ int sd_bus_open_with_description(sd_bus **ret, const char *description) { const char *e; - sd_bus *b; + _cleanup_(bus_freep) sd_bus *b = NULL; int r; assert_return(ret, -EINVAL); @@ -1167,21 +1202,21 @@ _public_ int sd_bus_open(sd_bus **ret) { e = secure_getenv("DBUS_STARTER_BUS_TYPE"); if (e) { if (streq(e, "system")) - return sd_bus_open_system(ret); -#if 0 /// elogind does not support systemd units + return sd_bus_open_system_with_description(ret, description); +#if 0 /// elogind does not support systemd user instances else if (STR_IN_SET(e, "session", "user")) - return sd_bus_open_user(ret); #endif // 0 + return sd_bus_open_user_with_description(ret, description); } e = secure_getenv("DBUS_STARTER_ADDRESS"); if (!e) { -#if 0 /// elogind does not support systemd units +#if 0 /// elogind does not support systemd user instances if (cg_pid_get_owner_uid(0, NULL) >= 0) - return sd_bus_open_user(ret); + return sd_bus_open_user_with_description(ret, description); else #endif // 0 - return sd_bus_open_system(ret); + return sd_bus_open_system_with_description(ret, description); } r = sd_bus_new(&b); @@ -1190,7 +1225,7 @@ _public_ int sd_bus_open(sd_bus **ret) { r = sd_bus_set_address(b, e); if (r < 0) - goto fail; + return r; b->bus_client = true; @@ -1198,19 +1233,18 @@ _public_ int sd_bus_open(sd_bus **ret) { * be safe, and authenticate everything */ b->trusted = false; b->is_local = false; - b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS; b->creds_mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS; r = sd_bus_start(b); if (r < 0) - goto fail; + return r; - *ret = b; + *ret = TAKE_PTR(b); return 0; +} -fail: - bus_free(b); - return r; +_public_ int sd_bus_open(sd_bus **ret) { + return sd_bus_open_with_description(ret, NULL); } int bus_set_address_system(sd_bus *b) { @@ -1224,8 +1258,8 @@ int bus_set_address_system(sd_bus *b) { return sd_bus_set_address(b, DEFAULT_SYSTEM_BUS_ADDRESS); } -_public_ int sd_bus_open_system(sd_bus **ret) { - sd_bus *b; +_public_ int sd_bus_open_system_with_description(sd_bus **ret, const char *description) { + _cleanup_(bus_freep) sd_bus *b = NULL; int r; assert_return(ret, -EINVAL); @@ -1234,9 +1268,15 @@ _public_ int sd_bus_open_system(sd_bus **ret) { if (r < 0) return r; + if (description) { + r = sd_bus_set_description(b, description); + if (r < 0) + return r; + } + r = bus_set_address_system(b); if (r < 0) - goto fail; + return r; b->bus_client = true; b->is_system = true; @@ -1244,27 +1284,25 @@ _public_ int sd_bus_open_system(sd_bus **ret) { /* Let's do per-method access control on the system bus. We * need the caller's UID and capability set for that. */ b->trusted = false; - b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS; b->creds_mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS; b->is_local = true; r = sd_bus_start(b); if (r < 0) - goto fail; + return r; - *ret = b; + *ret = TAKE_PTR(b); return 0; +} -fail: - bus_free(b); - return r; +_public_ int sd_bus_open_system(sd_bus **ret) { + return sd_bus_open_system_with_description(ret, NULL); } #if 0 /// elogind can not open/use a user bus int bus_set_address_user(sd_bus *b) { const char *e; - uid_t uid; - int r; + _cleanup_free_ char *ee = NULL, *s = NULL; assert(b); @@ -1272,32 +1310,26 @@ int bus_set_address_user(sd_bus *b) { if (e) return sd_bus_set_address(b, e); - r = cg_pid_get_owner_uid(0, &uid); - if (r < 0) - uid = getuid(); - e = secure_getenv("XDG_RUNTIME_DIR"); - if (e) { - _cleanup_free_ char *ee = NULL; - - ee = bus_address_escape(e); - if (!ee) - return -ENOMEM; + if (!e) + return -ENOENT; - (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, ee); - } else - (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, uid); + ee = bus_address_escape(e); + if (!ee) + return -ENOMEM; - if (!b->address) + if (asprintf(&s, DEFAULT_USER_BUS_ADDRESS_FMT, ee) < 0) return -ENOMEM; + b->address = TAKE_PTR(s); + return 0; } #endif // 0 -_public_ int sd_bus_open_user(sd_bus **ret) { +_public_ int sd_bus_open_user_with_description(sd_bus **ret, const char *description) { #if 0 /// elogind does not support user buses - sd_bus *b; + _cleanup_(bus_freep) sd_bus *b = NULL; int r; assert_return(ret, -EINVAL); @@ -1306,6 +1338,12 @@ _public_ int sd_bus_open_user(sd_bus **ret) { if (r < 0) return r; + if (description) { + r = sd_bus_set_description(b, description); + if (r < 0) + return r; + } + r = bus_set_address_user(b); if (r < 0) return r; @@ -1320,22 +1358,22 @@ _public_ int sd_bus_open_user(sd_bus **ret) { r = sd_bus_start(b); if (r < 0) - goto fail; + return r; - *ret = b; + *ret = TAKE_PTR(b); return 0; - -fail: - bus_free(b); - return r; #else - return sd_bus_open_system(ret); + return sd_bus_open_system_with_description(ret, description); #endif // 0 } +_public_ int sd_bus_open_user(sd_bus **ret) { + return sd_bus_open_user_with_description(ret, NULL); +} + int bus_set_address_system_remote(sd_bus *b, const char *host) { _cleanup_free_ char *e = NULL; - char *m = NULL, *c = NULL; + char *m = NULL, *c = NULL, *a; assert(b); assert(host); @@ -1347,7 +1385,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) { /* Let's make sure this is not a port of some kind, * and is a valid machine name. */ - if (!in_charset(m, "0123456789") && machine_name_is_valid(m)) { + if (!in_charset(m, DIGITS) && machine_name_is_valid(m)) { char *t; /* Cut out the host part */ @@ -1356,7 +1394,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) { if (!e) return -ENOMEM; - c = strjoina(",argv4=--machine=", m); + c = strjoina(",argv5=--machine=", m); } } @@ -1366,47 +1404,44 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) { return -ENOMEM; } - b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", c); - if (!b->address) + a = strjoin("unixexec:path=ssh,argv1=-xT,argv2=--,argv3=", e, ",argv4=elogind-stdio-bridge", c); + if (!a) return -ENOMEM; - return 0; - } + return free_and_replace(b->address, a); +} _public_ int sd_bus_open_system_remote(sd_bus **ret, const char *host) { - sd_bus *bus; + _cleanup_(bus_freep) sd_bus *b = NULL; int r; assert_return(host, -EINVAL); assert_return(ret, -EINVAL); - r = sd_bus_new(&bus); + r = sd_bus_new(&b); if (r < 0) return r; - r = bus_set_address_system_remote(bus, host); + r = bus_set_address_system_remote(b, host); if (r < 0) - goto fail; + return r; - bus->bus_client = true; - bus->trusted = false; - bus->is_system = true; - bus->is_local = false; + b->bus_client = true; + b->trusted = false; + b->is_system = true; + b->is_local = false; - r = sd_bus_start(bus); + r = sd_bus_start(b); if (r < 0) - goto fail; + return r; - *ret = bus; + *ret = TAKE_PTR(b); return 0; - -fail: - bus_free(bus); - return r; } int bus_set_address_system_machine(sd_bus *b, const char *machine) { _cleanup_free_ char *e = NULL; + char *a; assert(b); assert(machine); @@ -1415,48 +1450,43 @@ int bus_set_address_system_machine(sd_bus *b, const char *machine) { if (!e) return -ENOMEM; - b->address = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e); - if (!b->address) + a = strjoin("x-machine-unix:machine=", e); + if (!a) return -ENOMEM; - return 0; + return free_and_replace(b->address, a); } _public_ int sd_bus_open_system_machine(sd_bus **ret, const char *machine) { - sd_bus *bus; + _cleanup_(bus_freep) sd_bus *b = NULL; int r; assert_return(machine, -EINVAL); assert_return(ret, -EINVAL); assert_return(machine_name_is_valid(machine), -EINVAL); - r = sd_bus_new(&bus); + r = sd_bus_new(&b); if (r < 0) return r; - r = bus_set_address_system_machine(bus, machine); + r = bus_set_address_system_machine(b, machine); if (r < 0) - goto fail; + return r; - bus->bus_client = true; - bus->trusted = false; - bus->is_system = true; - bus->is_local = false; + b->bus_client = true; + b->trusted = false; + b->is_system = true; + b->is_local = false; - r = sd_bus_start(bus); + r = sd_bus_start(b); if (r < 0) - goto fail; + return r; - *ret = bus; + *ret = TAKE_PTR(b); return 0; - -fail: - bus_free(bus); - return r; } _public_ void sd_bus_close(sd_bus *bus) { - if (!bus) return; if (bus->state == BUS_CLOSED) @@ -1464,7 +1494,10 @@ _public_ void sd_bus_close(sd_bus *bus) { if (bus_pid_changed(bus)) return; - bus->state = BUS_CLOSED; + /* Don't leave ssh hanging around */ + bus_kill_exec(bus); + + bus_set_state(bus, BUS_CLOSED); sd_bus_detach_event(bus); @@ -1472,40 +1505,33 @@ _public_ void sd_bus_close(sd_bus *bus) { * the bus object and the bus may be freed */ bus_reset_queues(bus); - if (!bus->is_kernel) - bus_close_fds(bus); - - /* We'll leave the fd open in case this is a kernel bus, since - * there might still be memblocks around that reference this - * bus, and they might need to invoke the KDBUS_CMD_FREE - * ioctl on the fd when they are freed. */ + bus_close_io_fds(bus); + bus_close_inotify_fd(bus); } _public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) { - if (!bus) return NULL; + /* Have to do this before flush() to prevent hang */ + bus_kill_exec(bus); + sd_bus_flush(bus); sd_bus_close(bus); return sd_bus_unref(bus); } -static void bus_enter_closing(sd_bus *bus) { +void bus_enter_closing(sd_bus *bus) { assert(bus); - if (bus->state != BUS_OPENING && - bus->state != BUS_AUTHENTICATING && - bus->state != BUS_HELLO && - bus->state != BUS_RUNNING) + if (!IN_SET(bus->state, BUS_WATCH_BIND, BUS_OPENING, BUS_AUTHENTICATING, BUS_HELLO, BUS_RUNNING)) return; - bus->state = BUS_CLOSING; + bus_set_state(bus, BUS_CLOSING); } _public_ sd_bus *sd_bus_ref(sd_bus *bus) { - if (!bus) return NULL; @@ -1524,30 +1550,38 @@ _public_ sd_bus *sd_bus_unref(sd_bus *bus) { if (i > 0) return NULL; - bus_free(bus); - return NULL; + return bus_free(bus); } _public_ int sd_bus_is_open(sd_bus *bus) { - assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); return BUS_IS_OPEN(bus->state); } +_public_ int sd_bus_is_ready(sd_bus *bus) { + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(!bus_pid_changed(bus), -ECHILD); + + return bus->state == BUS_RUNNING; +} + _public_ int sd_bus_can_send(sd_bus *bus, char type) { int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state != BUS_UNSET, -ENOTCONN); assert_return(!bus_pid_changed(bus), -ECHILD); - if (bus->hello_flags & KDBUS_HELLO_MONITOR) + if (bus->is_monitor) return 0; if (type == SD_BUS_TYPE_UNIX_FD) { - if (!(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) + if (!bus->accept_fd) return 0; r = bus_ensure_running(bus); @@ -1564,6 +1598,7 @@ _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) { int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(id, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -1576,6 +1611,8 @@ _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) { } static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) { + int r; + assert(b); assert(m); @@ -1590,7 +1627,13 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) { if (timeout == 0) timeout = BUS_DEFAULT_TIMEOUT; - return bus_message_seal(m, ++b->cookie, timeout); + if (!m->sender && b->patch_sender) { + r = sd_bus_message_set_sender(m, b->patch_sender); + if (r < 0) + return r; + } + + return sd_bus_message_seal(m, ++b->cookie, timeout); } static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) { @@ -1606,14 +1649,6 @@ static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) { if (b->message_endian != 0 && b->message_endian != (*m)->header->endian) remarshal = true; - /* TODO: kdbus-messages received from the kernel contain data which is - * not allowed to be passed to KDBUS_CMD_SEND. Therefore, we have to - * force remarshaling of the message. Technically, we could just - * recreate the kdbus message, but that is non-trivial as other parts of - * the message refer to m->kdbus already. This should be fixed! */ - if ((*m)->kdbus && (*m)->release_kdbus) - remarshal = true; - return remarshal ? bus_message_remarshal(b, m) : 0; } @@ -1623,7 +1658,7 @@ int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) { /* Fake some timestamps, if they were requested, and not * already initialized */ - if (b->attach_flags & KDBUS_ATTACH_TIMESTAMP) { + if (b->attach_timestamp) { if (m->realtime <= 0) m->realtime = now(CLOCK_REALTIME); @@ -1638,25 +1673,21 @@ int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) { * pick a fixed, artificial one. We use (uint32_t) -1 rather * than (uint64_t) -1 since dbus1 only had 32bit identifiers, * even though kdbus can do 64bit. */ - return bus_message_seal(m, 0xFFFFFFFFULL, 0); + return sd_bus_message_seal(m, 0xFFFFFFFFULL, 0); } -static int bus_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call, size_t *idx) { +static int bus_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { int r; assert(bus); assert(m); - if (bus->is_kernel) - r = bus_kernel_write_message(bus, m, hint_sync_call); - else - r = bus_socket_write_message(bus, m, idx); - + r = bus_socket_write_message(bus, m, idx); if (r <= 0) return r; - if (bus->is_kernel || *idx >= BUS_MESSAGE_SIZE(m)) - log_debug("Sent message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " error=%s", + if (*idx >= BUS_MESSAGE_SIZE(m)) + log_debug("Sent message type=%s sender=%s destination=%s path=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " signature=%s error-name=%s error-message=%s", bus_message_type_to_string(m->header->type), strna(sd_bus_message_get_sender(m)), strna(sd_bus_message_get_destination(m)), @@ -1665,6 +1696,8 @@ static int bus_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call strna(sd_bus_message_get_member(m)), BUS_MESSAGE_COOKIE(m), m->reply_cookie, + strna(m->root_container.signature), + strna(m->error.name), strna(m->error.message)); return r; @@ -1674,17 +1707,17 @@ static int dispatch_wqueue(sd_bus *bus) { int r, ret = 0; assert(bus); - assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)); while (bus->wqueue_size > 0) { - r = bus_write_message(bus, bus->wqueue[0], false, &bus->windex); + r = bus_write_message(bus, bus->wqueue[0], &bus->windex); if (r < 0) return r; else if (r == 0) /* Didn't do anything this time */ return ret; - else if (bus->is_kernel || bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) { + else if (bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) { /* Fully written. Let's drop the entry from * the queue. * @@ -1710,10 +1743,7 @@ static int dispatch_wqueue(sd_bus *bus) { static int bus_read_message(sd_bus *bus, bool hint_priority, int64_t priority) { assert(bus); - if (bus->is_kernel) - return bus_kernel_read_message(bus, hint_priority, priority); - else - return bus_socket_read_message(bus); + return bus_socket_read_message(bus); } int bus_rqueue_make_room(sd_bus *bus) { @@ -1733,7 +1763,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd assert(bus); assert(m); - assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)); /* Note that the priority logic is only available on kdbus, * where the rqueue is unused. We check the rqueue here @@ -1760,7 +1790,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd } } -static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, bool hint_sync_call) { +_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m); int r; @@ -1770,7 +1800,6 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, bus = m->bus; assert_return(!bus_pid_changed(bus), -ECHILD); - assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -1803,10 +1832,10 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, if (m->dont_send) goto finish; - if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) { + if (IN_SET(bus->state, BUS_RUNNING, BUS_HELLO) && bus->wqueue_size <= 0) { size_t idx = 0; - r = bus_write_message(bus, m, hint_sync_call, &idx); + r = bus_write_message(bus, m, &idx); if (r < 0) { if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); @@ -1816,7 +1845,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, return r; } - if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m)) { + if (idx < BUS_MESSAGE_SIZE(m)) { /* Wasn't fully written. So let's remember how * much was written. Note that the first entry * of the wqueue array is always allocated so @@ -1846,10 +1875,6 @@ finish: return 1; } -_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) { - return bus_send_internal(bus, m, cookie, false); -} - _public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie) { int r; @@ -1876,26 +1901,35 @@ _public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destinat return sd_bus_send(bus, m, cookie); } -static usec_t calc_elapse(uint64_t usec) { +static usec_t calc_elapse(sd_bus *bus, uint64_t usec) { + assert(bus); + if (usec == (uint64_t) -1) return 0; - return now(CLOCK_MONOTONIC) + usec; + /* We start all timeouts the instant we enter BUS_HELLO/BUS_RUNNING state, so that the don't run in parallel + * with any connection setup states. Hence, if a method callback is started earlier than that we just store the + * relative timestamp, and afterwards the absolute one. */ + + if (IN_SET(bus->state, BUS_WATCH_BIND, BUS_OPENING, BUS_AUTHENTICATING)) + return usec; + else + return now(CLOCK_MONOTONIC) + usec; } static int timeout_compare(const void *a, const void *b) { const struct reply_callback *x = a, *y = b; - if (x->timeout != 0 && y->timeout == 0) + if (x->timeout_usec != 0 && y->timeout_usec == 0) return -1; - if (x->timeout == 0 && y->timeout != 0) + if (x->timeout_usec == 0 && y->timeout_usec != 0) return 1; - if (x->timeout < y->timeout) + if (x->timeout_usec < y->timeout_usec) return -1; - if (x->timeout > y->timeout) + if (x->timeout_usec > y->timeout_usec) return 1; return 0; @@ -1915,18 +1949,20 @@ _public_ int sd_bus_call_async( assert_return(m, -EINVAL); assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); - assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL); - assert_return(callback, -EINVAL); + assert_return(!m->sealed || (!!callback == !(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)), -EINVAL); if (!bus) bus = m->bus; assert_return(!bus_pid_changed(bus), -ECHILD); - assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; + /* If no callback is specified and there's no interest in a slot, then there's no reason to ask for a reply */ + if (!callback && !slot && !m->sealed) + m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + r = ordered_hashmap_ensure_allocated(&bus->reply_callbacks, &uint64_hash_ops); if (r < 0) return r; @@ -1943,29 +1979,31 @@ _public_ int sd_bus_call_async( if (r < 0) return r; - s = bus_slot_allocate(bus, !slot, BUS_REPLY_CALLBACK, sizeof(struct reply_callback), userdata); - if (!s) - return -ENOMEM; + if (slot || callback) { + s = bus_slot_allocate(bus, !slot, BUS_REPLY_CALLBACK, sizeof(struct reply_callback), userdata); + if (!s) + return -ENOMEM; - s->reply_callback.callback = callback; + s->reply_callback.callback = callback; - s->reply_callback.cookie = BUS_MESSAGE_COOKIE(m); - r = ordered_hashmap_put(bus->reply_callbacks, &s->reply_callback.cookie, &s->reply_callback); - if (r < 0) { - s->reply_callback.cookie = 0; - return r; - } - - s->reply_callback.timeout = calc_elapse(m->timeout); - if (s->reply_callback.timeout != 0) { - r = prioq_put(bus->reply_callbacks_prioq, &s->reply_callback, &s->reply_callback.prioq_idx); + s->reply_callback.cookie = BUS_MESSAGE_COOKIE(m); + r = ordered_hashmap_put(bus->reply_callbacks, &s->reply_callback.cookie, &s->reply_callback); if (r < 0) { - s->reply_callback.timeout = 0; + s->reply_callback.cookie = 0; return r; } + + s->reply_callback.timeout_usec = calc_elapse(bus, m->timeout); + if (s->reply_callback.timeout_usec != 0) { + r = prioq_put(bus->reply_callbacks_prioq, &s->reply_callback, &s->reply_callback.prioq_idx); + if (r < 0) { + s->reply_callback.timeout_usec = 0; + return r; + } + } } - r = sd_bus_send(bus, m, &s->reply_callback.cookie); + r = sd_bus_send(bus, m, s ? &s->reply_callback.cookie : NULL); if (r < 0) return r; @@ -1981,7 +2019,7 @@ int bus_ensure_running(sd_bus *bus) { assert(bus); - if (bus->state == BUS_UNSET || bus->state == BUS_CLOSED || bus->state == BUS_CLOSING) + if (IN_SET(bus->state, BUS_UNSET, BUS_CLOSED, BUS_CLOSING)) return -ENOTCONN; if (bus->state == BUS_RUNNING) return 1; @@ -2023,7 +2061,6 @@ _public_ int sd_bus_call( bus = m->bus; bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - bus_assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS, error); if (!BUS_IS_OPEN(bus->state)) { r = -ENOTCONN; @@ -2044,11 +2081,11 @@ _public_ int sd_bus_call( if (r < 0) goto fail; - r = bus_send_internal(bus, m, &cookie, true); + r = sd_bus_send(bus, m, &cookie); if (r < 0) goto fail; - timeout = calc_elapse(m->timeout); + timeout = calc_elapse(bus, m->timeout); for (;;) { usec_t left; @@ -2067,7 +2104,7 @@ _public_ int sd_bus_call( if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) { - if (incoming->n_fds <= 0 || (bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) { + if (incoming->n_fds <= 0 || bus->accept_fd) { if (reply) *reply = incoming; else @@ -2162,35 +2199,63 @@ fail: _public_ int sd_bus_get_fd(sd_bus *bus) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->input_fd == bus->output_fd, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); - return bus->input_fd; + if (bus->state == BUS_CLOSED) + return -ENOTCONN; + + if (bus->inotify_fd >= 0) + return bus->inotify_fd; + + if (bus->input_fd >= 0) + return bus->input_fd; + + return -ENOTCONN; } _public_ int sd_bus_get_events(sd_bus *bus) { int flags = 0; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); - if (!BUS_IS_OPEN(bus->state) && bus->state != BUS_CLOSING) + switch (bus->state) { + + case BUS_UNSET: + case BUS_CLOSED: return -ENOTCONN; - if (bus->state == BUS_OPENING) + case BUS_WATCH_BIND: + flags |= POLLIN; + break; + + case BUS_OPENING: flags |= POLLOUT; - else if (bus->state == BUS_AUTHENTICATING) { + break; + case BUS_AUTHENTICATING: if (bus_socket_auth_needs_write(bus)) flags |= POLLOUT; flags |= POLLIN; + break; - } else if (bus->state == BUS_RUNNING || bus->state == BUS_HELLO) { + case BUS_RUNNING: + case BUS_HELLO: if (bus->rqueue_size <= 0) flags |= POLLIN; if (bus->wqueue_size > 0) flags |= POLLOUT; + break; + + case BUS_CLOSING: + break; + + default: + assert_not_reached("Unknown state"); } return flags; @@ -2200,6 +2265,7 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { struct reply_callback *c; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(timeout_usec, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -2211,39 +2277,45 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { return 1; } - if (bus->state == BUS_CLOSING) { - *timeout_usec = 0; - return 1; - } + switch (bus->state) { - if (bus->state == BUS_AUTHENTICATING) { + case BUS_AUTHENTICATING: *timeout_usec = bus->auth_timeout; return 1; - } - if (bus->state != BUS_RUNNING && bus->state != BUS_HELLO) { - *timeout_usec = (uint64_t) -1; - return 0; - } + case BUS_RUNNING: + case BUS_HELLO: + if (bus->rqueue_size > 0) { + *timeout_usec = 0; + return 1; + } + + c = prioq_peek(bus->reply_callbacks_prioq); + if (!c) { + *timeout_usec = (uint64_t) -1; + return 0; + } + + if (c->timeout_usec == 0) { + *timeout_usec = (uint64_t) -1; + return 0; + } - if (bus->rqueue_size > 0) { + *timeout_usec = c->timeout_usec; + return 1; + + case BUS_CLOSING: *timeout_usec = 0; return 1; - } - c = prioq_peek(bus->reply_callbacks_prioq); - if (!c) { + case BUS_WATCH_BIND: + case BUS_OPENING: *timeout_usec = (uint64_t) -1; return 0; - } - if (c->timeout == 0) { - *timeout_usec = (uint64_t) -1; - return 0; + default: + assert_not_reached("Unknown or unexpected stat"); } - - *timeout_usec = c->timeout; - return 1; } static int process_timeout(sd_bus *bus) { @@ -2251,17 +2323,19 @@ static int process_timeout(sd_bus *bus) { _cleanup_(sd_bus_message_unrefp) sd_bus_message* m = NULL; struct reply_callback *c; sd_bus_slot *slot; + bool is_hello; usec_t n; int r; assert(bus); + assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)); c = prioq_peek(bus->reply_callbacks_prioq); if (!c) return 0; n = now(CLOCK_MONOTONIC); - if (c->timeout > n) + if (c->timeout_usec > n) return 0; r = bus_message_new_synthetic_error( @@ -2277,7 +2351,7 @@ static int process_timeout(sd_bus *bus) { return r; assert_se(prioq_pop(bus->reply_callbacks_prioq) == c); - c->timeout = 0; + c->timeout_usec = 0; ordered_hashmap_remove(bus->reply_callbacks, &c->cookie); c->cookie = 0; @@ -2286,6 +2360,8 @@ static int process_timeout(sd_bus *bus) { bus->iteration_counter++; + is_hello = bus->state == BUS_HELLO && c->callback == hello_callback; + bus->current_message = m; bus->current_slot = sd_bus_slot_ref(slot); bus->current_handler = c->callback; @@ -2303,6 +2379,11 @@ static int process_timeout(sd_bus *bus) { sd_bus_slot_unref(slot); + /* When this is the hello message and it timed out, then make sure to propagate the error up, don't just log + * and ignore the callback handler's return value. */ + if (is_hello) + return r; + return bus_maybe_reply_error(m, r, &error_buffer); } @@ -2318,8 +2399,7 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) { * here (we leave that to the usual handling), we just verify * we don't let any earlier msg through. */ - if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN && - m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) + if (!IN_SET(m->header->type, SD_BUS_MESSAGE_METHOD_RETURN, SD_BUS_MESSAGE_METHOD_ERROR)) return -EIO; if (m->reply_cookie != 1) @@ -2333,16 +2413,13 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; struct reply_callback *c; sd_bus_slot *slot; + bool is_hello; int r; assert(bus); assert(m); - if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN && - m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) - return 0; - - if (bus->is_kernel && (bus->hello_flags & KDBUS_HELLO_MONITOR)) + if (!IN_SET(m->header->type, SD_BUS_MESSAGE_METHOD_RETURN, SD_BUS_MESSAGE_METHOD_ERROR)) return 0; if (m->destination && bus->unique_name && !streq_ptr(m->destination, bus->unique_name)) @@ -2356,7 +2433,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { slot = container_of(c, sd_bus_slot, reply_callback); - if (m->n_fds > 0 && !(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) { + if (m->n_fds > 0 && !bus->accept_fd) { /* If the reply contained a file descriptor which we * didn't want we pass an error instead. */ @@ -2385,11 +2462,13 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { return r; } - if (c->timeout != 0) { + if (c->timeout_usec != 0) { prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); - c->timeout = 0; + c->timeout_usec = 0; } + is_hello = bus->state == BUS_HELLO && c->callback == hello_callback; + bus->current_slot = sd_bus_slot_ref(slot); bus->current_handler = c->callback; bus->current_userdata = slot->userdata; @@ -2405,6 +2484,11 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { sd_bus_slot_unref(slot); + /* When this is the hello message and it failed, then make sure to propagate the error up, don't just log and + * ignore the callback handler's return value. */ + if (is_hello) + return r; + return bus_maybe_reply_error(m, r, &error_buffer); } @@ -2481,7 +2565,7 @@ static int process_builtin(sd_bus *bus, sd_bus_message *m) { assert(bus); assert(m); - if (bus->hello_flags & KDBUS_HELLO_MONITOR) + if (bus->is_monitor) return 0; if (bus->manual_peer_interface) @@ -2539,13 +2623,13 @@ static int process_fd_check(sd_bus *bus, sd_bus_message *m) { * delivered to us later even though we ourselves did not * negotiate it. */ - if (bus->hello_flags & KDBUS_HELLO_MONITOR) + if (bus->is_monitor) return 0; if (m->n_fds <= 0) return 0; - if (bus->hello_flags & KDBUS_HELLO_ACCEPT_FD) + if (bus->accept_fd) return 0; if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL) @@ -2611,7 +2695,7 @@ static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd int r; assert(bus); - assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)); r = process_timeout(bus); if (r != 0) @@ -2640,8 +2724,8 @@ static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd if (r < 0) return r; - *ret = m; - m = NULL; + *ret = TAKE_PTR(m); + return 1; } @@ -2716,9 +2800,9 @@ static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c) if (r < 0) return r; - if (c->timeout != 0) { + if (c->timeout_usec != 0) { prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); - c->timeout = 0; + c->timeout_usec = 0; } ordered_hashmap_remove(bus->reply_callbacks, &c->cookie); @@ -2800,10 +2884,8 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) { bus->exit_triggered = true; (void) bus_exit_now(bus); - if (ret) { - *ret = m; - m = NULL; - } + if (ret) + *ret = TAKE_PTR(m); r = 1; @@ -2823,6 +2905,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit * means *ret is filled in with an unprocessed message. */ assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); /* We don't allow recursively invoking sd_bus_process(). */ @@ -2837,48 +2920,44 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit case BUS_CLOSED: return -ECONNRESET; + case BUS_WATCH_BIND: + r = bus_socket_process_watch_bind(bus); + break; + case BUS_OPENING: r = bus_socket_process_opening(bus); - if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { - bus_enter_closing(bus); - r = 1; - } else if (r < 0) - return r; - if (ret) - *ret = NULL; - return r; + break; case BUS_AUTHENTICATING: r = bus_socket_process_authenticating(bus); - if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { - bus_enter_closing(bus); - r = 1; - } else if (r < 0) - return r; - - if (ret) - *ret = NULL; - - return r; + break; case BUS_RUNNING: case BUS_HELLO: r = process_running(bus, hint_priority, priority, ret); - if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { - bus_enter_closing(bus); - r = 1; - - if (ret) - *ret = NULL; - } + if (r >= 0) + return r; - return r; + /* This branch initializes *ret, hence we don't use the generic error checking below */ + break; case BUS_CLOSING: return process_closing(bus, ret); + + default: + assert_not_reached("Unknown state"); } - assert_not_reached("Unknown state"); + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { + bus_enter_closing(bus); + r = 1; + } else if (r < 0) + return r; + + if (ret) + *ret = NULL; + + return r; } _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) { @@ -2891,7 +2970,7 @@ _public_ int sd_bus_process_priority(sd_bus *bus, int64_t priority, sd_bus_messa static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { struct pollfd p[2] = {}; - int r, e, n; + int r, n; struct timespec ts; usec_t m = USEC_INFINITY; @@ -2903,45 +2982,52 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; - e = sd_bus_get_events(bus); - if (e < 0) - return e; - - if (need_more) - /* The caller really needs some more data, he doesn't - * care about what's already read, or any timeouts - * except its own. */ - e |= POLLIN; - else { - usec_t until; - /* The caller wants to process if there's something to - * process, but doesn't care otherwise */ - - r = sd_bus_get_timeout(bus, &until); - if (r < 0) - return r; - if (r > 0) { - usec_t nw; - nw = now(CLOCK_MONOTONIC); - m = until > nw ? until - nw : 0; - } - } - - if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m)) - m = timeout_usec; + if (bus->state == BUS_WATCH_BIND) { + assert(bus->inotify_fd >= 0); - p[0].fd = bus->input_fd; - if (bus->output_fd == bus->input_fd) { - p[0].events = e; + p[0].events = POLLIN; + p[0].fd = bus->inotify_fd; n = 1; } else { - p[0].events = e & POLLIN; - p[1].fd = bus->output_fd; - p[1].events = e & POLLOUT; - n = 2; + int e; + + e = sd_bus_get_events(bus); + if (e < 0) + return e; + + if (need_more) + /* The caller really needs some more data, he doesn't + * care about what's already read, or any timeouts + * except its own. */ + e |= POLLIN; + else { + usec_t until; + /* The caller wants to process if there's something to + * process, but doesn't care otherwise */ + + r = sd_bus_get_timeout(bus, &until); + if (r < 0) + return r; + if (r > 0) + m = usec_sub_unsigned(until, now(CLOCK_MONOTONIC)); + } + + p[0].fd = bus->input_fd; + if (bus->output_fd == bus->input_fd) { + p[0].events = e; + n = 1; + } else { + p[0].events = e & POLLIN; + p[1].fd = bus->output_fd; + p[1].events = e & POLLOUT; + n = 2; + } } - r = ppoll(p, n, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL); + if (timeout_usec != (uint64_t) -1 && (m == USEC_INFINITY || timeout_usec < m)) + m = timeout_usec; + + r = ppoll(p, n, m == USEC_INFINITY ? NULL : timespec_store(&ts, m), NULL); if (r < 0) return -errno; @@ -2951,6 +3037,7 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { _public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); if (bus->state == BUS_CLOSING) @@ -2969,6 +3056,7 @@ _public_ int sd_bus_flush(sd_bus *bus) { int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); if (bus->state == BUS_CLOSING) @@ -2977,6 +3065,10 @@ _public_ int sd_bus_flush(sd_bus *bus) { if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; + /* We never were connected? Don't hang in inotify for good, as there's no timeout set for it */ + if (bus->state == BUS_WATCH_BIND) + return -EUNATCH; + r = bus_ensure_running(bus); if (r < 0) return r; @@ -3013,6 +3105,7 @@ _public_ int sd_bus_add_filter( sd_bus_slot *s; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(callback, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -3031,11 +3124,78 @@ _public_ int sd_bus_add_filter( return 0; } -_public_ int sd_bus_add_match( +static int add_match_callback( + sd_bus_message *m, + void *userdata, + sd_bus_error *ret_error) { + + sd_bus_slot *match_slot = userdata; + bool failed = false; + int r; + + assert(m); + assert(match_slot); + + sd_bus_slot_ref(match_slot); + + if (sd_bus_message_is_method_error(m, NULL)) { + log_debug_errno(sd_bus_message_get_errno(m), + "Unable to add match %s, failing connection: %s", + match_slot->match_callback.match_string, + sd_bus_message_get_error(m)->message); + + failed = true; + } else + log_debug("Match %s successfully installed.", match_slot->match_callback.match_string); + + if (match_slot->match_callback.install_callback) { + sd_bus *bus; + + bus = sd_bus_message_get_bus(m); + + /* This function has been called as slot handler, and we want to call another slot handler. Let's + * update the slot callback metadata temporarily with our own data, and then revert back to the old + * values. */ + + assert(bus->current_slot == match_slot->match_callback.install_slot); + assert(bus->current_handler == add_match_callback); + assert(bus->current_userdata == userdata); + + bus->current_slot = match_slot; + bus->current_handler = match_slot->match_callback.install_callback; + bus->current_userdata = match_slot->userdata; + + r = match_slot->match_callback.install_callback(m, match_slot->userdata, ret_error); + + bus->current_slot = match_slot->match_callback.install_slot; + bus->current_handler = add_match_callback; + bus->current_userdata = userdata; + + match_slot->match_callback.install_slot = sd_bus_slot_unref(match_slot->match_callback.install_slot); + } else { + if (failed) /* Generic failure handling: destroy the connection */ + bus_enter_closing(sd_bus_message_get_bus(m)); + + r = 1; + } + + if (failed && match_slot->floating) { + bus_slot_disconnect(match_slot); + sd_bus_slot_unref(match_slot); + } + + sd_bus_slot_unref(match_slot); + + return r; +} + +static int bus_add_match_full( sd_bus *bus, sd_bus_slot **slot, + bool asynchronous, const char *match, sd_bus_message_handler_t callback, + sd_bus_message_handler_t install_callback, void *userdata) { struct bus_match_component *components = NULL; @@ -3044,6 +3204,7 @@ _public_ int sd_bus_add_match( int r = 0; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(match, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -3058,31 +3219,40 @@ _public_ int sd_bus_add_match( } s->match_callback.callback = callback; - s->match_callback.cookie = ++bus->match_cookie; + s->match_callback.install_callback = install_callback; if (bus->bus_client) { enum bus_match_scope scope; scope = bus_match_get_scope(components, n_components); - /* Do not install server-side matches for matches - * against the local service, interface or bus - * path. */ + /* Do not install server-side matches for matches against the local service, interface or bus path. */ if (scope != BUS_MATCH_LOCAL) { - if (!bus->is_kernel) { - /* When this is not a kernel transport, we - * store the original match string, so that we - * can use it to remove the match again */ + /* We store the original match string, so that we can use it to remove the match again. */ - s->match_callback.match_string = strdup(match); - if (!s->match_callback.match_string) { - r = -ENOMEM; - goto finish; - } + s->match_callback.match_string = strdup(match); + if (!s->match_callback.match_string) { + r = -ENOMEM; + goto finish; } - r = bus_add_match_internal(bus, s->match_callback.match_string, components, n_components, s->match_callback.cookie); + if (asynchronous) { + r = bus_add_match_internal_async(bus, + &s->match_callback.install_slot, + s->match_callback.match_string, + add_match_callback, + s); + + if (r < 0) + return r; + + /* Make the slot of the match call floating now. We need the reference, but we don't + * want that this match pins the bus object, hence we first create it non-floating, but + * then make it floating. */ + r = sd_bus_slot_set_floating(s->match_callback.install_slot, true); + } else + r = bus_add_match_internal(bus, s->match_callback.match_string); if (r < 0) goto finish; @@ -3107,37 +3277,27 @@ finish: } #if 0 /// UNNEEDED by elogind -int bus_remove_match_by_string( +#endif // 0 +_public_ int sd_bus_add_match( sd_bus *bus, + sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) { - struct bus_match_component *components = NULL; - unsigned n_components = 0; - struct match_callback *c; - int r = 0; - - assert_return(bus, -EINVAL); - assert_return(match, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); - - r = bus_match_parse(match, &components, &n_components); - if (r < 0) - goto finish; - - r = bus_match_find(&bus->match_callbacks, components, n_components, NULL, NULL, &c); - if (r <= 0) - goto finish; - - sd_bus_slot_unref(container_of(c, sd_bus_slot, match_callback)); + return bus_add_match_full(bus, slot, false, match, callback, NULL, userdata); +} -finish: - bus_match_parse_free(components, n_components); +_public_ int sd_bus_add_match_async( + sd_bus *bus, + sd_bus_slot **slot, + const char *match, + sd_bus_message_handler_t callback, + sd_bus_message_handler_t install_callback, + void *userdata) { - return r; + return bus_add_match_full(bus, slot, true, match, callback, install_callback, userdata); } -#endif // 0 bool bus_pid_changed(sd_bus *bus) { assert(bus); @@ -3145,7 +3305,7 @@ bool bus_pid_changed(sd_bus *bus) { /* We don't support people creating a bus connection and * keeping it around over a fork(). Let's complain. */ - return bus->original_pid != getpid(); + return bus->original_pid != getpid_cached(); } static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { @@ -3154,9 +3314,13 @@ static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userd assert(bus); + /* Note that this is called both on input_fd, output_fd as well as inotify_fd events */ + r = sd_bus_process(bus, NULL); - if (r < 0) - return r; + if (r < 0) { + log_debug_errno(r, "Processing of bus failed, closing down: %m"); + bus_enter_closing(bus); + } return 1; } @@ -3168,8 +3332,10 @@ static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) { assert(bus); r = sd_bus_process(bus, NULL); - if (r < 0) - return r; + if (r < 0) { + log_debug_errno(r, "Processing of bus failed, closing down: %m"); + bus_enter_closing(bus); + } return 1; } @@ -3183,38 +3349,45 @@ static int prepare_callback(sd_event_source *s, void *userdata) { assert(bus); e = sd_bus_get_events(bus); - if (e < 0) - return e; + if (e < 0) { + r = e; + goto fail; + } if (bus->output_fd != bus->input_fd) { r = sd_event_source_set_io_events(bus->input_io_event_source, e & POLLIN); if (r < 0) - return r; + goto fail; r = sd_event_source_set_io_events(bus->output_io_event_source, e & POLLOUT); - if (r < 0) - return r; - } else { + } else r = sd_event_source_set_io_events(bus->input_io_event_source, e); - if (r < 0) - return r; - } + if (r < 0) + goto fail; r = sd_bus_get_timeout(bus, &until); if (r < 0) - return r; + goto fail; if (r > 0) { int j; j = sd_event_source_set_time(bus->time_event_source, until); - if (j < 0) - return j; + if (j < 0) { + r = j; + goto fail; + } } r = sd_event_source_set_enabled(bus->time_event_source, r > 0); if (r < 0) - return r; + goto fail; + + return 1; + +fail: + log_debug_errno(r, "Preparing of bus events failed, closing down: %m"); + bus_enter_closing(bus); return 1; } @@ -3230,7 +3403,7 @@ static int quit_callback(sd_event_source *event, void *userdata) { return 1; } -static int attach_io_events(sd_bus *bus) { +int bus_attach_io_events(sd_bus *bus) { int r; assert(bus); @@ -3284,7 +3457,7 @@ static int attach_io_events(sd_bus *bus) { return 0; } -static void detach_io_events(sd_bus *bus) { +static void bus_detach_io_events(sd_bus *bus) { assert(bus); if (bus->input_io_event_source) { @@ -3298,10 +3471,49 @@ static void detach_io_events(sd_bus *bus) { } } +int bus_attach_inotify_event(sd_bus *bus) { + int r; + + assert(bus); + + if (bus->inotify_fd < 0) + return 0; + + if (!bus->event) + return 0; + + if (!bus->inotify_event_source) { + r = sd_event_add_io(bus->event, &bus->inotify_event_source, bus->inotify_fd, EPOLLIN, io_callback, bus); + if (r < 0) + return r; + + r = sd_event_source_set_priority(bus->inotify_event_source, bus->event_priority); + if (r < 0) + return r; + + r = sd_event_source_set_description(bus->inotify_event_source, "bus-inotify"); + } else + r = sd_event_source_set_io_fd(bus->inotify_event_source, bus->inotify_fd); + if (r < 0) + return r; + + return 0; +} + +static void bus_detach_inotify_event(sd_bus *bus) { + assert(bus); + + if (bus->inotify_event_source) { + sd_event_source_set_enabled(bus->inotify_event_source, SD_EVENT_OFF); + bus->inotify_event_source = sd_event_source_unref(bus->inotify_event_source); + } +} + _public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) { int r; assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus->event, -EBUSY); assert(!bus->input_io_event_source); @@ -3338,7 +3550,11 @@ _public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) { if (r < 0) goto fail; - r = attach_io_events(bus); + r = bus_attach_io_events(bus); + if (r < 0) + goto fail; + + r = bus_attach_inotify_event(bus); if (r < 0) goto fail; @@ -3351,11 +3567,13 @@ fail: _public_ int sd_bus_detach_event(sd_bus *bus) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); if (!bus->event) return 0; - detach_io_events(bus); + bus_detach_io_events(bus); + bus_detach_inotify_event(bus); if (bus->time_event_source) { sd_event_source_set_enabled(bus->time_event_source, SD_EVENT_OFF); @@ -3432,7 +3650,6 @@ _public_ int sd_bus_default_system(sd_bus **ret) { return bus_default(sd_bus_open_system, &default_system_bus, ret); } - _public_ int sd_bus_default_user(sd_bus **ret) { #if 0 /// elogind does not support user buses return bus_default(sd_bus_open_user, &default_user_bus, ret); @@ -3442,43 +3659,11 @@ _public_ int sd_bus_default_user(sd_bus **ret) { } _public_ int sd_bus_default(sd_bus **ret) { + int (*bus_open)(sd_bus **) = NULL; + sd_bus **busp; - const char *e; - - /* Let's try our best to reuse another cached connection. If - * the starter bus type is set, connect via our normal - * connection logic, ignoring $DBUS_STARTER_ADDRESS, so that - * we can share the connection with the user/system default - * bus. */ - - e = secure_getenv("DBUS_STARTER_BUS_TYPE"); - if (e) { - if (streq(e, "system")) - return sd_bus_default_system(ret); -#if 0 /// elogind does not support systemd units - else if (STR_IN_SET(e, "user", "session")) - return sd_bus_default_user(ret); -#endif // 0 - } - - /* No type is specified, so we have not other option than to - * use the starter address if it is set. */ - - e = secure_getenv("DBUS_STARTER_ADDRESS"); - if (e) { - - return bus_default(sd_bus_open, &default_starter_bus, ret); - } - - /* Finally, if nothing is set use the cached connection for - * the right scope */ - -#if 0 /// elogind does not support systemd units - if (cg_pid_get_owner_uid(0, NULL) >= 0) - return sd_bus_default_user(ret); - else -#endif // 0 - return sd_bus_default_system(ret); + busp = bus_choose_default(&bus_open); + return bus_default(bus_open, busp, ret); } _public_ int sd_bus_get_tid(sd_bus *b, pid_t *tid) { @@ -3699,44 +3884,34 @@ _public_ int sd_bus_path_decode_many(const char *path, const char *path_template } va_end(list); - free(labels); - labels = NULL; + labels = mfree(labels); return 1; } _public_ int sd_bus_try_close(sd_bus *bus) { - int r; - assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); - if (!bus->is_kernel) - return -EOPNOTSUPP; - - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; - - if (bus->rqueue_size > 0) - return -EBUSY; - - if (bus->wqueue_size > 0) - return -EBUSY; - - r = bus_kernel_try_close(bus); - if (r < 0) - return r; - - sd_bus_close(bus); - return 0; + return -EOPNOTSUPP; } _public_ int sd_bus_get_description(sd_bus *bus, const char **description) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(description, -EINVAL); assert_return(bus->description, -ENXIO); assert_return(!bus_pid_changed(bus), -ECHILD); - *description = bus->description; + if (bus->description) + *description = bus->description; + else if (bus->is_system) + *description = "system"; + else if (bus->is_user) + *description = "user"; + else + *description = NULL; + return 0; } @@ -3759,32 +3934,11 @@ int bus_get_root_path(sd_bus *bus) { } _public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) { - int r; - assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(scope, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); - if (bus->is_kernel) { - _cleanup_free_ char *n = NULL; - const char *dash; - - r = bus_kernel_get_bus_name(bus, &n); - if (r < 0) - return r; - - if (streq(n, "0-system")) { - *scope = "system"; - return 0; - } - - dash = strchr(n, '-'); - if (streq_ptr(dash, "-user")) { - *scope = "user"; - return 0; - } - } - if (bus->is_user) { *scope = "user"; return 0; @@ -3801,6 +3955,7 @@ _public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) { _public_ int sd_bus_get_address(sd_bus *bus, const char **address) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(address, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -3814,6 +3969,7 @@ _public_ int sd_bus_get_address(sd_bus *bus, const char **address) { _public_ int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *mask) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(mask, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -3823,6 +3979,7 @@ _public_ int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *mask) { _public_ int sd_bus_is_bus_client(sd_bus *bus) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); return bus->bus_client; @@ -3830,6 +3987,7 @@ _public_ int sd_bus_is_bus_client(sd_bus *bus) { _public_ int sd_bus_is_server(sd_bus *bus) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); return bus->is_server; @@ -3837,6 +3995,7 @@ _public_ int sd_bus_is_server(sd_bus *bus) { _public_ int sd_bus_is_anonymous(sd_bus *bus) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); return bus->anonymous_auth; @@ -3844,6 +4003,7 @@ _public_ int sd_bus_is_anonymous(sd_bus *bus) { _public_ int sd_bus_is_trusted(sd_bus *bus) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); return bus->trusted; @@ -3851,9 +4011,10 @@ _public_ int sd_bus_is_trusted(sd_bus *bus) { _public_ int sd_bus_is_monitor(sd_bus *bus) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); - return !!(bus->hello_flags & KDBUS_HELLO_MONITOR); + return bus->is_monitor; } static void flush_close(sd_bus *bus) { @@ -3869,7 +4030,7 @@ static void flush_close(sd_bus *bus) { _public_ void sd_bus_default_flush_close(void) { flush_close(default_starter_bus); -#if 0 /// There is no user bus with elogind +#if 0 /// elogind does not support user buses flush_close(default_user_bus); #endif // 0 flush_close(default_system_bus); @@ -3877,6 +4038,7 @@ _public_ void sd_bus_default_flush_close(void) { _public_ int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); /* Turns on exit-on-disconnect, and triggers it immediately if the bus connection was already * disconnected. Note that this is triggered exclusively on disconnections triggered by the server side, never @@ -3889,6 +4051,48 @@ _public_ int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b) { _public_ int sd_bus_get_exit_on_disconnect(sd_bus *bus) { assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); return bus->exit_on_disconnect; } + +_public_ int sd_bus_set_sender(sd_bus *bus, const char *sender) { + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(!bus->bus_client, -EPERM); + assert_return(!sender || service_name_is_valid(sender), -EINVAL); + + return free_and_strdup(&bus->patch_sender, sender); +} + +_public_ int sd_bus_get_sender(sd_bus *bus, const char **ret) { + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(ret, -EINVAL); + + if (!bus->patch_sender) + return -ENODATA; + + *ret = bus->patch_sender; + return 0; +} + +_public_ int sd_bus_get_n_queued_read(sd_bus *bus, uint64_t *ret) { + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(ret, -EINVAL); + + *ret = bus->rqueue_size; + return 0; +} + +_public_ int sd_bus_get_n_queued_write(sd_bus *bus, uint64_t *ret) { + assert_return(bus, -EINVAL); + assert_return(bus = bus_resolve(bus), -ENOPKG); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(ret, -EINVAL); + + *ret = bus->wqueue_size; + return 0; +} diff --git a/src/libelogind/sd-bus/test-bus-error.c b/src/libelogind/sd-bus/test-bus-error.c index f7c889b7c..6d2f59688 100644 --- a/src/libelogind/sd-bus/test-bus-error.c +++ b/src/libelogind/sd-bus/test-bus-error.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "sd-bus.h" diff --git a/src/libelogind/sd-bus/test-bus-introspect.c b/src/libelogind/sd-bus/test-bus-introspect.c index 4425cfae2..00167cb64 100644 --- a/src/libelogind/sd-bus/test-bus-introspect.c +++ b/src/libelogind/sd-bus/test-bus-introspect.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "bus-introspect.h" diff --git a/src/libelogind/sd-bus/test-bus-match.c b/src/libelogind/sd-bus/test-bus-match.c index 29c4529f9..2822a8f82 100644 --- a/src/libelogind/sd-bus/test-bus-match.c +++ b/src/libelogind/sd-bus/test-bus-match.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "bus-match.h" @@ -94,7 +79,7 @@ int main(int argc, char *argv[]) { sd_bus_slot slots[19]; int r; - r = sd_bus_open_system(&bus); + r = sd_bus_open_user(&bus); if (r < 0) return EXIT_TEST_SKIP; @@ -121,7 +106,7 @@ int main(int argc, char *argv[]) { assert_se(sd_bus_message_new_signal(bus, &m, "/foo/bar", "bar.x", "waldo") >= 0); assert_se(sd_bus_message_append(m, "ssssas", "one", "two", "/prefix/three", "prefix.four", 3, "pi", "pa", "po") >= 0); - assert_se(bus_message_seal(m, 1, 0) >= 0); + assert_se(sd_bus_message_seal(m, 1, 0) >= 0); zero(mask); assert_se(bus_match_run(NULL, &root, m) == 0); diff --git a/src/libelogind/sd-bus/test-bus-server.c b/src/libelogind/sd-bus/test-bus-server.c index b6272efc3..31b54e252 100644 --- a/src/libelogind/sd-bus/test-bus-server.c +++ b/src/libelogind/sd-bus/test-bus-server.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include <pthread.h> @@ -80,7 +65,8 @@ static void *server(void *p) { if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Exit")) { - assert_se((sd_bus_can_send(bus, 'h') >= 1) == (c->server_negotiate_unix_fds && c->client_negotiate_unix_fds)); + assert_se((sd_bus_can_send(bus, 'h') >= 1) == + (c->server_negotiate_unix_fds && c->client_negotiate_unix_fds)); r = sd_bus_message_new_method_return(m, &reply); if (r < 0) { diff --git a/src/libelogind/sd-bus/test-bus-signature.c b/src/libelogind/sd-bus/test-bus-signature.c index 4f4fd093b..1ba190919 100644 --- a/src/libelogind/sd-bus/test-bus-signature.c +++ b/src/libelogind/sd-bus/test-bus-signature.c @@ -1,20 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ #include "bus-internal.h" diff --git a/src/libelogind/sd-bus/test-bus-vtable.c b/src/libelogind/sd-bus/test-bus-vtable.c index fd9ad8121..5604aa668 100644 --- a/src/libelogind/sd-bus/test-bus-vtable.c +++ b/src/libelogind/sd-bus/test-bus-vtable.c @@ -8,7 +8,15 @@ #include "sd-bus-vtable.h" +#if 0 /// elogind should support both /run/dbus & /var/run/dbus (per Linux FHS) #define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket" +#else +#if VARRUN_IS_SYMLINK + #define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket" +#else + #define DEFAULT_BUS_PATH "unix:path=/var/run/dbus/system_bus_socket" +#endif // VARRUN_IS_SYMLINK +#endif // 0 struct context { bool quit; |