chiark / gitweb /
tree-wide: drop 'This file is part of systemd' blurb
[elogind.git] / src / libelogind / sd-bus / sd-bus.c
index 0ca29b98dce7c9650b45d2cc05edf78eb784fd61..0b4a498a7f00f888f0c0be8a3737d64c21e5dff3 100644 (file)
@@ -1,29 +1,16 @@
 /* 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"
@@ -50,6 +37,7 @@
 #include "macro.h"
 #include "missing.h"
 #include "parse-util.h"
+//#include "process-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "util.h"
@@ -79,11 +67,67 @@ 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 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);
 
@@ -120,7 +164,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);
@@ -159,6 +203,7 @@ static void bus_free(sd_bus *b) {
         free(b->machine);
         free(b->cgroup_root);
         free(b->description);
+        free(b->patch_sender);
 
         free(b->exec_path);
         strv_free(b->exec_argv);
@@ -184,60 +229,52 @@ static void bus_free(sd_bus *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->inotify_fd = -1;
-        r->message_version = 1;
-        r->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
-        r->accept_fd = true;
-        r->original_pid = getpid_cached();
-        r->n_groups = (size_t) -1;
-
-        assert_se(pthread_mutex_init(&r->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);
+        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(&b->memfd_cache_mutex, NULL) == 0);
+
+        /* 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);
@@ -249,36 +286,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;
@@ -287,36 +320,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);
 
-        bus->is_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);
 
-        bus->accept_fd = b;
+        bus->accept_fd = !!b;
         return 0;
 }
 
 _public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) {
         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);
 
         /* 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;
+        bus->attach_timestamp = !!b;
 
         return 0;
 }
 
 _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) {
         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);
@@ -331,6 +368,7 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) {
 
 _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);
@@ -342,6 +380,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);
 
@@ -351,6 +390,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);
 
@@ -360,6 +400,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);
 
@@ -368,6 +409,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;
@@ -376,6 +418,7 @@ _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;
@@ -383,15 +426,17 @@ _public_ int sd_bus_get_allow_interactive_authorization(sd_bus *bus) {
 
 _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;
+        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;
@@ -399,15 +444,17 @@ _public_ int sd_bus_get_watch_bind(sd_bus *bus) {
 
 _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;
+        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;
@@ -450,8 +497,7 @@ static int synthesize_connected_signal(sd_bus *bus) {
 
         /* Insert at the very front */
         memmove(bus->rqueue + 1, bus->rqueue, sizeof(sd_bus_message*) * bus->rqueue_size);
-        bus->rqueue[0] = m;
-        m = NULL;
+        bus->rqueue[0] = TAKE_PTR(m);
         bus->rqueue_size++;
 
         return 0;
@@ -501,9 +547,9 @@ 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_set_state(bus, BUS_RUNNING);
@@ -575,8 +621,8 @@ int bus_start_running(sd_bus *bus) {
 
 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);
@@ -604,16 +650,12 @@ static int parse_address_key(const char **p, const char *key, char **value) {
                         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;
@@ -640,8 +682,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;
 }
@@ -1025,6 +1066,13 @@ 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) {
         int r;
 
@@ -1034,6 +1082,8 @@ static int bus_start_address(sd_bus *b) {
                 bus_close_io_fds(b);
                 bus_close_inotify_fd(b);
 
+                bus_kill_exec(b);
+
                 /* If you provide multiple different bus-addresses, we
                  * try all of them in order and use the first one that
                  * succeeds. */
@@ -1115,6 +1165,7 @@ _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);
 
@@ -1138,9 +1189,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);
@@ -1152,21 +1203,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);
+                        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 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);
@@ -1175,7 +1226,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;
 
@@ -1187,14 +1238,14 @@ _public_ int sd_bus_open(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;
+_public_ int sd_bus_open(sd_bus **ret) {
+        return sd_bus_open_with_description(ret, NULL);
 }
 
 int bus_set_address_system(sd_bus *b) {
@@ -1208,8 +1259,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);
@@ -1218,9 +1269,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;
@@ -1233,14 +1290,14 @@ _public_ int sd_bus_open_system(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;
+_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
@@ -1265,16 +1322,15 @@ int bus_set_address_user(sd_bus *b) {
         if (asprintf(&s, DEFAULT_USER_BUS_ADDRESS_FMT, ee) < 0)
                 return -ENOMEM;
 
-        b->address = s;
-        s = NULL;
+        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);
@@ -1283,9 +1339,15 @@ _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)
-                goto fail;
+                return r;
 
         b->bus_client = true;
         b->is_user = true;
@@ -1297,14 +1359,14 @@ _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;
+_public_ int sd_bus_open_user(sd_bus **ret) {
+        return sd_bus_open_user_with_description(ret, NULL);
 #else
         return sd_bus_open_system(ret);
 #endif // 0
@@ -1312,7 +1374,7 @@ fail:
 
 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);
@@ -1324,7 +1386,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 */
@@ -1343,47 +1405,44 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) {
                         return -ENOMEM;
         }
 
