mirror of
https://github.com/systemd/systemd.git
synced 2025-01-26 14:04:03 +03:00
Merge pull request #20157 from keszybz/numerical-uids-in--M
Allow numerical UIDs in systemctl -M uid@ and similar
This commit is contained in:
commit
5c8cf104e7
@ -8,6 +8,7 @@
|
||||
#include "escape.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "macro.h"
|
||||
#include "strv.h"
|
||||
#include "utf8.h"
|
||||
|
||||
int cescape_char(char c, char *buf) {
|
||||
@ -542,3 +543,23 @@ char* shell_maybe_quote(const char *s, ShellEscapeFlags flags) {
|
||||
|
||||
return str_realloc(buf);
|
||||
}
|
||||
|
||||
char* quote_command_line(char **argv) {
|
||||
_cleanup_free_ char *result = NULL;
|
||||
|
||||
assert(argv);
|
||||
|
||||
char **a;
|
||||
STRV_FOREACH(a, argv) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
t = shell_maybe_quote(*a, SHELL_ESCAPE_EMPTY);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
if (!strextend_with_separator(&result, " ", t))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return TAKE_PTR(result);
|
||||
}
|
||||
|
@ -68,3 +68,4 @@ char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFl
|
||||
|
||||
char* shell_escape(const char *s, const char *bad);
|
||||
char* shell_maybe_quote(const char *s, ShellEscapeFlags flags);
|
||||
char* quote_command_line(char **argv);
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
#include "errno-list.h"
|
||||
#include "escape.h"
|
||||
#include "execute.h"
|
||||
#include "exit-status.h"
|
||||
#include "fd-util.h"
|
||||
@ -3638,8 +3639,6 @@ static int compile_suggested_paths(const ExecContext *c, const ExecParameters *p
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *exec_command_line(char **argv);
|
||||
|
||||
static int exec_parameters_get_cgroup_path(const ExecParameters *params, char **ret) {
|
||||
bool using_subcgroup;
|
||||
char *p;
|
||||
@ -3842,7 +3841,7 @@ static int exec_child(
|
||||
const char *vc = params->confirm_spawn;
|
||||
_cleanup_free_ char *cmdline = NULL;
|
||||
|
||||
cmdline = exec_command_line(command->argv);
|
||||
cmdline = quote_command_line(command->argv);
|
||||
if (!cmdline) {
|
||||
*exit_status = EXIT_MEMORY;
|
||||
return log_oom();
|
||||
@ -4688,12 +4687,15 @@ static int exec_child(
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
|
||||
line = exec_command_line(final_argv);
|
||||
if (line)
|
||||
log_unit_struct(unit, LOG_DEBUG,
|
||||
"EXECUTABLE=%s", executable,
|
||||
LOG_UNIT_MESSAGE(unit, "Executing: %s", line),
|
||||
LOG_UNIT_INVOCATION_ID(unit));
|
||||
line = quote_command_line(final_argv);
|
||||
if (!line) {
|
||||
*exit_status = EXIT_MEMORY;
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
log_unit_struct(unit, LOG_DEBUG,
|
||||
"EXECUTABLE=%s", executable,
|
||||
LOG_UNIT_MESSAGE(unit, "Executing: %s", line));
|
||||
}
|
||||
|
||||
if (exec_fd >= 0) {
|
||||
@ -4777,7 +4779,7 @@ int exec_spawn(Unit *unit,
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
|
||||
|
||||
line = exec_command_line(command->argv);
|
||||
line = quote_command_line(command->argv);
|
||||
if (!line)
|
||||
return log_oom();
|
||||
|
||||
@ -5992,46 +5994,6 @@ void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) {
|
||||
prefix, s->status);
|
||||
}
|
||||
|
||||
static char *exec_command_line(char **argv) {
|
||||
size_t k;
|
||||
char *n, *p, **a;
|
||||
bool first = true;
|
||||
|
||||
assert(argv);
|
||||
|
||||
k = 1;
|
||||
STRV_FOREACH(a, argv)
|
||||
k += strlen(*a)+3;
|
||||
|
||||
n = new(char, k);
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
p = n;
|
||||
STRV_FOREACH(a, argv) {
|
||||
|
||||
if (!first)
|
||||
*(p++) = ' ';
|
||||
else
|
||||
first = false;
|
||||
|
||||
if (strpbrk(*a, WHITESPACE)) {
|
||||
*(p++) = '\'';
|
||||
p = stpcpy(p, *a);
|
||||
*(p++) = '\'';
|
||||
} else
|
||||
p = stpcpy(p, *a);
|
||||
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
|
||||
/* FIXME: this doesn't really handle arguments that have
|
||||
* spaces and ticks in them */
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
|
||||
_cleanup_free_ char *cmd = NULL;
|
||||
const char *prefix2;
|
||||
@ -6042,7 +6004,7 @@ static void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
|
||||
prefix = strempty(prefix);
|
||||
prefix2 = strjoina(prefix, "\t");
|
||||
|
||||
cmd = exec_command_line(c->argv);
|
||||
cmd = quote_command_line(c->argv);
|
||||
fprintf(f,
|
||||
"%sCommand Line: %s\n",
|
||||
prefix, cmd ? cmd : strerror_safe(ENOMEM));
|
||||
|
@ -37,11 +37,11 @@ int bus_container_connect_socket(sd_bus *b) {
|
||||
|
||||
r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_debug_errno(r, "Failed to open namespace of PID "PID_FMT": %m", b->nspid);
|
||||
|
||||
b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||
if (b->input_fd < 0)
|
||||
return -errno;
|
||||
return log_debug_errno(errno, "Failed to create a socket: %m");
|
||||
|
||||
b->input_fd = fd_move_above_stdio(b->input_fd);
|
||||
|
||||
@ -50,12 +50,12 @@ int bus_container_connect_socket(sd_bus *b) {
|
||||
bus_socket_setup(b);
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
|
||||
return -errno;
|
||||
return log_debug_errno(errno, "Failed to create a socket pair: %m");
|
||||
|
||||
r = namespace_fork("(sd-buscntrns)", "(sd-buscntr)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG,
|
||||
pidnsfd, mntnsfd, -1, usernsfd, rootfd, &child);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_debug_errno(r, "Failed to create namespace for (sd-buscntr): %m");
|
||||
if (r == 0) {
|
||||
pair[0] = safe_close(pair[0]);
|
||||
|
||||
@ -80,20 +80,22 @@ int bus_container_connect_socket(sd_bus *b) {
|
||||
|
||||
n = read(pair[0], &error_buf, sizeof(error_buf));
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
return log_debug_errno(errno, "Failed to read error status from (sd-buscntr): %m");
|
||||
|
||||
if (n > 0) {
|
||||
if (n != sizeof(error_buf))
|
||||
return -EIO;
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||
"Read error status of unexpected length %zd from (sd-buscntr): %m", n);
|
||||
|
||||
if (error_buf < 0)
|
||||
return -EIO;
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Got unexpected error status from (sd-buscntr): %m");
|
||||
|
||||
if (error_buf == EINPROGRESS)
|
||||
return 1;
|
||||
|
||||
if (error_buf > 0)
|
||||
return -error_buf;
|
||||
return log_debug_errno(error_buf, "Got error from (sd-buscntr): %m");
|
||||
}
|
||||
|
||||
return bus_socket_start_auth(b);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "bus-internal.h"
|
||||
#include "bus-message.h"
|
||||
#include "bus-socket.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
@ -962,8 +963,17 @@ int bus_socket_exec(sd_bus *b) {
|
||||
assert(b->exec_path);
|
||||
assert(b->busexec_pid == 0);
|
||||
|
||||
log_debug("sd-bus: starting bus%s%s with %s...",
|
||||
b->description ? " " : "", strempty(b->description), b->exec_path);
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
|
||||
if (b->exec_argv)
|
||||
line = quote_command_line(b->exec_argv);
|
||||
|
||||
log_debug("sd-bus: starting bus%s%s with %s%s",
|
||||
b->description ? " " : "", strempty(b->description),
|
||||
line ?: b->exec_path,
|
||||
b->exec_argv && !line ? "…" : "");
|
||||
}
|
||||
|
||||
r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s);
|
||||
if (r < 0)
|
||||
@ -984,10 +994,8 @@ int bus_socket_exec(sd_bus *b) {
|
||||
|
||||
if (b->exec_argv)
|
||||
execvp(b->exec_path, b->exec_argv);
|
||||
else {
|
||||
const char *argv[] = { b->exec_path, NULL };
|
||||
execvp(b->exec_path, (char**) argv);
|
||||
}
|
||||
else
|
||||
execvp(b->exec_path, STRV_MAKE(b->exec_path));
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "user-util.h"
|
||||
@ -1617,7 +1618,7 @@ static int user_and_machine_valid(const char *user_and_machine) {
|
||||
if (!user)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!isempty(user) && !valid_user_group_name(user, VALID_USER_RELAX))
|
||||
if (!isempty(user) && !valid_user_group_name(user, VALID_USER_RELAX | VALID_USER_ALLOW_NUMERIC))
|
||||
return false;
|
||||
|
||||
h++;
|
||||
@ -1648,17 +1649,25 @@ static int user_and_machine_equivalent(const char *user_and_machine) {
|
||||
|
||||
/* 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"))
|
||||
uid_t uid = geteuid();
|
||||
|
||||
if (uid == 0 && STR_IN_SET(user_and_machine, ".host", "root@.host", "0@.host"))
|
||||
return true;
|
||||
|
||||
/* Otherwise, we have to figure our user name, and compare things with that. */
|
||||
un = getusername_malloc();
|
||||
if (!un)
|
||||
return -ENOMEM;
|
||||
/* Otherwise, we have to figure out our user id and name, and compare things with that. */
|
||||
char buf[DECIMAL_STR_MAX(uid_t)];
|
||||
xsprintf(buf, UID_FMT, uid);
|
||||
|
||||
f = startswith(user_and_machine, un);
|
||||
if (!f)
|
||||
return false;
|
||||
f = startswith(user_and_machine, buf);
|
||||
if (!f) {
|
||||
un = getusername_malloc();
|
||||
if (!un)
|
||||
return -ENOMEM;
|
||||
|
||||
f = startswith(user_and_machine, un);
|
||||
if (!f)
|
||||
return false;
|
||||
}
|
||||
|
||||
return STR_IN_SET(f, "@", "@.host");
|
||||
}
|
||||
|
@ -8,6 +8,8 @@
|
||||
static void test_cescape(void) {
|
||||
_cleanup_free_ char *t;
|
||||
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(t = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313"));
|
||||
assert_se(streq(t, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313"));
|
||||
}
|
||||
@ -15,6 +17,8 @@ static void test_cescape(void) {
|
||||
static void test_xescape(void) {
|
||||
_cleanup_free_ char *t;
|
||||
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(t = xescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313", ""));
|
||||
assert_se(streq(t, "abc\\x5c\"\\x08\\x0c\\x0a\\x0d\\x09\\x0b\\x07\\x03\\x7f\\x9c\\xcb"));
|
||||
}
|
||||
@ -26,6 +30,8 @@ static void test_xescape_full(bool eight_bits) {
|
||||
const unsigned full_fit = !eight_bits ? 55 : 46;
|
||||
XEscapeFlags flags = eight_bits * XESCAPE_8_BIT;
|
||||
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
for (unsigned i = 0; i < 60; i++) {
|
||||
_cleanup_free_ char *t, *q;
|
||||
|
||||
@ -60,6 +66,8 @@ static void test_xescape_full(bool eight_bits) {
|
||||
static void test_cunescape(void) {
|
||||
_cleanup_free_ char *unescaped;
|
||||
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0);
|
||||
assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0);
|
||||
assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00"));
|
||||
@ -133,6 +141,8 @@ static void test_shell_escape_one(const char *s, const char *bad, const char *ex
|
||||
}
|
||||
|
||||
static void test_shell_escape(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
test_shell_escape_one("", "", "");
|
||||
test_shell_escape_one("\\", "", "\\\\");
|
||||
test_shell_escape_one("foobar", "", "foobar");
|
||||
@ -150,6 +160,7 @@ static void test_shell_maybe_quote_one(const char *s, ShellEscapeFlags flags, co
|
||||
}
|
||||
|
||||
static void test_shell_maybe_quote(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
test_shell_maybe_quote_one("", 0, "");
|
||||
test_shell_maybe_quote_one("", SHELL_ESCAPE_EMPTY, "\"\"");
|
||||
@ -192,6 +203,29 @@ static void test_shell_maybe_quote(void) {
|
||||
test_shell_maybe_quote_one("głąb\002\003rząd", SHELL_ESCAPE_POSIX, "$'głąb\\002\\003rząd'");
|
||||
}
|
||||
|
||||
static void test_quote_command_line_one(char **argv, const char *expected) {
|
||||
_cleanup_free_ char *s;
|
||||
|
||||
assert_se(s = quote_command_line(argv));
|
||||
log_info("%s", s);
|
||||
assert_se(streq(s, expected));
|
||||
}
|
||||
|
||||
static void test_quote_command_line(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
test_quote_command_line_one(STRV_MAKE("true", "true"),
|
||||
"true true");
|
||||
test_quote_command_line_one(STRV_MAKE("true", "with a space"),
|
||||
"true \"with a space\"");
|
||||
test_quote_command_line_one(STRV_MAKE("true", "with a 'quote'"),
|
||||
"true \"with a 'quote'\"");
|
||||
test_quote_command_line_one(STRV_MAKE("true", "with a \"quote\""),
|
||||
"true \"with a \\\"quote\\\"\"");
|
||||
test_quote_command_line_one(STRV_MAKE("true", "$dollar"),
|
||||
"true \"\\$dollar\"");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
@ -202,6 +236,7 @@ int main(int argc, char *argv[]) {
|
||||
test_cunescape();
|
||||
test_shell_escape();
|
||||
test_shell_maybe_quote();
|
||||
test_quote_command_line();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user