sd-bus: support connecting to remote hosts, directly into containers

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.
This commit is contained in:
Lennart Poettering 2014-07-03 01:17:26 +02:00
parent 8f6e22a1ca
commit 7f0d207d2c
5 changed files with 93 additions and 29 deletions

View 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;
}

View 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++;
b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", NULL);
/* 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", c, NULL);
if (!b->address)
return -ENOMEM;

View File

@ -41,23 +41,6 @@
#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);

View 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,

View 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);