chiark / gitweb /
sd-bus: support connecting to remote hosts, directly into containers
authorLennart Poettering <lennart@poettering.net>
Wed, 2 Jul 2014 23:17:26 +0000 (01:17 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 2 Jul 2014 23:17:26 +0000 (01:17 +0200)
systemctl -H root@foobar:waldi

will now show a list of services running on container "waldi" on host
"foobar", using "root" for authenticating at "foobar".

Since entereing a container requires priviliges, this will only work
correctly for root logins.

src/bus-proxyd/bus-proxyd.c
src/libsystemd/sd-bus/sd-bus.c
src/machine/machined-dbus.c
src/shared/util.c
src/shared/util.h

index 3f095e0..79dbdcf 100644 (file)
@@ -47,7 +47,7 @@
 #include "capability.h"
 #include "bus-policy.h"
 
-static const char *arg_address = DEFAULT_SYSTEM_BUS_PATH;
+static char *arg_address = NULL;
 static char *arg_command_line_buffer = NULL;
 static bool arg_drop_privileges = false;
 static char **arg_configuration = NULL;
@@ -60,8 +60,9 @@ static int help(void) {
                "     --version            Show package version\n"
                "     --drop-privileges    Drop privileges\n"
                "     --configuration=PATH Configuration file or directory\n"
+               "     --machine=MACHINE    Connect to specified machine\n"
                "     --address=ADDRESS    Connect to the bus specified by ADDRESS\n"
-               "                         (default: " KERNEL_SYSTEM_BUS_PATH ")\n",
+               "                          (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
                program_invocation_short_name);
 
         return 0;
@@ -74,6 +75,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_ADDRESS,
                 ARG_DROP_PRIVILEGES,
                 ARG_CONFIGURATION,
+                ARG_MACHINE,
         };
 
         static const struct option options[] = {
@@ -82,7 +84,8 @@ static int parse_argv(int argc, char *argv[]) {
                 { "address",         required_argument, NULL, ARG_ADDRESS         },
                 { "drop-privileges", no_argument,       NULL, ARG_DROP_PRIVILEGES },
                 { "configuration",   required_argument, NULL, ARG_CONFIGURATION   },
-                { NULL,              0,                 NULL, 0                   },
+                { "machine",         required_argument, NULL, ARG_MACHINE         },
+                {},
         };
 
         int c, r;
@@ -103,9 +106,17 @@ static int parse_argv(int argc, char *argv[]) {
                         puts(SYSTEMD_FEATURES);
                         return 0;
 
-                case ARG_ADDRESS:
-                        arg_address = optarg;
+                case ARG_ADDRESS: {
+                        char *a;
+
+                        a = strdup(optarg);
+                        if (!a)
+                                return log_oom();
+
+                        free(arg_address);
+                        arg_address = a;
                         break;
+                }
 
                 case ARG_DROP_PRIVILEGES:
                         arg_drop_privileges = true;
@@ -117,6 +128,28 @@ static int parse_argv(int argc, char *argv[]) {
                                 return log_oom();
                         break;
 
+                case ARG_MACHINE: {
+                        _cleanup_free_ char *e = NULL;
+                        char *a;
+
+                        e = bus_address_escape(optarg);
+                        if (!e)
+                                return log_oom();
+
+#ifdef ENABLE_KDBUS
+                        a = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL);
+#else
+                        a = strjoin("x-container-unix:machine=", e, NULL);
+#endif
+                        if (!a)
+                                return log_oom();
+
+                        free(arg_address);
+                        arg_address = a;
+
+                        break;
+                }
+
                 case '?':
                         return -EINVAL;
 
@@ -129,12 +162,17 @@ static int parse_argv(int argc, char *argv[]) {
          * we'll write who we are talking to into it, so that "ps" is
          * explanatory */
         arg_command_line_buffer = argv[optind];
-        if (argc > optind + 1 ||
-            (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) {
+        if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
                 log_error("Too many arguments");
                 return -EINVAL;
         }
 
+        if (!arg_address) {
+                arg_address = strdup(DEFAULT_SYSTEM_BUS_PATH);
+                if (!arg_address)
+                        return log_oom();
+        }
+
         return 1;
 }
 
@@ -1439,9 +1477,12 @@ int main(int argc, char *argv[]) {
 finish:
         sd_bus_flush(a);
         sd_bus_flush(b);
+        sd_bus_close(a);
+        sd_bus_close(b);
 
         policy_free(&policy);
         strv_free(arg_configuration);
+        free(arg_address);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index eb267d4..c25375c 100644 (file)
@@ -1209,15 +1209,38 @@ fail:
 
 int bus_set_address_system_remote(sd_bus *b, const char *host) {
         _cleanup_free_ char *e = NULL;
+        char *m = NULL, *c = NULL;
 
         assert(b);
         assert(host);
 
-        e = bus_address_escape(host);
-        if (!e)
-                return -ENOMEM;
+        /* Let's see if we shall enter some container */
+        m = strchr(host, ':');
+        if (m) {
+                m++;
+
+                /* 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)) {
+                        char *t;
+
+                        /* Cut out the host part */
+                        t = strndupa(host, m - host - 1);
+                        e = bus_address_escape(t);
+                        if (!e)
+                                return -ENOMEM;
+
+                        c = strappenda(",argv4=--machine=", m);
+                }
+        }
+
+        if (!e) {
+                e = bus_address_escape(host);
+                if (!e)
+                        return -ENOMEM;
+        }
 
-        b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", NULL);
+        b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", c, NULL);
         if (!b->address)
                 return -ENOMEM;
 
index 0078a27..6f8ba47 100644 (file)
 #include "cgroup-util.h"
 #include "machined.h"
 
-static bool valid_machine_name(const char *p) {
-        size_t l;
-
-        if (!filename_is_safe(p))
-                return false;
-
-        if (!ascii_is_valid(p))
-                return false;
-
-        l = strlen(p);
-
-        if (l < 1 || l> 64)
-                return false;
-
-        return true;
-}
-
 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *p = NULL;
         Manager *m = userdata;
@@ -185,7 +168,7 @@ static int method_create_or_register_machine(Manager *manager, sd_bus_message *m
         r = sd_bus_message_read(message, "s", &name);
         if (r < 0)
                 return r;
-        if (!valid_machine_name(name))
+        if (!machine_name_is_valid(name))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
 
         r = sd_bus_message_read_array(message, 'y', &v, &n);
index 4ad3f20..3d875c7 100644 (file)
@@ -3975,6 +3975,21 @@ char* hostname_cleanup(char *s, bool lowercase) {
         return s;
 }
 
+bool machine_name_is_valid(const char *s) {
+
+        if (!hostname_is_valid(s))
+                return false;
+
+        /* Machine names should be useful hostnames, but also be
+         * useful in unit names, hence we enforce a stricter length
+         * limitation. */
+
+        if (strlen(s) > 64)
+                return false;
+
+        return true;
+}
+
 int pipe_eof(int fd) {
         struct pollfd pollfd = {
                 .fd = fd,
index 6d3791b..e23069c 100644 (file)
@@ -515,6 +515,8 @@ bool plymouth_running(void);
 bool hostname_is_valid(const char *s) _pure_;
 char* hostname_cleanup(char *s, bool lowercase);
 
+bool machine_name_is_valid(const char *s) _pure_;
+
 char* strshorten(char *s, size_t l);
 
 int terminal_vhangup_fd(int fd);