diff options
-rw-r--r-- | man/run0.xml | 16 | ||||
-rw-r--r-- | src/run/run.c | 35 | ||||
-rw-r--r-- | src/shared/parse-argument.c | 20 | ||||
-rw-r--r-- | src/shared/parse-argument.h | 1 | ||||
-rwxr-xr-x | test/units/TEST-35-LOGIN.sh | 21 |
5 files changed, 93 insertions, 0 deletions
diff --git a/man/run0.xml b/man/run0.xml index 16774813d4..59aa6d05d9 100644 --- a/man/run0.xml +++ b/man/run0.xml @@ -225,6 +225,21 @@ </varlistentry> <varlistentry> + <term><option>--lightweight=<replaceable>BOOLEAN</replaceable></option></term> + + <listitem><para>Controls whether to activate the per-user service manager for the target user. By + default if the target user is <literal>root</literal> or a system user the per-user service manager + is not activated as effect of the <command>run0</command> invocation, otherwise it is.</para> + + <para>This ultimately controls the <varname>$XDG_SESSION_CLASS</varname> variable + <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry> + respects.</para> + + <xi:include href="version-info.xml" xpointer="v258"/> + </listitem> + </varlistentry> + + <varlistentry> <term><option>--machine=</option></term> <listitem> @@ -321,6 +336,7 @@ <member><citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry></member> <member><citerefentry project='man-pages'><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry></member> <member><citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member> + <member><citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry></member> </simplelist></para> </refsect1> diff --git a/src/run/run.c b/src/run/run.c index 1f2507c10e..7538029548 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -88,6 +88,7 @@ static bool arg_ignore_failure = false; static char *arg_background = NULL; static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF; static char *arg_shell_prompt_prefix = NULL; +static int arg_lightweight = -1; STATIC_DESTRUCTOR_REGISTER(arg_description, freep); STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep); @@ -199,6 +200,8 @@ static int help_sudo_mode(void) { " --pty Request allocation of a pseudo TTY for stdio\n" " --pipe Request direct pipe for stdio\n" " --shell-prompt-prefix=PREFIX Set $SHELL_PROMPT_PREFIX\n" + " --lightweight=BOOLEAN Control whether to register a session with service manager\n" + " or without\n" "\nSee the %s for details.\n", program_invocation_short_name, ansi_highlight(), @@ -778,6 +781,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { ARG_PTY, ARG_PIPE, ARG_SHELL_PROMPT_PREFIX, + ARG_LIGHTWEIGHT, }; /* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions @@ -802,6 +806,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { { "pty", no_argument, NULL, ARG_PTY }, { "pipe", no_argument, NULL, ARG_PIPE }, { "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX }, + { "lightweight", required_argument, NULL, ARG_LIGHTWEIGHT }, {}, }; @@ -914,6 +919,12 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { return r; break; + case ARG_LIGHTWEIGHT: + r = parse_tristate_argument("--lightweight=", optarg, &arg_lightweight); + if (r < 0) + return r; + break; + case '?': return -EINVAL; @@ -947,6 +958,8 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { if (IN_SET(arg_stdio, ARG_STDIO_NONE, ARG_STDIO_AUTO)) arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ? ARG_STDIO_PTY : ARG_STDIO_DIRECT; + log_debug("Using %s stdio mode.", arg_stdio == ARG_STDIO_PTY ? "pty" : "direct"); + arg_expand_environment = false; arg_send_sighup = true; @@ -1045,6 +1058,28 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) { return log_error_errno(r, "Failed to set $SHELL_PROMPT_PREFIX environment variable: %m"); } + /* When using run0 to acquire privileges temporarily, let's not pull in session manager by + * default. Note that pam_logind/systemd-logind doesn't distinguish between run0-style privilege + * escalation on a TTY and first class (getty-style) TTY logins (and thus gives root a per-session + * manager for interactive TTY sessions), hence let's override the logic explicitly here. We only do + * this for root though, under the assumption that if a regular user temporarily transitions into + * another regular user it's a better default that the full user environment is uniformly + * available. */ + if (arg_lightweight < 0 && !strv_env_get(arg_environment, "XDG_SESSION_CLASS") && privileged_execution()) + arg_lightweight = true; + + if (arg_lightweight >= 0) { + const char *class = + arg_lightweight ? (arg_stdio == ARG_STDIO_PTY ? (privileged_execution() ? "user-early-light" : "user-light") : "background-light") : + (arg_stdio == ARG_STDIO_PTY ? (privileged_execution() ? "user-early" : "user") : "background"); + + log_debug("Setting XDG_SESSION_CLASS to '%s'.", class); + + r = strv_env_assign(&arg_environment, "XDG_SESSION_CLASS", class); + if (r < 0) + return log_error_errno(r, "Failed to set $XDG_SESSION_CLASS environment variable: %m"); + } + return 1; } diff --git a/src/shared/parse-argument.c b/src/shared/parse-argument.c index e6159c1482..177028e424 100644 --- a/src/shared/parse-argument.c +++ b/src/shared/parse-argument.c @@ -31,6 +31,26 @@ int parse_boolean_argument(const char *optname, const char *s, bool *ret) { } } +int parse_tristate_argument(const char *optname, const char *s, int *ret) { + int r; + + if (s) { + r = parse_boolean(s); + if (r < 0) + return log_error_errno(r, "Failed to parse boolean argument to %s: %s.", optname, s); + + if (ret) + *ret = r; + + return r; + } else { + if (ret) + *ret = -1; + + return 0; + } +} + int parse_json_argument(const char *s, sd_json_format_flags_t *ret) { assert(s); assert(ret); diff --git a/src/shared/parse-argument.h b/src/shared/parse-argument.h index 6a1a67aef7..bd577033b8 100644 --- a/src/shared/parse-argument.h +++ b/src/shared/parse-argument.h @@ -6,6 +6,7 @@ #include "sd-json.h" int parse_boolean_argument(const char *optname, const char *s, bool *ret); +int parse_tristate_argument(const char *optname, const char *s, int *ret); int parse_json_argument(const char *s, sd_json_format_flags_t *ret); int parse_path_argument(const char *path, bool suppress_root, char **arg); int parse_signal_argument(const char *s, int *ret); diff --git a/test/units/TEST-35-LOGIN.sh b/test/units/TEST-35-LOGIN.sh index 9a5c781001..5a83b5847a 100755 --- a/test/units/TEST-35-LOGIN.sh +++ b/test/units/TEST-35-LOGIN.sh @@ -713,6 +713,10 @@ testcase_background() { TRANSIENTUNIT2="bgg$RANDOM.service" TRANSIENTUNIT3="bggg$RANDOM.service" TRANSIENTUNIT4="bgggg$RANDOM.service" + RUN0UNIT0="run0$RANDOM.service" + RUN0UNIT1="runn0$RANDOM.service" + RUN0UNIT2="runnn0$RANDOM.service" + RUN0UNIT3="runnnn0$RANDOM.service" trap background_at_return RETURN @@ -758,6 +762,23 @@ EOF systemd-run -u "$TRANSIENTUNIT4" -p PAMName="$PAMSERVICE" -p "Environment=XDG_SESSION_TYPE=tty" -p Type=exec -p User=lightuser sleep infinity loginctl | grep lightuser | grep -q user-light systemctl stop "$TRANSIENTUNIT4" + + # Now check that run0's session class control works + systemd-run --service-type=notify run0 -u lightuser --unit="$RUN0UNIT0" sleep infinity + loginctl | grep lightuser | grep -q "background-light " + systemctl stop "$RUN0UNIT0" + + systemd-run --service-type=notify run0 -u lightuser --unit="$RUN0UNIT1" --lightweight=yes sleep infinity + loginctl | grep lightuser | grep -q "background-light " + systemctl stop "$RUN0UNIT1" + + systemd-run --service-type=notify run0 -u lightuser --unit="$RUN0UNIT2" --lightweight=no sleep infinity + loginctl | grep lightuser | grep -q "background " + systemctl stop "$RUN0UNIT2" + + systemd-run --service-type=notify run0 -u root --unit="$RUN0UNIT3" sleep infinity + loginctl | grep root | grep -q "background-light " + systemctl stop "$RUN0UNIT3" } testcase_varlink() { |