summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-12-15 21:14:01 +0100
committerGitHub <noreply@github.com>2020-12-15 21:14:01 +0100
commit94b78105c6f93dfe17b4353356227a0baf86f1fe (patch)
tree7c51f75a12b78a4641ade43a621bfa813aa404a6
parent6fe2a70b9160e35fdeed9d37bd31727c2d46a8b2 (diff)
parent1ecb46724cae151606bc825f0e39f14d4dfe1a0e (diff)
downloadsystemd-94b78105c6f93dfe17b4353356227a0baf86f1fe.tar.gz
Merge pull request #17967 from poettering/connect-user-bus
add support for "systemctl --user --machine=foobar@.host" for connecting to user bus of user "foobar"
-rw-r--r--man/sd_bus_default.xml22
-rw-r--r--man/user-system-options.xml10
-rw-r--r--src/basic/hostname-util.c41
-rw-r--r--src/basic/hostname-util.h10
-rw-r--r--src/basic/util.c2
-rw-r--r--src/busctl/busctl.c2
-rw-r--r--src/core/hostname-setup.c13
-rw-r--r--src/firstboot/firstboot.c6
-rw-r--r--src/hostname/hostnamectl.c2
-rw-r--r--src/hostname/hostnamed.c4
-rw-r--r--src/import/export.c4
-rw-r--r--src/import/import-fs.c2
-rw-r--r--src/import/import-raw.c2
-rw-r--r--src/import/import-tar.c2
-rw-r--r--src/import/import.c4
-rw-r--r--src/import/importd.c8
-rw-r--r--src/import/pull-raw.c2
-rw-r--r--src/import/pull-tar.c2
-rw-r--r--src/import/pull.c4
-rw-r--r--src/journal/sd-journal.c2
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c2
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c2
-rw-r--r--src/libsystemd/libsystemd.sym2
-rw-r--r--src/libsystemd/sd-bus/bus-container.c2
-rw-r--r--src/libsystemd/sd-bus/bus-control.c4
-rw-r--r--src/libsystemd/sd-bus/bus-convenience.c19
-rw-r--r--src/libsystemd/sd-bus/bus-internal.h2
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c219
-rw-r--r--src/libsystemd/sd-login/sd-login.c6
-rw-r--r--src/machine/machine-dbus.c2
-rw-r--r--src/machine/machinectl.c16
-rw-r--r--src/machine/machined-dbus.c2
-rw-r--r--src/machine/machined.c2
-rw-r--r--src/network/generator/network-generator.c2
-rw-r--r--src/network/networkd-network.c2
-rw-r--r--src/nspawn/nspawn-oci.c2
-rw-r--r--src/nspawn/nspawn-settings.c2
-rw-r--r--src/nspawn/nspawn.c6
-rw-r--r--src/shared/bus-util.c15
-rw-r--r--src/shared/bus-util.h21
-rw-r--r--src/shared/logs-show.c3
-rw-r--r--src/stdio-bridge/stdio-bridge.c21
-rw-r--r--src/systemctl/systemctl.c2
-rw-r--r--src/systemd/sd-bus.h1
-rw-r--r--src/test/test-hostname-util.c70
45 files changed, 410 insertions, 161 deletions
diff --git a/man/sd_bus_default.xml b/man/sd_bus_default.xml
index 4ae26414eb..768a386160 100644
--- a/man/sd_bus_default.xml
+++ b/man/sd_bus_default.xml
@@ -24,6 +24,7 @@
<refname>sd_bus_open_with_description</refname>
<refname>sd_bus_open_user</refname>
<refname>sd_bus_open_user_with_description</refname>
+ <refname>sd_bus_open_user_machine</refname>
<refname>sd_bus_open_system</refname>
<refname>sd_bus_open_system_with_description</refname>
<refname>sd_bus_open_system_remote</refname>
@@ -74,6 +75,12 @@
</funcprototype>
<funcprototype>
+ <funcdef>int <function>sd_bus_open_user_machine</function></funcdef>
+ <paramdef>sd_bus **<parameter>bus</parameter></paramdef>
+ <paramdef>const char *<parameter>machine</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
<funcdef>int <function>sd_bus_open_system</function></funcdef>
<paramdef>sd_bus **<parameter>bus</parameter></paramdef>
</funcprototype>
@@ -187,14 +194,24 @@
work for the root user on the remote machine.</para>
<para><function>sd_bus_open_system_machine()</function> connects to the system bus in the specified
- <parameter>machine</parameter>, where <parameter>machine</parameter> is the name of a local
- container. See
+ <parameter>machine</parameter>, where <parameter>machine</parameter> is the name of a local container,
+ possibly prefixed by a user name and a separating <literal>@</literal>. If the container name is
+ specified as the special string <literal>.host</literal> the connection is made to the local system. This
+ is useful to connect to the local system bus as specific user, e.g. <literal>foobar@.host</literal> to
+ connect to the local system bus as local user <literal>foobar</literal>. If the <literal>@</literal>
+ syntax is used either the left-hand side or the right-hand side may be ommited (but not both) in which
+ case the local user name or <literal>.host</literal> is implied. If the <literal>@</literal> syntax is
+ not used the connection is always made as root user. See
<citerefentry><refentrytitle>sd_bus_set_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for a description of the address syntax, and
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry> for more
information about the "machine" concept. Note that connections into local containers are only available
to privileged processes at this time.</para>
+ <para><function>sd_bus_open_user_machine()</function> is similar to
+ <function>sd_bus_open_system_machine()</function>, but connects to the user bus of the root user, or if
+ the <literal>@</literal> syntax is used, of the specified user.</para>
+
<para>These calls allocate a bus connection object and initiate
the connection to a well-known bus of some form. An alternative to
using these high-level calls is to create an unconnected bus
@@ -210,6 +227,7 @@
<title>Reference ownership</title>
<para>The functions <function>sd_bus_open()</function>,
<function>sd_bus_open_user()</function>,
+ <function>sd_bus_open_user_machine()</function>,
<function>sd_bus_open_system()</function>,
<function>sd_bus_open_system_remote()</function>, and
<function>sd_bus_open_system_machine()</function> return a new
diff --git a/man/user-system-options.xml b/man/user-system-options.xml
index 728118e60c..e2c19b2982 100644
--- a/man/user-system-options.xml
+++ b/man/user-system-options.xml
@@ -45,8 +45,14 @@
<term><option>--machine=</option></term>
<listitem id='machine-text'>
- <para>Execute operation on a local container. Specify a
- container name to connect to.</para>
+ <para>Execute operation on a local container. Specify a container name to connect to, optionally
+ prefixed by a user name to connect as and a separating <literal>@</literal> character. If the special
+ string <literal>.host</literal> is used in place of the container name, a connection to the local
+ system is made (which is useful to connect to a specific user's user bus: <literal>--user
+ --machine=lennart@.host</literal>). If the <literal>@</literal> syntax is not used, the connection is
+ made as root user. If the <literal>@</literal> syntax is used either the left hand side or the right hand
+ side may be ommitted (but not both) in which case the local user name and <literal>.host</literal> are
+ implied.</para>
</listitem>
</varlistentry>
</variablelist>
diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c
index 5c3157fdf2..e1e3d1b061 100644
--- a/src/basic/hostname-util.c
+++ b/src/basic/hostname-util.c
@@ -89,6 +89,8 @@ int gethostname_strict(char **ret) {
}
bool valid_ldh_char(char c) {
+ /* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */
+
return
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
@@ -96,28 +98,24 @@ bool valid_ldh_char(char c) {
c == '-';
}
-/**
- * Check if s looks like a valid hostname or FQDN. This does not do
- * full DNS validation, but only checks if the name is composed of
- * allowed characters and the length is not above the maximum allowed
- * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
- * allow_trailing_dot is true and at least two components are present
- * in the name. Note that due to the restricted charset and length
- * this call is substantially more conservative than
- * dns_name_is_valid().
- */
-bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
+bool hostname_is_valid(const char *s, ValidHostnameFlags flags) {
unsigned n_dots = 0;
const char *p;
bool dot, hyphen;
+ /* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only
+ * checks if the name is composed of allowed characters and the length is not above the maximum
+ * allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if
+ * VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note
+ * that due to the restricted charset and length this call is substantially more conservative than
+ * dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames
+ * with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */
+
if (isempty(s))
return false;
- /* Doesn't accept empty hostnames, hostnames with
- * leading dots, and hostnames with multiple dots in a
- * sequence. Also ensures that the length stays below
- * HOST_NAME_MAX. */
+ if (streq(s, ".host")) /* Used by the container logic to denote the "root container" */
+ return FLAGS_SET(flags, VALID_HOSTNAME_DOT_HOST);
for (p = s, dot = hyphen = true; *p; p++)
if (*p == '.') {
@@ -143,14 +141,13 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
hyphen = false;
}
- if (dot && (n_dots < 2 || !allow_trailing_dot))
+ if (dot && (n_dots < 2 || !FLAGS_SET(flags, VALID_HOSTNAME_TRAILING_DOT)))
return false;
if (hyphen)
return false;
- if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
- * Linux, but DNS allows domain names
- * up to 255 characters */
+ if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to
+ * 255 characters */
return false;
return true;
@@ -241,7 +238,7 @@ int shorten_overlong(const char *s, char **ret) {
if (!h)
return -ENOMEM;
- if (hostname_is_valid(h, false)) {
+ if (hostname_is_valid(h, 0)) {
*ret = h;
return 0;
}
@@ -252,7 +249,7 @@ int shorten_overlong(const char *s, char **ret) {
strshorten(h, HOST_NAME_MAX);
- if (!hostname_is_valid(h, false)) {
+ if (!hostname_is_valid(h, 0)) {
free(h);
return -EDOM;
}
@@ -285,7 +282,7 @@ int read_etc_hostname_stream(FILE *f, char **ret) {
hostname_cleanup(p); /* normalize the hostname */
- if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */
+ if (!hostname_is_valid(p, VALID_HOSTNAME_TRAILING_DOT)) /* check that the hostname we return is valid */
return -EBADMSG;
copy = strdup(p);
diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h
index 34819c2953..fe417297ee 100644
--- a/src/basic/hostname-util.h
+++ b/src/basic/hostname-util.h
@@ -14,10 +14,14 @@ char* gethostname_short_malloc(void);
int gethostname_strict(char **ret);
bool valid_ldh_char(char c) _const_;
-bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_;
-char* hostname_cleanup(char *s);
-#define machine_name_is_valid(s) hostname_is_valid(s, false)
+typedef enum ValidHostnameFlags {
+ VALID_HOSTNAME_TRAILING_DOT = 1 << 0, /* Accept trailing dot on multi-label names */
+ VALID_HOSTNAME_DOT_HOST = 1 << 1, /* Accept ".host" as valid hostname */
+} ValidHostnameFlags;
+
+bool hostname_is_valid(const char *s, ValidHostnameFlags flags) _pure_;
+char* hostname_cleanup(char *s);
bool is_localhost(const char *hostname);
diff --git a/src/basic/util.c b/src/basic/util.c
index b080ce4e96..7c708eb3be 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -165,7 +165,7 @@ int container_get_leader(const char *machine, pid_t *pid) {
return 0;
}
- if (!machine_name_is_valid(machine))
+ if (!hostname_is_valid(machine, 0))
return -EINVAL;
p = strjoina("/run/systemd/machines/", machine);
diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c
index 274fb42ed3..7e293e47e5 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -121,7 +121,7 @@ static int acquire_bus(bool set_monitor, sd_bus **ret) {
break;
case BUS_TRANSPORT_MACHINE:
- r = bus_set_address_system_machine(bus, arg_host);
+ r = bus_set_address_machine(bus, arg_user, arg_host);
break;
default:
diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c
index 867ea19905..6ccaa479de 100644
--- a/src/core/hostname-setup.c
+++ b/src/core/hostname-setup.c
@@ -24,7 +24,7 @@ int hostname_setup(void) {
if (r < 0)
log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
else if (r > 0) {
- if (hostname_is_valid(b, true))
+ if (hostname_is_valid(b, VALID_HOSTNAME_TRAILING_DOT))
hn = b;
else {
log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
@@ -34,12 +34,11 @@ int hostname_setup(void) {
if (!hn) {
r = read_etc_hostname(NULL, &b);
- if (r < 0) {
- if (r == -ENOENT)
- enoent = true;
- else
- log_warning_errno(r, "Failed to read configured hostname: %m");
- } else
+ if (r == -ENOENT)
+ enoent = true;
+ else if (r < 0)
+ log_warning_errno(r, "Failed to read configured hostname, ignoring: %m");
+ else
hn = b;
}
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 742b43f9fc..afead11b42 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -493,7 +493,7 @@ static int prompt_hostname(void) {
break;
}
- if (!hostname_is_valid(h, true)) {
+ if (!hostname_is_valid(h, VALID_HOSTNAME_TRAILING_DOT)) {
log_error("Specified hostname invalid.");
continue;
}
@@ -1135,15 +1135,15 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_HOSTNAME:
- if (!hostname_is_valid(optarg, true))
+ if (!hostname_is_valid(optarg, VALID_HOSTNAME_TRAILING_DOT))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Host name %s is not valid.", optarg);
- hostname_cleanup(optarg);
r = free_and_strdup(&arg_hostname, optarg);
if (r < 0)
return log_oom();
+ hostname_cleanup(arg_hostname);
break;
case ARG_MACHINE_ID:
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c
index 0d39e9176f..de6eb9ea2f 100644
--- a/src/hostname/hostnamectl.c
+++ b/src/hostname/hostnamectl.c
@@ -248,7 +248,7 @@ static int set_hostname(int argc, char **argv, void *userdata) {
/* If the passed hostname is already valid, then assume the user doesn't know anything about pretty
* hostnames, so let's unset the pretty hostname, and just set the passed hostname as static/dynamic
* hostname. */
- if (arg_static && hostname_is_valid(hostname, true))
+ if (arg_static && hostname_is_valid(hostname, VALID_HOSTNAME_TRAILING_DOT))
p = ""; /* No pretty hostname (as it is redundant), just a static one */
else
p = hostname; /* Use the passed name as pretty hostname */
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index a1794bdab1..a0dc25c834 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -596,7 +596,7 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
if (isempty(name))
name = FALLBACK_HOSTNAME;
- if (!hostname_is_valid(name, false))
+ if (!hostname_is_valid(name, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
assert_se(uname(&u) >= 0);
@@ -650,7 +650,7 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
return sd_bus_reply_method_return(m, NULL);
- if (!isempty(name) && !hostname_is_valid(name, false))
+ if (!isempty(name) && !hostname_is_valid(name, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
r = bus_verify_polkit_async(
diff --git a/src/import/export.c b/src/import/export.c
index 83990df64c..b8507330ac 100644
--- a/src/import/export.c
+++ b/src/import/export.c
@@ -65,7 +65,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
_cleanup_close_ int open_fd = -1;
int r, fd;
- if (machine_name_is_valid(argv[1])) {
+ if (hostname_is_valid(argv[1], 0)) {
r = image_find(IMAGE_MACHINE, argv[1], &image);
if (r == -ENOENT)
return log_error_errno(r, "Machine image %s not found.", argv[1]);
@@ -141,7 +141,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
_cleanup_close_ int open_fd = -1;
int r, fd;
- if (machine_name_is_valid(argv[1])) {
+ if (hostname_is_valid(argv[1], 0)) {
r = image_find(IMAGE_MACHINE, argv[1], &image);
if (r == -ENOENT)
return log_error_errno(r, "Machine image %s not found.", argv[1]);
diff --git a/src/import/import-fs.c b/src/import/import-fs.c
index 3b43ea112d..a22eef8255 100644
--- a/src/import/import-fs.c
+++ b/src/import/import-fs.c
@@ -126,7 +126,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
local = empty_or_dash_to_null(local);
if (local) {
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
diff --git a/src/import/import-raw.c b/src/import/import-raw.c
index 9f5c13ba16..c0869ffcf9 100644
--- a/src/import/import-raw.c
+++ b/src/import/import-raw.c
@@ -393,7 +393,7 @@ int raw_import_start(RawImport *i, int fd, const char *local, bool force_local,
assert(fd >= 0);
assert(local);
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return -EINVAL;
if (i->input_fd >= 0)
diff --git a/src/import/import-tar.c b/src/import/import-tar.c
index 9f68d45eac..d68ce91613 100644
--- a/src/import/import-tar.c
+++ b/src/import/import-tar.c
@@ -329,7 +329,7 @@ int tar_import_start(TarImport *i, int fd, const char *local, bool force_local,
assert(fd >= 0);
assert(local);
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return -EINVAL;
if (i->input_fd >= 0)
diff --git a/src/import/import.c b/src/import/import.c
index eade0f0ec8..9ea8e7f16d 100644
--- a/src/import/import.c
+++ b/src/import/import.c
@@ -64,7 +64,7 @@ static int import_tar(int argc, char *argv[], void *userdata) {
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
@@ -159,7 +159,7 @@ static int import_raw(int argc, char *argv[], void *userdata) {
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
diff --git a/src/import/importd.c b/src/import/importd.c
index 63f80e0e38..b5cff4aca8 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -717,7 +717,7 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
return -EINVAL;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Local name %s is invalid", local);
@@ -787,7 +787,7 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e
if (r < 0)
return r;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Local name %s is invalid", local);
@@ -852,7 +852,7 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
if (r < 0)
return r;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Local name %s is invalid", local);
@@ -932,7 +932,7 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
if (isempty(local))
local = NULL;
- else if (!machine_name_is_valid(local))
+ else if (!hostname_is_valid(local, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Local name %s is invalid", local);
diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c
index 7956ef0395..4a2bab3d07 100644
--- a/src/import/pull-raw.c
+++ b/src/import/pull-raw.c
@@ -651,7 +651,7 @@ int raw_pull_start(
if (!http_url_is_valid(url))
return -EINVAL;
- if (local && !machine_name_is_valid(local))
+ if (local && !hostname_is_valid(local, 0))
return -EINVAL;
if (i->raw_job)
diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c
index 72e5b8be27..bbbd0f57a0 100644
--- a/src/import/pull-tar.c
+++ b/src/import/pull-tar.c
@@ -481,7 +481,7 @@ int tar_pull_start(
if (!http_url_is_valid(url))
return -EINVAL;
- if (local && !machine_name_is_valid(local))
+ if (local && !hostname_is_valid(local, 0))
return -EINVAL;
if (i->tar_job)
diff --git a/src/import/pull.c b/src/import/pull.c
index 9aff377b93..a4cec9448e 100644
--- a/src/import/pull.c
+++ b/src/import/pull.c
@@ -72,7 +72,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
@@ -158,7 +158,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 624fc5fab5..27251a2597 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -1984,7 +1984,7 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in
assert_return(machine, -EINVAL);
assert_return(ret, -EINVAL);
assert_return((flags & ~OPEN_CONTAINER_ALLOWED_FLAGS) == 0, -EINVAL);
- assert_return(machine_name_is_valid(machine), -EINVAL);
+ assert_return(hostname_is_valid(machine, 0), -EINVAL);
p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(NULL, p,
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index c3b51c0d0f..0c2eb91ae3 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -544,7 +544,7 @@ int sd_dhcp_client_set_hostname(
/* Make sure hostnames qualify as DNS and as Linux hostnames */
if (hostname &&
- !(hostname_is_valid(hostname, false) && dns_name_is_valid(hostname) > 0))
+ !(hostname_is_valid(hostname, 0) && dns_name_is_valid(hostname) > 0))
return -EINVAL;
return free_and_strdup(&client->hostname, hostname);
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 97fd5fd4fb..e068e0dc91 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -407,7 +407,7 @@ int sd_dhcp6_client_set_fqdn(
/* Make sure FQDN qualifies as DNS and as Linux hostname */
if (fqdn &&
- !(hostname_is_valid(fqdn, false) && dns_name_is_valid(fqdn) > 0))
+ !(hostname_is_valid(fqdn, 0) && dns_name_is_valid(fqdn) > 0))
return -EINVAL;
return free_and_strdup(&client->fqdn, fqdn);
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index b03bcd952f..9e9e8fd372 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -739,6 +739,8 @@ global:
LIBSYSTEMD_248 {
global:
+ sd_bus_open_user_machine;
+
sd_event_source_set_ratelimit;
sd_event_source_get_ratelimit;
sd_event_source_is_ratelimited;
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
index f09d5e7fd1..b11ebb3f65 100644
--- a/src/libsystemd/sd-bus/bus-container.c
+++ b/src/libsystemd/sd-bus/bus-container.c
@@ -49,7 +49,7 @@ int bus_container_connect_socket(sd_bus *b) {
bus_socket_setup(b);
- if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
return -errno;
r = namespace_fork("(sd-buscntrns)", "(sd-buscntr)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG,
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index a63937e1ce..3ee22c9638 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -713,7 +713,7 @@ _public_ int sd_bus_get_name_creds(
}
r = bus_creds_add_more(c, mask, pid, 0);
- if (r < 0)
+ if (r < 0 && r != -ESRCH) /* Return the error, but ignore ESRCH which just means the process is already gone */
return r;
}
@@ -788,7 +788,7 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
}
r = bus_creds_add_more(c, mask, pid, 0);
- if (r < 0)
+ if (r < 0 && r != -ESRCH) /* If the process vanished, then don't complain, just return what we got */
return r;
*ret = TAKE_PTR(c);
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
index 4bf228b436..0314642f3e 100644
--- a/src/libsystemd/sd-bus/bus-convenience.c
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -603,13 +603,15 @@ _public_ int sd_bus_set_property(
return r;
}
-_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
+_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **ret) {
sd_bus_creds *c;
+ int r;
assert_return(call, -EINVAL);
assert_return(call->sealed, -EPERM);
assert_return(call->bus, -EINVAL);
assert_return(!bus_pid_changed(call->bus), -ECHILD);
+ assert_return(ret, -EINVAL);
if (!BUS_IS_OPEN(call->bus->state))
return -ENOTCONN;
@@ -618,7 +620,7 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
/* All data we need? */
if (c && (mask & ~c->mask) == 0) {
- *creds = sd_bus_creds_ref(c);
+ *ret = sd_bus_creds_ref(c);
return 0;
}
@@ -629,15 +631,22 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
if (call->sender)
/* There's a sender, but the creds are missing. */
- return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
+ return sd_bus_get_name_creds(call->bus, call->sender, mask, ret);
else
/* There's no sender. For direct connections
* the credentials of the AF_UNIX peer matter,
* which may be queried via sd_bus_get_owner_creds(). */
- return sd_bus_get_owner_creds(call->bus, mask, creds);
+ return sd_bus_get_owner_creds(call->bus, mask, ret);
}
- return bus_creds_extend_by_pid(c, mask, creds);
+ r = bus_creds_extend_by_pid(c, mask, ret);
+ if (r == -ESRCH) {
+ /* Process doesn't exist anymore? propagate the few things we have */
+ *ret = sd_bus_creds_ref(c);
+ return 0;
+ }
+
+ return r;
}
_public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 233a228315..82fa97fc5d 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -401,7 +401,7 @@ void bus_close_io_fds(sd_bus *b);
int bus_set_address_system(sd_bus *bus);
int bus_set_address_user(sd_bus *bus);
int bus_set_address_system_remote(sd_bus *b, const char *host);
-int bus_set_address_system_machine(sd_bus *b, const char *machine);
+int bus_set_address_machine(sd_bus *b, bool user, const char *machine);
int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index b8d4dc8d95..e9bc19d96a 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -41,6 +41,7 @@
#include "process-util.h"
#include "string-util.h"
#include "strv.h"
+#include "user-util.h"
#define log_debug_bus_message(m) \
do { \
@@ -973,7 +974,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
return -EINVAL;
if (machine) {
- if (!streq(machine, ".host") && !machine_name_is_valid(machine))
+ if (!hostname_is_valid(machine, VALID_HOSTNAME_DOT_HOST))
return -EINVAL;
free_and_replace(b->machine, machine);
@@ -1448,7 +1449,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) {
}
if (!in_charset(p, "0123456789") || *p == '\0') {
- if (!machine_name_is_valid(p) || got_forward_slash)
+ if (!hostname_is_valid(p, 0) || got_forward_slash)
return -EINVAL;
m = TAKE_PTR(p);
@@ -1463,7 +1464,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) {
interpret_port_as_machine_old_syntax:
/* 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))
+ if (!in_charset(m, "0123456789") && hostname_is_valid(m, 0))
c = strjoina(",argv", p ? "7" : "5", "=--machine=", m);
}
@@ -1514,44 +1515,228 @@ _public_ int sd_bus_open_system_remote(sd_bus **ret, const char *host) {
return 0;
}
-int bus_set_address_system_machine(sd_bus *b, const char *machine) {
- _cleanup_free_ char *e = NULL;
+int bus_set_address_machine(sd_bus *b, bool user, const char *machine) {
+ const char *rhs;
char *a;
assert(b);
assert(machine);
- e = bus_address_escape(machine);
- if (!e)
- return -ENOMEM;
+ rhs = strchr(machine, '@');
+ if (rhs || user) {
+ _cleanup_free_ char *u = NULL, *eu = NULL, *erhs = NULL;
+
+ /* If there's an "@" in the container specification, we'll connect as a user specified at its
+ * left hand side, which is useful in combination with user=true. This isn't as trivial as it
+ * might sound: it's not sufficient to enter the container and connect to some socket there,
+ * since the --user socket path depends on $XDG_RUNTIME_DIR which is set via PAM. Thus, to be
+ * able to connect, we need to have a PAM session. Our way out? We use systemd-run to get
+ * into the container and acquire a PAM session there, and then invoke systemd-stdio-bridge
+ * in it, which propagates the bus transport to us.*/
+
+ if (rhs) {
+ if (rhs > machine)
+ u = strndup(machine, rhs - machine);
+ else
+ u = getusername_malloc(); /* Empty user name, let's use the local one */
+ if (!u)
+ return -ENOMEM;
- a = strjoin("x-machine-unix:machine=", e);
- if (!a)
- return -ENOMEM;
+ eu = bus_address_escape(u);
+ if (!eu)
+ return -ENOMEM;
+
+ rhs++;
+ } else {
+ /* No "@" specified but we shall connect to the user instance? Then assume root (and
+ * not a user named identically to the calling one). This means:
+ *
+ * --machine=foobar --user → connect to user bus of root user in container "foobar"
+ * --machine=@foobar --user → connect to user bus of user named like the calling user in container "foobar"
+ *
+ * Why? so that behaviour for "--machine=foobar --system" is roughly similar to
+ * "--machine=foobar --user": both times we unconditionally connect as root user
+ * regardless what the calling user is. */
+
+ rhs = machine;
+ }
+
+ if (!isempty(rhs)) {
+ erhs = bus_address_escape(rhs);
+ if (!erhs)
+ return -ENOMEM;
+ }
+
+ /* systemd-run -M… -PGq --wait -pUser=… -pPAMName=login systemd-stdio-bridge */
+
+ a = strjoin("unixexec:path=systemd-run,"
+ "argv1=-M", erhs ?: ".host", ","
+ "argv2=-PGq,"
+ "argv3=--wait,"
+ "argv4=-pUser%3d", eu ?: "root", ",",
+ "argv5=-pPAMName%3dlogin,"
+ "argv6=systemd-stdio-bridge");
+ if (!a)
+ return -ENOMEM;
+
+ if (user) {
+ char *k;
+
+ /* Ideally we'd use the "--user" switch to systemd-stdio-bridge here, but it's only
+ * available in recent systemd versions. Using the "-p" switch with the explicit path
+ * is a working alternative, and is compatible with older versions, hence that's what
+ * we use here. */
+
+ k = strjoin(a, ",argv7=-punix:path%3d%24%7bXDG_RUNTIME_DIR%7d/bus");
+ if (!k)
+ return -ENOMEM;
+
+ free_and_replace(a, k);
+ }
+ } else {
+ _cleanup_free_ char *e = NULL;
+
+ /* Just a container name, we can go the simple way, and just join the container, and connect
+ * to the well-known path of the system bus there. */
+
+ e = bus_address_escape(machine);
+ if (!e)
+ return -ENOMEM;
+
+ a = strjoin("x-machine-unix:machine=", e);
+ if (!a)
+ return -ENOMEM;
+ }
return free_and_replace(b->address, a);
}
-_public_ int sd_bus_open_system_machine(sd_bus **ret, const char *machine) {
+static int user_and_machine_valid(const char *user_and_machine) {
+ const char *h;
+
+ /* Checks if a container specification in the form "user@container" or just "container" is valid.
+ *
+ * If the "@" syntax is used we'll allow either the "user" or the "container" part to be omitted, but
+ * not both. */
+
+ h = strchr(user_and_machine, '@');
+ if (!h)
+ h = user_and_machine;
+ else {
+ _cleanup_free_ char *user = NULL;
+
+ user = strndup(user_and_machine, h - user_and_machine);
+ if (!user)
+ return -ENOMEM;
+
+ if (!isempty(user) && !valid_user_group_name(user, VALID_USER_RELAX))
+ return false;
+
+ h++;
+
+ if (isempty(h))
+ return !isempty(user);
+ }
+
+ return hostname_is_valid(h, VALID_HOSTNAME_DOT_HOST);
+}
+
+static int user_and_machine_equivalent(const char *user_and_machine) {
+ _cleanup_free_ char *un = NULL;
+ const char *f;
+
+ /* Returns true if the specified user+machine name are actually equivalent to our own identity and
+ * our own host. If so we can shortcut things. Why bother? Because that way we don't have to fork
+ * off short-lived worker processes that are then unavailable for authentication and logging in the
+ * peer. Moreover joining a namespace requires privileges. If we are in the right namespace anyway,
+ * we can avoid permission problems thus. */
+
+ assert(user_and_machine);
+
+ /* Omitting the user name means that we shall use the same user name as we run as locally, which
+ * means we'll end up on the same host, let's shortcut */
+ if (streq(user_and_machine, "@.host"))
+ return true;
+
+ /* Otherwise, if we are root, then we can also allow the ".host" syntax, as that's the user this
+ * would connect to. */
+ if (geteuid() == 0 && STR_IN_SET(user_and_machine, ".host", "root@.host"))
+ return true;
+
+ /* Otherwise, we have to figure our user name, and compare things with that. */
+ un = getusername_malloc();
+ if (!un)
+ return -ENOMEM;
+
+ f = startswith(user_and_machine, un);
+ if (!f)
+ return false;
+
+ return STR_IN_SET(f, "@", "@.host");
+}
+
+_public_ int sd_bus_open_system_machine(sd_bus **ret, const char *user_and_machine) {
_cleanup_(bus_freep) sd_bus *b = NULL;
int r;
- assert_return(machine, -EINVAL);
+ assert_return(user_and_machine, -EINVAL);
assert_return(ret, -EINVAL);
- assert_return(streq(machine, ".host") || machine_name_is_valid(machine), -EINVAL);
+
+ if (user_and_machine_equivalent(user_and_machine))
+ return sd_bus_open_system(ret);
+
+ r = user_and_machine_valid(user_and_machine);
+ if (r < 0)
+ return r;
+
+ assert_return(r > 0, -EINVAL);
r = sd_bus_new(&b);
if (r < 0)
return r;
- r = bus_set_address_system_machine(b, machine);
+ r = bus_set_address_machine(b, false, user_and_machine);
if (r < 0)
return r;
b->bus_client = true;
- b->trusted = false;
b->is_system = true;
- b->is_local = false;
+
+ r = sd_bus_start(b);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_PTR(b);
+ return 0;
+}
+
+_public_ int sd_bus_open_user_machine(sd_bus **ret, const char *user_and_machine) {
+ _cleanup_(bus_freep) sd_bus *b = NULL;
+ int r;
+
+ assert_return(user_and_machine, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ /* Shortcut things if we'd end up on this host and as the same user. */
+ if (user_and_machine_equivalent(user_and_machine))
+ return sd_bus_open_user(ret);
+
+ r = user_and_machine_valid(user_and_machine);
+ if (r < 0)
+ return r;
+
+ assert_return(r > 0, -EINVAL);
+
+ r = sd_bus_new(&b);
+ if (r < 0)
+ return r;
+
+ r = bus_set_address_machine(b, true, user_and_machine);
+ if (r < 0)
+ return r;
+
+ b->bus_client = true;
+ b->trusted = true;
r = sd_bus_start(b);
if (r < 0)
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index 1fc379512f..d15dafbd95 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -847,7 +847,7 @@ _public_ int sd_get_machine_names(char ***machines) {
/* Filter out the unit: symlinks */
for (a = b = l; *a; a++) {
- if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
+ if (startswith(*a, "unit:") || !hostname_is_valid(*a, 0))
free(*a);
else {
*b = *a;
@@ -877,7 +877,7 @@ _public_ int sd_machine_get_class(const char *machine, char **class) {
if (!c)
return -ENOMEM;
} else {
- if (!machine_name_is_valid(machine))
+ if (!hostname_is_valid(machine, 0))
return -EINVAL;
p = strjoina("/run/systemd/machines/", machine);
@@ -899,7 +899,7 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ret_ifindices)
const char *p;
int r;
- assert_return(machine_name_is_valid(machine), -EINVAL);
+ assert_return(hostname_is_valid(machine, 0), -EINVAL);
p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(NULL, p, "NETIF", &netif_line);
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index bb67beb665..4646571668 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -487,7 +487,7 @@ static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) {
if (r < 0)
return r;
- if (asprintf(&address, "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI, m->leader) < 0)
+ if (asprintf(&address, "x-machine-unix:pid=%" PID_PRI, m->leader) < 0)
return -ENOMEM;
bus->address = address;
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 4a3279d264..3c839455b6 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -1561,7 +1561,7 @@ static int make_service_name(const char *name, char **ret) {
assert(name);
assert(ret);
- if (!machine_name_is_valid(name))
+ if (!hostname_is_valid(name, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid machine name %s.", name);
@@ -1881,7 +1881,7 @@ static int import_tar(int argc, char *argv[], void *userdata) {
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local name %s is not a suitable machine name.",
local);
@@ -1941,7 +1941,7 @@ static int import_raw(int argc, char *argv[], void *userdata) {
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local name %s is not a suitable machine name.",
local);
@@ -1995,7 +1995,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Need either path or local name.");
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local name %s is not a suitable machine name.",
local);
@@ -2048,7 +2048,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
assert(bus);
local = argv[1];
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Machine name %s is not valid.", local);
@@ -2090,7 +2090,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
assert(bus);
local = argv[1];
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Machine name %s is not valid.", local);
@@ -2155,7 +2155,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local name %s is not a suitable machine name.",
local);
@@ -2211,7 +2211,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local name %s is not a suitable machine name.",
local);
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 494813e334..501db643f8 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -239,7 +239,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 (!machine_name_is_valid(name))
+ if (!hostname_is_valid(name, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
r = sd_bus_message_read_array(message, 'y', &v, &n);
diff --git a/src/machine/machined.c b/src/machine/machined.c
index 4d8891c4fc..6a5bf391e6 100644
--- a/src/machine/machined.c
+++ b/src/machine/machined.c
@@ -166,7 +166,7 @@ static int manager_enumerate_machines(Manager *m) {
if (startswith(de->d_name, "unit:"))
continue;
- if (!machine_name_is_valid(de->d_name))
+ if (!hostname_is_valid(de->d_name, 0))
continue;
k = manager_add_machine(m, de->d_name, &machine);
diff --git a/src/network/generator/network-generator.c b/src/network/generator/network-generator.c
index 2fa21a067a..f9b51d8b7b 100644
--- a/src/network/generator/network-generator.c
+++ b/src/network/generator/network-generator.c
@@ -601,7 +601,7 @@ static int parse_cmdline_ip_address(Context *context, int family, const char *va
if (p != value) {
hostname = strndupa(value, p - value);
- if (!hostname_is_valid(hostname, false))
+ if (!hostname_is_valid(hostname, 0))
return -EINVAL;
}
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 7ad8d087f4..73c3788e27 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -922,7 +922,7 @@ int config_parse_hostname(
if (r < 0)
return r;
- if (!hostname_is_valid(hn, false)) {
+ if (!hostname_is_valid(hn, 0)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Hostname is not valid, ignoring assignment: %s", rvalue);
return 0;
diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c
index ca708be755..ccbae616ca 100644
--- a/src/nspawn/nspawn-oci.c
+++ b/src/nspawn/nspawn-oci.c
@@ -462,7 +462,7 @@ static int oci_hostname(const char *name, JsonVariant *v, JsonDispatchFlags flag
assert_se(n = json_variant_string(v));
- if (!hostname_is_valid(n, false))
+ if (!hostname_is_valid(n, 0))
return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
"Hostname string is not a valid hostname: %s", n);
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
index 92bb5120ab..b43d61468e 100644
--- a/src/nspawn/nspawn-settings.c
+++ b/src/nspawn/nspawn-settings.c
@@ -701,7 +701,7 @@ int config_parse_hostname(
assert(rvalue);
assert(s);
- if (!hostname_is_valid(rvalue, false)) {
+ if (!hostname_is_valid(rvalue, 0)) {
log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 5e3d11be36..cfbc8f11bf 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -985,7 +985,7 @@ static int parse_argv(int argc, char *argv[]) {
if (isempty(optarg))
arg_machine = mfree(arg_machine);
else {
- if (!machine_name_is_valid(optarg))
+ if (!hostname_is_valid(optarg, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid machine name: %s", optarg);
@@ -999,7 +999,7 @@ static int parse_argv(int argc, char *argv[]) {
if (isempty(optarg))
arg_hostname = mfree(arg_hostname);
else {
- if (!hostname_is_valid(optarg, false))
+ if (!hostname_is_valid(optarg, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid hostname: %s", optarg);
@@ -2984,7 +2984,7 @@ static int determine_names(void) {
return log_oom();
hostname_cleanup(arg_machine);
- if (!machine_name_is_valid(arg_machine))
+ if (!hostname_is_valid(arg_machine, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine machine name automatically, please use -M.");
if (arg_ephemeral) {
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index fbda218b3b..58211ebd03 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -249,7 +249,12 @@ int bus_connect_user_systemd(sd_bus **_bus) {
return 0;
}
-int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
+int bus_connect_transport(
+ BusTransport transport,
+ const char *host,
+ bool user,
+ sd_bus **ret) {
+
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
int r;
@@ -258,7 +263,7 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
assert(ret);
assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
- assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
+ assert_return(transport != BUS_TRANSPORT_REMOTE || !user, -EOPNOTSUPP);
switch (transport) {
@@ -279,7 +284,10 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
break;
case BUS_TRANSPORT_MACHINE:
- r = sd_bus_open_system_machine(&bus, host);
+ if (user)
+ r = sd_bus_open_user_machine(&bus, host);
+ else
+ r = sd_bus_open_system_machine(&bus, host);
break;
default:
@@ -293,7 +301,6 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
return r;
*ret = TAKE_PTR(bus);
-
return 0;
}
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index a02d82a52e..27dd6c19c0 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -9,6 +9,7 @@
#include "sd-bus.h"
#include "sd-event.h"
+#include "errno-util.h"
#include "macro.h"
#include "string-util.h"
#include "time-util.h"
@@ -39,13 +40,21 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
#define bus_log_address_error(r) \
- log_error_errno(r, \
- r == -ENOMEDIUM ? "Failed to set bus address: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined" : \
- "Failed to set bus address: %m")
+ ({ \
+ int _k = (r); \
+ log_error_errno(_k, \
+ _k == -ENOMEDIUM ? "Failed to set bus address: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=<user>@.host --user to connect to bus of other user)" : \
+ "Failed to set bus address: %m"); \
+ })
+
#define bus_log_connect_error(r) \
- log_error_errno(r, \
- r == -ENOMEDIUM ? "Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined" : \
- "Failed to connect to bus: %m")
+ ({ \
+ int _k = (r); \
+ log_error_errno(_k, \
+ _k == -ENOMEDIUM ? "Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=<user>@.host --user to connect to bus of other user)" : \
+ ERRNO_IS_PRIVILEGE(_k) ? "Failed to connect to bus: Operation not permitted (consider using --machine=<user>@.host --user to connect to bus of other user)" : \
+ "Failed to connect to bus: %m"); \
+ })
#define bus_log_parse_error(r) \
log_error_errno(r, "Failed to parse bus message: %m")
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index bf574d32a5..597ec00ffb 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -1523,9 +1523,6 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
assert(machine);
assert(boot_id);
- if (!machine_name_is_valid(machine))
- return -EINVAL;
-
r = container_get_leader(machine, &pid);
if (r < 0)
return r;
diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c
index 81d50717b2..5d8b514874 100644
--- a/src/stdio-bridge/stdio-bridge.c
+++ b/src/stdio-bridge/stdio-bridge.c
@@ -23,6 +23,7 @@
static const char *arg_bus_path = DEFAULT_BUS_PATH;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
+static bool arg_user = false;
static int help(void) {
@@ -30,8 +31,10 @@ static int help(void) {
"STDIO or socket-activatable proxy to a given DBus endpoint.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
- " -p --bus-path=PATH Path to the kernel bus (default: %s)\n"
- " -M --machine=MACHINE Name of machine to connect to\n",
+ " -p --bus-path=PATH Path to the bus address (default: %s)\n"
+ " --system Connect to system bus\n"
+ " --user Connect to user bus\n"
+ " -M --machine=CONTAINER Name of local container to connect to\n",
program_invocation_short_name, DEFAULT_BUS_PATH);
return 0;
@@ -42,12 +45,16 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_MACHINE,
+ ARG_USER,
+ ARG_SYSTEM,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "bus-path", required_argument, NULL, 'p' },
+ { "user", no_argument, NULL, ARG_USER },
+ { "system", no_argument, NULL, ARG_SYSTEM },
{ "machine", required_argument, NULL, 'M' },
{},
};
@@ -67,6 +74,14 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VERSION:
return version();
+ case ARG_USER:
+ arg_user = true;
+ break;
+
+ case ARG_SYSTEM:
+ arg_user = false;
+ break;
+
case 'p':
arg_bus_path = optarg;
break;
@@ -121,7 +136,7 @@ static int run(int argc, char *argv[]) {
return log_error_errno(r, "Failed to allocate bus: %m");
if (arg_transport == BUS_TRANSPORT_MACHINE)
- r = bus_set_address_system_machine(a, arg_bus_path);
+ r = bus_set_address_machine(a, arg_user, arg_bus_path);
else
r = sd_bus_set_address(a, arg_bus_path);
if (r < 0)
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index d002d933ae..9a934badce 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -877,7 +877,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
- if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM)
+ if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != UNIT_FILE_SYSTEM)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot access user instance remotely.");
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 87fbcf366e..c51df2908d 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -135,6 +135,7 @@ int sd_bus_open(sd_bus **ret);
int sd_bus_open_with_description(sd_bus **ret, const char *description);
int sd_bus_open_user(sd_bus **ret);
int sd_bus_open_user_with_description(sd_bus **ret, const char *description);
+int sd_bus_open_user_machine(sd_bus **ret, const char *machine);
int sd_bus_open_system(sd_bus **ret);
int sd_bus_open_system_with_description(sd_bus **ret, const char *description);
int sd_bus_open_system_remote(sd_bus **ret, const char *host);
diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c
index 73839b3115..c7a63bd047 100644
--- a/src/test/test-hostname-util.c
+++ b/src/test/test-hostname-util.c
@@ -10,40 +10,40 @@
#include "util.h"
static void test_hostname_is_valid(void) {
- assert_se(hostname_is_valid("foobar", false));
- assert_se(hostname_is_valid("foobar.com", false));
- assert_se(!hostname_is_valid("foobar.com.", false));
- assert_se(hostname_is_valid("fooBAR", false));
- assert_se(hostname_is_valid("fooBAR.com", false));
- assert_se(!hostname_is_valid("fooBAR.", false));
- assert_se(!hostname_is_valid("fooBAR.com.", false));
- assert_se(!hostname_is_valid("fööbar", false));
- assert_se(!hostname_is_valid("", false));
- assert_se(!hostname_is_valid(".", false));
- assert_se(!hostname_is_valid("..", false));
- assert_se(!hostname_is_valid("foobar.", false));
- assert_se(!hostname_is_valid(".foobar", false));
- assert_se(!hostname_is_valid("foo..bar", false));
- assert_se(!hostname_is_valid("foo.bar..", false));
- assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", false));
- assert_se(!hostname_is_valid("au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local", false));
-
- assert_se(hostname_is_valid("foobar", true));
- assert_se(hostname_is_valid("foobar.com", true));
- assert_se(hostname_is_valid("foobar.com.", true));
- assert_se(hostname_is_valid("fooBAR", true));
- assert_se(hostname_is_valid("fooBAR.com", true));
- assert_se(!hostname_is_valid("fooBAR.", true));
- assert_se(hostname_is_valid("fooBAR.com.", true));
- assert_se(!hostname_is_valid("fööbar", true));
- assert_se(!hostname_is_valid("", true));
- assert_se(!hostname_is_valid(".", true));
- assert_se(!hostname_is_valid("..", true));
- assert_se(!hostname_is_valid("foobar.", true));
- assert_se(!hostname_is_valid(".foobar", true));
- assert_se(!hostname_is_valid("foo..bar", true));
- assert_se(!hostname_is_valid("foo.bar..", true));
- assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true));
+ assert_se(hostname_is_valid("foobar", 0));
+ assert_se(hostname_is_valid("foobar.com", 0));
+ assert_se(!hostname_is_valid("foobar.com.", 0));
+ assert_se(hostname_is_valid("fooBAR", 0));
+ assert_se(hostname_is_valid("fooBAR.com", 0));
+ assert_se(!hostname_is_valid("fooBAR.", 0));
+ assert_se(!hostname_is_valid("fooBAR.com.", 0));
+ assert_se(!hostname_is_valid("fööbar", 0));
+ assert_se(!hostname_is_valid("", 0));
+ assert_se(!hostname_is_valid(".", 0));
+ assert_se(!hostname_is_valid("..", 0));
+ assert_se(!hostname_is_valid("foobar.", 0));
+ assert_se(!hostname_is_valid(".foobar", 0));
+ assert_se(!hostname_is_valid("foo..bar", 0));
+ assert_se(!hostname_is_valid("foo.bar..", 0));
+ assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 0));
+ assert_se(!hostname_is_valid("au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local", 0));
+
+ assert_se(hostname_is_valid("foobar", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(hostname_is_valid("foobar.com", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(hostname_is_valid("foobar.com.", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(hostname_is_valid("fooBAR", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(hostname_is_valid("fooBAR.com", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("fooBAR.", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(hostname_is_valid("fooBAR.com.", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("fööbar", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid(".", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("..", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("foobar.", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid(".foobar", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("foo..bar", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("foo.bar..", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", VALID_HOSTNAME_TRAILING_DOT));
}
static void test_hostname_cleanup(void) {
@@ -151,7 +151,7 @@ static void test_hostname_malloc(void) {
}
static void test_fallback_hostname(void) {
- if (!hostname_is_valid(FALLBACK_HOSTNAME, false)) {
+ if (!hostname_is_valid(FALLBACK_HOSTNAME, 0)) {
log_error("Configured fallback hostname \"%s\" is not valid.", FALLBACK_HOSTNAME);
exit(EXIT_FAILURE);
}