summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--man/run0.xml16
-rw-r--r--src/run/run.c35
-rw-r--r--src/shared/parse-argument.c20
-rw-r--r--src/shared/parse-argument.h1
-rwxr-xr-xtest/units/TEST-35-LOGIN.sh21
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() {