mirror of
https://github.com/systemd/systemd
synced 2025-10-06 00:13:24 +02:00
fixes for --machine= handling in run0 and journalctl (#37741)
Fixes: #32997
This commit is contained in:
@@ -94,7 +94,6 @@ node /org/freedesktop/machine1 {
|
|||||||
out s ssh_private_key_path);
|
out s ssh_private_key_path);
|
||||||
GetMachineOSRelease(in s name,
|
GetMachineOSRelease(in s name,
|
||||||
out a{ss} fields);
|
out a{ss} fields);
|
||||||
@org.freedesktop.systemd1.Privileged("true")
|
|
||||||
OpenMachinePTY(in s name,
|
OpenMachinePTY(in s name,
|
||||||
out h pty,
|
out h pty,
|
||||||
out s pty_path);
|
out s pty_path);
|
||||||
|
@@ -172,3 +172,36 @@ int get_pretty_hostname(char **ret) {
|
|||||||
*ret = TAKE_PTR(n);
|
*ret = TAKE_PTR(n);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int split_user_at_host(const char *s, char **ret_user, char **ret_host) {
|
||||||
|
_cleanup_free_ char *u = NULL, *h = NULL;
|
||||||
|
|
||||||
|
/* Splits a user@host expression (one of those we accept on --machine= and similar). Returns NULL in
|
||||||
|
* each of the two return parameters if that part was left empty. */
|
||||||
|
|
||||||
|
const char *rhs = strchr(s, '@');
|
||||||
|
if (rhs) {
|
||||||
|
if (ret_user && rhs > s) {
|
||||||
|
u = strndup(s, rhs - s);
|
||||||
|
if (!u)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret_host && rhs[1] != 0) {
|
||||||
|
h = strdup(rhs + 1);
|
||||||
|
if (!h)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
} else if (!isempty(s) && ret_host) {
|
||||||
|
h = strdup(s);
|
||||||
|
if (!h)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret_user)
|
||||||
|
*ret_user = TAKE_PTR(u);
|
||||||
|
if (ret_host)
|
||||||
|
*ret_host = TAKE_PTR(h);
|
||||||
|
|
||||||
|
return !!rhs; /* return > 0 if '@' was specified, 0 otherwise */
|
||||||
|
}
|
||||||
|
@@ -38,3 +38,5 @@ static inline bool is_dns_proxy_stub_hostname(const char *hostname) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int get_pretty_hostname(char **ret);
|
int get_pretty_hostname(char **ret);
|
||||||
|
|
||||||
|
int split_user_at_host(const char *s, char **ret_user, char **ret_host);
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "glob-util.h"
|
#include "glob-util.h"
|
||||||
|
#include "hostname-util.h"
|
||||||
#include "id128-util.h"
|
#include "id128-util.h"
|
||||||
#include "journal-util.h"
|
#include "journal-util.h"
|
||||||
#include "journalctl.h"
|
#include "journalctl.h"
|
||||||
@@ -43,9 +44,18 @@ int acquire_journal(sd_journal **ret) {
|
|||||||
r = sd_journal_open_files_fd(&j, (int[]) { STDIN_FILENO }, 1, arg_journal_additional_open_flags);
|
r = sd_journal_open_files_fd(&j, (int[]) { STDIN_FILENO }, 1, arg_journal_additional_open_flags);
|
||||||
else if (arg_file)
|
else if (arg_file)
|
||||||
r = sd_journal_open_files(&j, (const char**) arg_file, arg_journal_additional_open_flags);
|
r = sd_journal_open_files(&j, (const char**) arg_file, arg_journal_additional_open_flags);
|
||||||
else if (arg_machine)
|
else if (arg_machine) {
|
||||||
r = journal_open_machine(&j, arg_machine, arg_journal_additional_open_flags);
|
_cleanup_free_ char *u = NULL, *h = NULL;
|
||||||
else
|
|
||||||
|
r = split_user_at_host(arg_machine, &u, &h);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to split machine specification '%s': %m", arg_machine);
|
||||||
|
|
||||||
|
if (!isempty(u) && !streq(u, "root"))
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Connecting to a machine as non-root is not supported.");
|
||||||
|
|
||||||
|
r = journal_open_machine(&j, h ?: ".host", arg_journal_additional_open_flags);
|
||||||
|
} else
|
||||||
r = sd_journal_open_namespace(
|
r = sd_journal_open_namespace(
|
||||||
&j,
|
&j,
|
||||||
arg_namespace,
|
arg_namespace,
|
||||||
|
@@ -1561,14 +1561,18 @@ _public_ int sd_bus_open_system_remote(sd_bus **ret, const char *host) {
|
|||||||
|
|
||||||
int bus_set_address_machine(sd_bus *b, RuntimeScope runtime_scope, const char *machine) {
|
int bus_set_address_machine(sd_bus *b, RuntimeScope runtime_scope, const char *machine) {
|
||||||
_cleanup_free_ char *a = NULL;
|
_cleanup_free_ char *a = NULL;
|
||||||
const char *rhs;
|
|
||||||
|
|
||||||
assert(b);
|
assert(b);
|
||||||
assert(machine);
|
assert(machine);
|
||||||
|
|
||||||
rhs = strchr(machine, '@');
|
_cleanup_free_ char *u = NULL, *h = NULL;
|
||||||
if (rhs || runtime_scope == RUNTIME_SCOPE_USER) {
|
int with_at;
|
||||||
_cleanup_free_ char *u = NULL, *eu = NULL, *erhs = NULL;
|
with_at = split_user_at_host(machine, &u, &h);
|
||||||
|
if (with_at < 0)
|
||||||
|
return with_at;
|
||||||
|
|
||||||
|
if (with_at || runtime_scope == RUNTIME_SCOPE_USER) {
|
||||||
|
_cleanup_free_ char *eu = NULL, *eh = NULL;
|
||||||
|
|
||||||
/* If there's an "@" in the container specification, we'll connect as a user specified at its
|
/* 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
|
* left hand side, which is useful in combination with user=true. This isn't as trivial as it
|
||||||
@@ -1578,43 +1582,38 @@ int bus_set_address_machine(sd_bus *b, RuntimeScope runtime_scope, const char *m
|
|||||||
* into the container and acquire a PAM session there, and then invoke systemd-stdio-bridge
|
* into the container and acquire a PAM session there, and then invoke systemd-stdio-bridge
|
||||||
* in it, which propagates the bus transport to us. */
|
* in it, which propagates the bus transport to us. */
|
||||||
|
|
||||||
if (rhs) {
|
if (with_at) {
|
||||||
if (rhs > machine)
|
if (!u) {
|
||||||
u = strndup(machine, rhs - machine);
|
|
||||||
else
|
|
||||||
u = getusername_malloc(); /* Empty user name, let's use the local one */
|
u = getusername_malloc(); /* Empty user name, let's use the local one */
|
||||||
if (!u)
|
if (!u)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
eu = bus_address_escape(u);
|
eu = bus_address_escape(u);
|
||||||
if (!eu)
|
if (!eu)
|
||||||
return -ENOMEM;
|
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)) {
|
/* No "@" specified but we shall connect to the user instance? Then assume root (and
|
||||||
erhs = bus_address_escape(rhs);
|
* not a user named identically to the calling one). This means:
|
||||||
if (!erhs)
|
*
|
||||||
|
* --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. */
|
||||||
|
|
||||||
|
if (h) {
|
||||||
|
eh = bus_address_escape(h);
|
||||||
|
if (!eh)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* systemd-run -M… -PGq --wait -pUser=… -pPAMName=login systemd-stdio-bridge */
|
/* systemd-run -M… -PGq --wait -pUser=… -pPAMName=login systemd-stdio-bridge */
|
||||||
|
|
||||||
a = strjoin("unixexec:path=systemd-run,"
|
a = strjoin("unixexec:path=systemd-run,"
|
||||||
"argv1=-M", erhs ?: ".host", ","
|
"argv1=-M", eh ?: ".host", ","
|
||||||
"argv2=-PGq,"
|
"argv2=-PGq,"
|
||||||
"argv3=--wait,"
|
"argv3=--wait,"
|
||||||
"argv4=-pUser%3d", eu ?: "root", ",",
|
"argv4=-pUser%3d", eu ?: "root", ",",
|
||||||
@@ -1637,7 +1636,7 @@ int bus_set_address_machine(sd_bus *b, RuntimeScope runtime_scope, const char *m
|
|||||||
/* Just a container name, we can go the simple way, and just join the container, and connect
|
/* 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. */
|
* to the well-known path of the system bus there. */
|
||||||
|
|
||||||
e = bus_address_escape(machine);
|
e = bus_address_escape(h ?: ".host");
|
||||||
if (!e)
|
if (!e)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@@ -1693,7 +1692,7 @@ static int user_and_machine_equivalent(const char *user_and_machine) {
|
|||||||
|
|
||||||
/* Omitting the user name means that we shall use the same user name as we run as locally, which
|
/* 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 */
|
* means we'll end up on the same host, let's shortcut */
|
||||||
if (streq(user_and_machine, "@.host"))
|
if (STR_IN_SET(user_and_machine, "@.host", "@"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Otherwise, if we are root, then we can also allow the ".host" syntax, as that's the user this
|
/* Otherwise, if we are root, then we can also allow the ".host" syntax, as that's the user this
|
||||||
|
@@ -948,7 +948,7 @@ const sd_bus_vtable manager_vtable[] = {
|
|||||||
SD_BUS_ARGS("s", name),
|
SD_BUS_ARGS("s", name),
|
||||||
SD_BUS_RESULT("h", pty, "s", pty_path),
|
SD_BUS_RESULT("h", pty, "s", pty_path),
|
||||||
method_open_machine_pty,
|
method_open_machine_pty,
|
||||||
0),
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD_WITH_ARGS("OpenMachineLogin",
|
SD_BUS_METHOD_WITH_ARGS("OpenMachineLogin",
|
||||||
SD_BUS_ARGS("s", name),
|
SD_BUS_ARGS("s", name),
|
||||||
SD_BUS_RESULT("h", pty, "s", pty_path),
|
SD_BUS_RESULT("h", pty, "s", pty_path),
|
||||||
|
@@ -72,6 +72,10 @@
|
|||||||
send_interface="org.freedesktop.machine1.Manager"
|
send_interface="org.freedesktop.machine1.Manager"
|
||||||
send_member="OpenMachineLogin"/>
|
send_member="OpenMachineLogin"/>
|
||||||
|
|
||||||
|
<allow send_destination="org.freedesktop.machine1"
|
||||||
|
send_interface="org.freedesktop.machine1.Manager"
|
||||||
|
send_member="OpenMachinePTY"/>
|
||||||
|
|
||||||
<allow send_destination="org.freedesktop.machine1"
|
<allow send_destination="org.freedesktop.machine1"
|
||||||
send_interface="org.freedesktop.machine1.Manager"
|
send_interface="org.freedesktop.machine1.Manager"
|
||||||
send_member="OpenMachineShell"/>
|
send_member="OpenMachineShell"/>
|
||||||
@@ -176,6 +180,10 @@
|
|||||||
send_interface="org.freedesktop.machine1.Machine"
|
send_interface="org.freedesktop.machine1.Machine"
|
||||||
send_member="OpenLogin"/>
|
send_member="OpenLogin"/>
|
||||||
|
|
||||||
|
<allow send_destination="org.freedesktop.machine1"
|
||||||
|
send_interface="org.freedesktop.machine1.Machine"
|
||||||
|
send_member="OpenPTY"/>
|
||||||
|
|
||||||
<allow send_destination="org.freedesktop.machine1"
|
<allow send_destination="org.freedesktop.machine1"
|
||||||
send_interface="org.freedesktop.machine1.Machine"
|
send_interface="org.freedesktop.machine1.Machine"
|
||||||
send_member="OpenShell"/>
|
send_member="OpenShell"/>
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include "format-table.h"
|
#include "format-table.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
|
#include "hostname-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "osc-context.h"
|
#include "osc-context.h"
|
||||||
@@ -2358,12 +2359,20 @@ static int start_transient_service(sd_bus *bus) {
|
|||||||
|
|
||||||
(void) sd_bus_set_allow_interactive_authorization(system_bus, arg_ask_password);
|
(void) sd_bus_set_allow_interactive_authorization(system_bus, arg_ask_password);
|
||||||
|
|
||||||
r = bus_call_method(system_bus,
|
/* Chop off a username prefix. We allow this for sd-bus machine connections, hence
|
||||||
bus_machine_mgr,
|
* support that here too. */
|
||||||
"OpenMachinePTY",
|
_cleanup_free_ char *h = NULL;
|
||||||
&error,
|
r = split_user_at_host(arg_host, /* ret_user= */ NULL, &h);
|
||||||
&pty_reply,
|
if (r < 0)
|
||||||
"s", arg_host);
|
return log_error_errno(r, "Failed to split host specification '%s': %m", arg_host);
|
||||||
|
|
||||||
|
r = bus_call_method(
|
||||||
|
system_bus,
|
||||||
|
bus_machine_mgr,
|
||||||
|
"OpenMachinePTY",
|
||||||
|
&error,
|
||||||
|
&pty_reply,
|
||||||
|
"s", h ?: ".host");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to get machine PTY: %s", bus_error_message(&error, r));
|
return log_error_errno(r, "Failed to get machine PTY: %s", bus_error_message(&error, r));
|
||||||
|
|
||||||
|
@@ -89,4 +89,31 @@ TEST(hostname_cleanup) {
|
|||||||
ASSERT_STREQ(hostname_cleanup(s), "xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
ASSERT_STREQ(hostname_cleanup(s), "xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_split_user_at_host_one(const char *s, const char *expected_user, const char *expected_host, int ret) {
|
||||||
|
_cleanup_free_ char *u = NULL, *h = NULL;
|
||||||
|
|
||||||
|
ASSERT_OK_EQ(split_user_at_host(s, &u, &h), ret);
|
||||||
|
ASSERT_STREQ(u, expected_user);
|
||||||
|
ASSERT_STREQ(h, expected_host);
|
||||||
|
|
||||||
|
u = mfree(u);
|
||||||
|
h = mfree(h);
|
||||||
|
|
||||||
|
ASSERT_OK_EQ(split_user_at_host(s, &u, NULL), ret);
|
||||||
|
ASSERT_STREQ(u, expected_user);
|
||||||
|
|
||||||
|
ASSERT_OK_EQ(split_user_at_host(s, NULL, &h), ret);
|
||||||
|
ASSERT_STREQ(h, expected_host);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(split_user_at_host) {
|
||||||
|
test_split_user_at_host_one("", NULL, NULL, 0);
|
||||||
|
test_split_user_at_host_one("@", NULL, NULL, 1);
|
||||||
|
test_split_user_at_host_one("a", NULL, "a", 0);
|
||||||
|
test_split_user_at_host_one("a@b", "a", "b", 1);
|
||||||
|
test_split_user_at_host_one("@b", NULL, "b", 1);
|
||||||
|
test_split_user_at_host_one("a@", "a", NULL, 1);
|
||||||
|
test_split_user_at_host_one("aa@@@bb", "aa", "@@bb", 1);
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||||
|
Reference in New Issue
Block a user