-        b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=--,argv3=", e, ",argv4=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);
@@ -1392,48 +1451,43 @@ int bus_set_address_system_machine(sd_bus *b, const char *machine) {
         if (!e)
                 return -ENOMEM;
 
-        b->address = strjoin("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)
@@ -1441,6 +1495,9 @@ _public_ void sd_bus_close(sd_bus *bus) {
         if (bus_pid_changed(bus))
                 return;
 
+        /* Don't leave ssh hanging around */
+        bus_kill_exec(bus);
+
         bus_set_state(bus, BUS_CLOSED);
 
         sd_bus_detach_event(bus);
@@ -1454,10 +1511,12 @@ _public_ void sd_bus_close(sd_bus *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);
 
@@ -1474,7 +1533,6 @@ void bus_enter_closing(sd_bus *bus) {
 }
 
 _public_ sd_bus *sd_bus_ref(sd_bus *bus) {
-
         if (!bus)
                 return NULL;
 
@@ -1493,13 +1551,12 @@ _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);
@@ -1507,6 +1564,7 @@ _public_ int sd_bus_is_open(sd_bus *bus) {
 
 _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;
@@ -1516,6 +1574,7 @@ _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);
 
@@ -1540,6 +1599,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);
 
@@ -1552,6 +1612,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);
 
@@ -1566,6 +1628,12 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
         if (timeout == 0)
                 timeout = BUS_DEFAULT_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);
 }
 
@@ -1609,7 +1677,7 @@ int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) {
         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);
@@ -1644,7 +1712,7 @@ static int dispatch_wqueue(sd_bus *bus) {
 
         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)
@@ -1723,7 +1791,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;
 
@@ -1768,7 +1836,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
         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);
@@ -1808,10 +1876,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;
 
@@ -2018,7 +2082,7 @@ _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;
 
@@ -2136,6 +2200,7 @@ 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);
 
@@ -2155,6 +2220,7 @@ _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);
 
         switch (bus->state) {
@@ -2200,6 +2266,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);
 
@@ -2658,8 +2725,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;
         }
 
@@ -2818,10 +2885,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;
 
@@ -2841,6 +2906,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(). */
@@ -2972,6 +3038,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)
@@ -2990,6 +3057,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)
@@ -3038,6 +3106,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);
 
@@ -3136,6 +3205,7 @@ static int bus_add_match_full(
         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);
 
@@ -3168,13 +3238,21 @@ static int bus_add_match_full(
                                 goto finish;
                         }
 
-                        if (asynchronous)
+                        if (asynchronous) {
                                 r = bus_add_match_internal_async(bus,
                                                                  &s->match_callback.install_slot,
                                                                  s->match_callback.match_string,
                                                                  add_match_callback,
                                                                  s);
-                        else
+
+                                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;
@@ -3436,6 +3514,7 @@ _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);
@@ -3489,6 +3568,7 @@ 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;
@@ -3571,7 +3651,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);
@@ -3581,40 +3660,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 user instances
-        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) {
@@ -3841,6 +3891,7 @@ _public_ int sd_bus_path_decode_many(const char *path, const char *path_template
 
 _public_ int sd_bus_try_close(sd_bus *bus) {
         assert_return(bus, -EINVAL);
+        assert_return(bus = bus_resolve(bus), -ENOPKG);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
         return -EOPNOTSUPP;
@@ -3848,11 +3899,20 @@ _public_ int sd_bus_try_close(sd_bus *bus) {
 
 _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;
 }
 
@@ -3876,6 +3936,7 @@ int bus_get_root_path(sd_bus *bus) {
 
 _public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) {
         assert_return(bus, -EINVAL);
+        assert_return(bus = bus_resolve(bus), -ENOPKG);
         assert_return(scope, -EINVAL);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
@@ -3895,6 +3956,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);
 
@@ -3908,6 +3970,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);
 
@@ -3917,6 +3980,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;
@@ -3924,6 +3988,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;
@@ -3931,6 +3996,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;
@@ -3938,6 +4004,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;
@@ -3945,6 +4012,7 @@ _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->is_monitor;
@@ -3971,6 +4039,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
@@ -3983,6 +4052,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;
+}