From 0f8bd8debb0ff7f5bff7738841931f6c41e40bc1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 30 Oct 2013 13:52:40 +0100 Subject: [PATCH] bus: move ssh support into public API of libsystem-bus --- src/cgroups-agent/cgroups-agent.c | 2 +- src/fsck/fsck.c | 2 +- src/initctl/initctl.c | 2 +- src/libsystemd-bus/bus-internal.c | 26 +++++++++ src/libsystemd-bus/bus-internal.h | 2 + src/libsystemd-bus/bus-util.c | 92 ++++++++----------------------- src/libsystemd-bus/bus-util.h | 3 +- src/libsystemd-bus/sd-bus.c | 36 ++++++++++++ src/machine/machinectl.c | 2 +- src/systemd/sd-bus.h | 3 +- src/update-utmp/update-utmp.c | 2 +- 11 files changed, 95 insertions(+), 77 deletions(-) diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c index 256de1f506..d8ae55a313 100644 --- a/src/cgroups-agent/cgroups-agent.c +++ b/src/cgroups-agent/cgroups-agent.c @@ -44,7 +44,7 @@ int main(int argc, char *argv[]) { * this to avoid an activation loop when we start dbus when we * are called when the dbus service is shut down. */ - r = bus_connect_system(&bus); + r = bus_open_system_systemd(&bus); if (r < 0) { log_warning("Failed to get D-Bus connection: %s", strerror(-r)); return EXIT_FAILURE; diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index 5c21c7e41f..3164d6899c 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -50,7 +50,7 @@ static void start_target(const char *target) { assert(target); - r = bus_connect_system(&bus); + r = bus_open_system_systemd(&bus); if (r < 0) { log_error("Failed to get D-Bus connection: %s", strerror(-r)); return; diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c index 3c5986171f..0000d6ccd4 100644 --- a/src/initctl/initctl.c +++ b/src/initctl/initctl.c @@ -329,7 +329,7 @@ static int server_init(Server *s, unsigned n_sockets) { s->n_fifos ++; } - r = bus_connect_system(&s->bus); + r = bus_open_system_systemd(&s->bus); if (r < 0) { log_error("Failed to get D-Bus connection: %s", strerror(-r)); r = -EIO; diff --git a/src/libsystemd-bus/bus-internal.c b/src/libsystemd-bus/bus-internal.c index 942ac2b953..0bea8cac49 100644 --- a/src/libsystemd-bus/bus-internal.c +++ b/src/libsystemd-bus/bus-internal.c @@ -277,3 +277,29 @@ const char *bus_message_type_to_string(uint8_t u) { else return NULL; } + +char *bus_address_escape(const char *v) { + const char *a; + char *r, *b; + + r = new(char, strlen(v)*3+1); + if (!r) + return NULL; + + for (a = v, b = r; *a; a++) { + + if ((*a >= '0' && *a <= '9') || + (*a >= 'a' && *a <= 'z') || + (*a >= 'A' && *a <= 'Z') || + strchr("_-/.", *a)) + *(b++) = *a; + else { + *(b++) = '%'; + *(b++) = hexchar(*a >> 4); + *(b++) = hexchar(*a & 0xF); + } + } + + *b = 0; + return r; +} diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h index 5f8298bbb1..2ae7961915 100644 --- a/src/libsystemd-bus/bus-internal.h +++ b/src/libsystemd-bus/bus-internal.h @@ -289,6 +289,8 @@ int bus_next_address(sd_bus *bus); bool bus_pid_changed(sd_bus *bus); +char *bus_address_escape(const char *v); + #define OBJECT_PATH_FOREACH_PREFIX(prefix, path) \ for (char *_slash = ({ strcpy((prefix), (path)); streq((prefix), "/") ? NULL : strrchr((prefix), '/'); }) ; \ _slash && !(_slash[(_slash) == (prefix)] = 0); \ diff --git a/src/libsystemd-bus/bus-util.c b/src/libsystemd-bus/bus-util.c index 6a2fb04a77..53be009be2 100644 --- a/src/libsystemd-bus/bus-util.c +++ b/src/libsystemd-bus/bus-util.c @@ -380,26 +380,22 @@ void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) { } static int bus_check_peercred(sd_bus *c) { - int fd; struct ucred ucred; socklen_t l; + int fd; assert(c); fd = sd_bus_get_fd(c); - - assert(fd >= 0); + if (fd < 0) + return fd; l = sizeof(struct ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) { - log_error("SO_PEERCRED failed: %m"); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) return -errno; - } - if (l != sizeof(struct ucred)) { - log_error("SO_PEERCRED returned wrong size."); + if (l != sizeof(struct ucred)) return -E2BIG; - } if (ucred.uid != 0 && ucred.uid != geteuid()) return -EPERM; @@ -407,79 +403,37 @@ static int bus_check_peercred(sd_bus *c) { return 1; } -int bus_connect_system(sd_bus **_bus) { - sd_bus *bus = NULL; +int bus_open_system_systemd(sd_bus **_bus) { + _cleanup_bus_unref_ sd_bus *bus = NULL; int r; - bool private = true; assert(_bus); - if (geteuid() == 0) { - /* If we are root, then let's talk directly to the - * system instance, instead of going via the bus */ - - 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 r; - - } else { - r = sd_bus_open_system(&bus); - if (r < 0) - return r; - - private = false; - } - - if (private) { - r = bus_check_peercred(bus); - if (r < 0) { - sd_bus_unref(bus); - - return -EACCES; - } - } - - *_bus = bus; - return 0; -} - -int bus_connect_system_ssh(const char *host, sd_bus **_bus) { - sd_bus *bus; - char *p = NULL; - int r; + if (geteuid() != 0) + return sd_bus_open_system(_bus); - assert(_bus); - assert(host); - - asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host); - if (!p) - return -ENOMEM; + /* If we are root, then let's talk directly to the system + * instance, instead of going via the bus */ - r = sd_bus_new(&bus); - if (r < 0) - return r; + r = sd_bus_new(&bus); + if (r < 0) + return r; - r = sd_bus_set_address(bus, p); - if (r < 0) - return r; + r = sd_bus_set_address(bus, "unix:path=/run/systemd/private"); + if (r < 0) + return r; - r = sd_bus_set_bus_client(bus, true); - if (r < 0) - return r; + r = sd_bus_start(bus); + if (r < 0) + return r; - r = sd_bus_start(bus); + r = bus_check_peercred(bus); if (r < 0) return r; *_bus = bus; + bus = NULL; + return 0; } diff --git a/src/libsystemd-bus/bus-util.h b/src/libsystemd-bus/bus-util.h index 5ddab2c11b..46e10b3c1d 100644 --- a/src/libsystemd-bus/bus-util.h +++ b/src/libsystemd-bus/bus-util.h @@ -37,8 +37,7 @@ int bus_verify_polkit(sd_bus *bus, sd_bus_message *m, const char *action, bool i int bus_verify_polkit_async(sd_bus *bus, Hashmap **registry, sd_bus_message *m, const char *action, bool interactive, sd_bus_error *error, sd_bus_message_handler_t callback, void *userdata); void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry); -int bus_connect_system(sd_bus **_bus); -int bus_connect_system_ssh(const char *host, sd_bus **_bus); +int bus_open_system_systemd(sd_bus **_bus); int bus_generic_print_property(const char *name, sd_bus_message *property, bool all); diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index 55d964ed8f..383b035b7e 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -1033,6 +1033,42 @@ fail: return r; } +int sd_bus_open_system_remote(const char *host, sd_bus **ret) { + _cleanup_free_ char *e = NULL; + char *p = NULL; + sd_bus *bus; + int r; + + assert_return(host, -EINVAL); + assert_return(ret, -EINVAL); + + e = bus_address_escape(host); + if (!e) + return -ENOMEM; + + p = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", NULL); + if (!p) + return -ENOMEM; + + r = sd_bus_new(&bus); + if (r < 0) { + free(p); + return r; + } + + bus->address = p; + bus->bus_client = true; + + r = sd_bus_start(bus); + if (r < 0) { + bus_free(bus); + return r; + } + + *ret = bus; + return 0; +} + void sd_bus_close(sd_bus *bus) { if (!bus) return; diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 8795565f8e..241e360d49 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -759,7 +759,7 @@ int main(int argc, char*argv[]) { if (arg_transport == TRANSPORT_NORMAL) r = sd_bus_open_system(&bus); else if (arg_transport == TRANSPORT_SSH) - r = bus_connect_system_ssh(arg_host, &bus); + r = sd_bus_open_system_remote(arg_host, &bus); else assert_not_reached("Uh, invalid transport..."); if (r < 0) { diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index aa8caee70f..7b6c86dd39 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -58,8 +58,9 @@ typedef int (*sd_bus_node_enumerator_t) (sd_bus *bus, const char *path, char *** /* Connections */ -int sd_bus_open_system(sd_bus **ret); int sd_bus_open_user(sd_bus **ret); +int sd_bus_open_system(sd_bus **ret); +int sd_bus_open_system_remote(const char *host, sd_bus **ret); int sd_bus_new(sd_bus **ret); int sd_bus_set_address(sd_bus *bus, const char *address); diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c index f5c143d39d..61db1e96d3 100644 --- a/src/update-utmp/update-utmp.c +++ b/src/update-utmp/update-utmp.c @@ -299,7 +299,7 @@ int main(int argc, char *argv[]) { errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT) log_error("Failed to connect to audit log: %m"); #endif - r = bus_connect_system(&c.bus); + r = bus_open_system_systemd(&c.bus); if (r < 0) { log_error("Failed to get D-Bus connection: %s", strerror(-r)); r = -EIO; -- 2.34.1