]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libsystemd/sd-bus/sd-bus.c
tree-wide: define iterator inside of the macro
[thirdparty/systemd.git] / src / libsystemd / sd-bus / sd-bus.c
index 026ac8cb946946c4b6d4596899f31b4f8d0754f2..272b97e17a419a33f5a5270479586968eb240aeb 100644 (file)
@@ -7,6 +7,7 @@
 #include <signal.h>
 #include <stdlib.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
@@ -34,7 +35,7 @@
 #include "hostname-util.h"
 #include "macro.h"
 #include "memory-util.h"
-#include "missing.h"
+#include "missing_syscall.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -283,7 +284,7 @@ _public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) {
         return 0;
 }
 
-_public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) {
+_public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const *argv) {
         _cleanup_strv_free_ char **a = NULL;
         int r;
 
@@ -503,7 +504,6 @@ static int synthesize_connected_signal(sd_bus *bus) {
 }
 
 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",
@@ -536,29 +536,41 @@ static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *e
         assert(IN_SET(bus->state, BUS_HELLO, BUS_CLOSING));
 
         r = sd_bus_message_get_errno(reply);
-        if (r > 0)
-                return -r;
+        if (r > 0) {
+                r = -r;
+                goto fail;
+        }
 
         r = sd_bus_message_read(reply, "s", &s);
         if (r < 0)
-                return r;
+                goto fail;
 
-        if (!service_name_is_valid(s) || s[0] != ':')
-                return -EBADMSG;
+        if (!service_name_is_valid(s) || s[0] != ':') {
+                r = -EBADMSG;
+                goto fail;
+        }
 
         r = free_and_strdup(&bus->unique_name, s);
         if (r < 0)
-                return r;
+                goto fail;
 
         if (bus->state == BUS_HELLO) {
                 bus_set_state(bus, BUS_RUNNING);
 
                 r = synthesize_connected_signal(bus);
                 if (r < 0)
-                        return r;
+                        goto fail;
         }
 
         return 1;
+
+fail:
+        /* When Hello() failed, let's propagate this in two ways: first we return the error immediately here,
+         * which is the propagated up towards the event loop. Let's also invalidate the connection, so that
+         * if the user then calls back into us again we won't wait any longer. */
+
+        bus_set_state(bus, BUS_CLOSING);
+        return r;
 }
 
 static int bus_send_hello(sd_bus *bus) {
@@ -585,7 +597,6 @@ 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;
 
@@ -597,7 +608,7 @@ int bus_start_running(sd_bus *bus) {
          * 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) {
+        ORDERED_HASHMAP_FOREACH(c, bus->reply_callbacks) {
                 if (c->timeout_usec == 0)
                         continue;
 
@@ -967,9 +978,8 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
                         return -EINVAL;
 
                 free_and_replace(b->machine, machine);
-        } else {
+        } else
                 b->machine = mfree(b->machine);
-        }
 
         if (pid) {
                 r = parse_pid(pid, &b->nspid);
@@ -1255,13 +1265,16 @@ _public_ int sd_bus_open(sd_bus **ret) {
 
 int bus_set_address_system(sd_bus *b) {
         const char *e;
+        int r;
+
         assert(b);
 
         e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
-        if (e)
-                return sd_bus_set_address(b, e);
 
-        return sd_bus_set_address(b, DEFAULT_SYSTEM_BUS_ADDRESS);
+        r = sd_bus_set_address(b, e ?: DEFAULT_SYSTEM_BUS_ADDRESS);
+        if (r >= 0)
+                b->is_system = true;
+        return r;
 }
 
 _public_ int sd_bus_open_system_with_description(sd_bus **ret, const char *description) {
@@ -1285,7 +1298,6 @@ _public_ int sd_bus_open_system_with_description(sd_bus **ret, const char *descr
                 return r;
 
         b->bus_client = true;
-        b->is_system = true;
 
         /* Let's do per-method access control on the system bus. We
          * need the caller's UID and capability set for that. */
@@ -1306,29 +1318,34 @@ _public_ int sd_bus_open_system(sd_bus **ret) {
 }
 
 int bus_set_address_user(sd_bus *b) {
-        const char *e;
-        _cleanup_free_ char *ee = NULL, *s = NULL;
+        const char *a;
+        _cleanup_free_ char *_a = NULL;
+        int r;
 
         assert(b);
 
-        e = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
-        if (e)
-                return sd_bus_set_address(b, e);
-
-        e = secure_getenv("XDG_RUNTIME_DIR");
-        if (!e)
-                return -ENOENT;
+        a = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
+        if (!a) {
+                const char *e;
+                _cleanup_free_ char *ee = NULL;
 
-        ee = bus_address_escape(e);
-        if (!ee)
-                return -ENOMEM;
+                e = secure_getenv("XDG_RUNTIME_DIR");
+                if (!e)
+                        return -ENOENT;
 
-        if (asprintf(&s, DEFAULT_USER_BUS_ADDRESS_FMT, ee) < 0)
-                return -ENOMEM;
+                ee = bus_address_escape(e);
+                if (!ee)
+                        return -ENOMEM;
 
-        b->address = TAKE_PTR(s);
+                if (asprintf(&_a, DEFAULT_USER_BUS_ADDRESS_FMT, ee) < 0)
+                        return -ENOMEM;
+                a = _a;
+        }
 
-        return 0;
+        r = sd_bus_set_address(b, a);
+        if (r >= 0)
+                b->is_user = true;
+        return r;
 }
 
 _public_ int sd_bus_open_user_with_description(sd_bus **ret, const char *description) {
@@ -1352,7 +1369,6 @@ _public_ int sd_bus_open_user_with_description(sd_bus **ret, const char *descrip
                 return r;
 
         b->bus_client = true;
-        b->is_user = true;
 
         /* We don't do any per-method access control on the user bus. */
         b->trusted = true;
@@ -1824,7 +1840,7 @@ static int dispatch_wqueue(sd_bus *bus) {
         return ret;
 }
 
-static int bus_read_message(sd_bus *bus, bool hint_priority, int64_t priority) {
+static int bus_read_message(sd_bus *bus) {
         assert(bus);
 
         return bus_socket_read_message(bus);
@@ -1851,17 +1867,13 @@ static void rqueue_drop_one(sd_bus *bus, size_t i) {
         bus->rqueue_size--;
 }
 
-static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **m) {
+static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) {
         int r, ret = 0;
 
         assert(bus);
         assert(m);
         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
-         * anyway, because it's simple... */
-
         for (;;) {
                 if (bus->rqueue_size > 0) {
                         /* Dispatch a queued message */
@@ -1871,7 +1883,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
                 }
 
                 /* Try to read a new message */
-                r = bus_read_message(bus, hint_priority, priority);
+                r = bus_read_message(bus);
                 if (r < 0)
                         return r;
                 if (r == 0) {
@@ -1889,9 +1901,10 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) {
 
         assert_return(m, -EINVAL);
 
-        if (!bus)
-                bus = m->bus;
-
+        if (bus)
+                assert_return(bus = bus_resolve(bus), -ENOPKG);
+        else
+                assert_return(bus = m->bus, -ENOTCONN);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
         if (!BUS_IS_OPEN(bus->state))
@@ -1973,9 +1986,10 @@ _public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destinat
 
         assert_return(m, -EINVAL);
 
-        if (!bus)
-                bus = m->bus;
-
+        if (bus)
+                assert_return(bus = bus_resolve(bus), -ENOPKG);
+        else
+                assert_return(bus = m->bus, -ENOTCONN);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
         if (!BUS_IS_OPEN(bus->state))
@@ -2038,9 +2052,10 @@ _public_ int sd_bus_call_async(
         assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
         assert_return(!m->sealed || (!!callback == !(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)), -EINVAL);
 
-        if (!bus)
-                bus = m->bus;
-
+        if (bus)
+                assert_return(bus = bus_resolve(bus), -ENOPKG);
+        else
+                assert_return(bus = m->bus, -ENOTCONN);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
         if (!BUS_IS_OPEN(bus->state))
@@ -2144,9 +2159,10 @@ _public_ int sd_bus_call(
         bus_assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL, error);
         bus_assert_return(!bus_error_is_dirty(error), -EINVAL, error);
 
-        if (!bus)
-                bus = m->bus;
-
+        if (bus)
+                assert_return(bus = bus_resolve(bus), -ENOPKG);
+        else
+                assert_return(bus = m->bus, -ENOTCONN);
         bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
 
         if (!BUS_IS_OPEN(bus->state)) {
@@ -2224,7 +2240,7 @@ _public_ int sd_bus_call(
                         i++;
                 }
 
-                r = bus_read_message(bus, false, 0);
+                r = bus_read_message(bus);
                 if (r < 0) {
                         if (ERRNO_IS_DISCONNECT(r)) {
                                 bus_enter_closing(bus);
@@ -2273,7 +2289,6 @@ 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);
@@ -2659,7 +2674,7 @@ static int process_builtin(sd_bus *bus, sd_bus_message *m) {
                 r = sd_bus_message_new_method_return(m, &reply);
         else if (streq_ptr(m->member, "GetMachineId")) {
                 sd_id128_t id;
-                char sid[33];
+                char sid[SD_ID128_STRING_MAX];
 
                 r = sd_id128_get_machine(&id);
                 if (r < 0)
@@ -2764,7 +2779,7 @@ static int dispatch_track(sd_bus *bus) {
         return 1;
 }
 
-static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **ret) {
+static int process_running(sd_bus *bus, sd_bus_message **ret) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         int r;
 
@@ -2783,7 +2798,7 @@ static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd
         if (r != 0)
                 goto null_message;
 
-        r = dispatch_rqueue(bus, hint_priority, priority, &m);
+        r = dispatch_rqueue(bus, &m);
         if (r < 0)
                 return r;
         if (!m)
@@ -2969,7 +2984,7 @@ finish:
         return r;
 }
 
-static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **ret) {
+static int bus_process_internal(sd_bus *bus, sd_bus_message **ret) {
         int r;
 
         /* Returns 0 when we didn't do anything. This should cause the
@@ -3009,7 +3024,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
 
         case BUS_RUNNING:
         case BUS_HELLO:
-                r = process_running(bus, hint_priority, priority, ret);
+                r = process_running(bus, ret);
                 if (r >= 0)
                         return r;
 
@@ -3036,11 +3051,11 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
 }
 
 _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
-        return bus_process_internal(bus, false, 0, ret);
+        return bus_process_internal(bus, ret);
 }
 
 _public_ int sd_bus_process_priority(sd_bus *bus, int64_t priority, sd_bus_message **ret) {
-        return bus_process_internal(bus, true, priority, ret);
+        return bus_process_internal(bus, ret);
 }
 
 static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
@@ -3105,8 +3120,15 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
         r = ppoll(p, n, m == USEC_INFINITY ? NULL : timespec_store(&ts, m), NULL);
         if (r < 0)
                 return -errno;
+        if (r == 0)
+                return 0;
+
+        if (p[0].revents & POLLNVAL)
+                return -EBADF;
+        if (n >= 2 && (p[1].revents & POLLNVAL))
+                return -EBADF;
 
-        return r > 0 ? 1 : 0;
+        return 1;
 }
 
 _public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) {
@@ -3664,31 +3686,31 @@ _public_ int sd_bus_detach_event(sd_bus *bus) {
 }
 
 _public_ sd_event* sd_bus_get_event(sd_bus *bus) {
-        assert_return(bus, NULL);
+        assert_return(bus = bus_resolve(bus), NULL);
 
         return bus->event;
 }
 
 _public_ sd_bus_message* sd_bus_get_current_message(sd_bus *bus) {
-        assert_return(bus, NULL);
+        assert_return(bus = bus_resolve(bus), NULL);
 
         return bus->current_message;
 }
 
 _public_ sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus) {
-        assert_return(bus, NULL);
+        assert_return(bus = bus_resolve(bus), NULL);
 
         return bus->current_slot;
 }
 
 _public_ sd_bus_message_handler_t sd_bus_get_current_handler(sd_bus *bus) {
-        assert_return(bus, NULL);
+        assert_return(bus = bus_resolve(bus), NULL);
 
         return bus->current_handler;
 }
 
 _public_ void* sd_bus_get_current_userdata(sd_bus *bus) {
-        assert_return(bus, NULL);
+        assert_return(bus = bus_resolve(bus), NULL);
 
         return bus->current_userdata;
 }
@@ -4005,7 +4027,6 @@ _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);
@@ -4194,3 +4215,27 @@ _public_ int sd_bus_get_close_on_exit(sd_bus *bus) {
 
         return bus->close_on_exit;
 }
+
+_public_ int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m) {
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(bus = bus_resolve(bus), -ENOPKG);
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (!BUS_IS_OPEN(bus->state))
+                return -ENOTCONN;
+
+        /* Re-enqueue a message for reading. This is primarily useful for PolicyKit-style authentication,
+         * where we accept a message, then determine we need to interactively authenticate the user, and then
+         * we want to process the message again. */
+
+        r = bus_rqueue_make_room(bus);
+        if (r < 0)
+                return r;
+
+        bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(m, bus);
+        return 0;
+}