X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;ds=sidebyside;f=src%2Flibsystemd-bus%2Fbus-util.c;h=30ee67e85050ab63d96f31653b9b6272e6db6fbc;hb=6203e07a83214a55bb1f88508fcda2005c601dea;hp=7a2197509254500f007b37eda785a49d69afd18d;hpb=5fd38859b30b95008e483109578c7fef2b5072f3;p=elogind.git diff --git a/src/libsystemd-bus/bus-util.c b/src/libsystemd-bus/bus-util.c index 7a2197509..30ee67e85 100644 --- a/src/libsystemd-bus/bus-util.c +++ b/src/libsystemd-bus/bus-util.c @@ -20,6 +20,7 @@ ***/ #include +#include #include "util.h" #include "strv.h" @@ -34,30 +35,48 @@ #include "bus-util.h" #include "bus-internal.h" -static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { +static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { sd_event *e = userdata; assert(bus); assert(m); assert(e); - sd_event_request_quit(e); + sd_event_exit(e, 0); return 1; } -int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) { +int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) { _cleanup_free_ char *match = NULL; + const char *unique; int r; assert(e); assert(bus); assert(name); - r = asprintf(&match, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameLost',arg0='%s'", name); + /* We unregister the name here and then wait for the + * NameOwnerChanged signal for this event to arrive before we + * quit. We do this in order to make sure that any queued + * requests are still processed before we really exit. */ + + r = sd_bus_get_unique_name(bus, &unique); if (r < 0) return r; - r = sd_bus_add_match(bus, match, quit_callback, e); + r = asprintf(&match, + "sender='org.freedesktop.DBus'," + "type='signal'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'," + "path='/org/freedesktop/DBus'," + "arg0='%s'," + "arg1='%s'," + "arg2=''", name, unique); + if (r < 0) + return -ENOMEM; + + r = sd_bus_add_match(bus, match, name_owner_change_callback, e); if (r < 0) return r; @@ -65,15 +84,12 @@ int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) { if (r < 0) return r; - if (r != SD_BUS_NAME_RELEASED) - return -EIO; - return 0; } int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) { bool exiting = false; - int r; + int r, code; assert(e); assert(bus); @@ -92,7 +108,7 @@ int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t return r; if (r == 0 && !exiting) { - r = bus_async_unregister_and_quit(e, bus, name); + r = bus_async_unregister_and_exit(e, bus, name); if (r < 0) return r; @@ -100,7 +116,11 @@ int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t } } - return 0; + r = sd_event_get_exit_code(e, &code); + if (r < 0) + return r; + + return code; } int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) { @@ -137,7 +157,7 @@ int bus_verify_polkit( bool *_challenge, sd_bus_error *e) { - const char *sender; + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; uid_t uid; int r; @@ -145,11 +165,11 @@ int bus_verify_polkit( assert(m); assert(action); - sender = sd_bus_message_get_sender(m); - if (!sender) - return -EBADMSG; + r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; - r = sd_bus_get_owner_uid(bus, sender, &uid); + r = sd_bus_creds_get_uid(creds, &uid); if (r < 0) return r; @@ -160,6 +180,11 @@ int bus_verify_polkit( else { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; int authorized = false, challenge = false; + const char *sender; + + sender = sd_bus_message_get_sender(m); + if (!sender) + return -EBADMSG; r = sd_bus_call_method( bus, @@ -271,8 +296,9 @@ int bus_verify_polkit_async( #ifdef ENABLE_POLKIT _cleanup_bus_message_unref_ sd_bus_message *pk = NULL; AsyncPolkitQuery *q; -#endif const char *sender; +#endif + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; uid_t uid; int r; @@ -319,17 +345,21 @@ int bus_verify_polkit_async( } #endif - sender = sd_bus_message_get_sender(m); - if (!sender) - return -EBADMSG; + r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; - r = sd_bus_get_owner_uid(bus, sender, &uid); + r = sd_bus_creds_get_uid(creds, &uid); if (r < 0) return r; if (uid == 0) return 1; + #ifdef ENABLE_POLKIT + sender = sd_bus_message_get_sender(m); + if (!sender) + return -EBADMSG; r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func); if (r < 0) @@ -428,21 +458,43 @@ int bus_open_system_systemd(sd_bus **_bus) { if (geteuid() != 0) return sd_bus_open_system(_bus); - /* If we are root, then let's talk directly to the system - * instance, instead of going via the bus */ + /* If we are root and kdbus is not available, then let's talk + * directly to the system instance, instead of going via the + * bus */ +#ifdef ENABLE_KDBUS r = sd_bus_new(&bus); if (r < 0) return r; - r = sd_bus_set_address(bus, "unix:path=/run/systemd/private"); + r = sd_bus_set_address(bus, "kernel:path=/dev/kdbus/0-system/bus"); if (r < 0) return r; + bus->bus_client = true; + r = sd_bus_start(bus); + if (r >= 0) { + *_bus = bus; + bus = NULL; + return 0; + } + + bus = sd_bus_unref(bus); +#endif + + r = sd_bus_new(&bus); + if (r < 0) + return r; + + r = sd_bus_set_address(bus, "unix:path=/run/systemd/private"); if (r < 0) return r; + r = sd_bus_start(bus); + if (r < 0) + return sd_bus_open_system(_bus); + r = bus_check_peercred(bus); if (r < 0) return r; @@ -455,33 +507,53 @@ int bus_open_system_systemd(sd_bus **_bus) { int bus_open_user_systemd(sd_bus **_bus) { _cleanup_bus_unref_ sd_bus *bus = NULL; - _cleanup_free_ char *p = NULL; + _cleanup_free_ char *ee = NULL; const char *e; int r; - /* If we are supposed to talk to the instance, try via - * XDG_RUNTIME_DIR first, then fallback to normal bus - * access */ + /* Try via kdbus first, and then directly */ assert(_bus); - e = secure_getenv("XDG_RUNTIME_DIR"); - if (e) { - if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) - return -ENOMEM; - } - +#ifdef ENABLE_KDBUS r = sd_bus_new(&bus); if (r < 0) return r; - r = sd_bus_set_address(bus, p); + if (asprintf(&bus->address, "kernel:path=/dev/kdbus/%lu-user/bus", (unsigned long) getuid()) < 0) + return -ENOMEM; + + bus->bus_client = true; + + r = sd_bus_start(bus); + if (r >= 0) { + *_bus = bus; + bus = NULL; + return 0; + } + + bus = sd_bus_unref(bus); +#endif + + e = secure_getenv("XDG_RUNTIME_DIR"); + if (!e) + return sd_bus_open_system(_bus); + + ee = bus_address_escape(e); + if (!ee) + return -ENOMEM; + + r = sd_bus_new(&bus); if (r < 0) return r; + bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL); + if (!bus->address) + return -ENOMEM; + r = sd_bus_start(bus); if (r < 0) - return r; + return sd_bus_open_system(_bus); r = bus_check_peercred(bus); if (r < 0) @@ -878,7 +950,8 @@ int bus_map_all_properties(sd_bus *bus, assert(path); assert(map); - r = sd_bus_call_method( bus, + r = sd_bus_call_method( + bus, destination, path, "org.freedesktop.DBus.Properties",