diff --git a/man/run0.xml b/man/run0.xml
index 5ad91240d5..ee2074b4ab 100644
--- a/man/run0.xml
+++ b/man/run0.xml
@@ -139,8 +139,8 @@
Switches to the specified user/group. If not specified defaults to
- root, unless is used (see below), in which case this
- defaults to the invoking user.
+ root, unless or are used (see
+ below), in which case this defaults to the invoking user.
@@ -290,6 +290,17 @@
+
+
+
+ If specified, run0 will elevate the privileges of the selected user (using
+ ) or the current user if no user is explicitly selected. Currently this means
+ we give the user all available capabilities, but other privileges may be granted in the future as
+ well when using this option.
+
+
+
+
diff --git a/shell-completion/bash/run0 b/shell-completion/bash/run0
index 0850b6ef96..1bba3b8145 100644
--- a/shell-completion/bash/run0
+++ b/shell-completion/bash/run0
@@ -37,7 +37,7 @@ _run0() {
--machine --unit --property --description --slice -u --user -g --group --nice -D --chdir
--setenv --background
)
- local OPTS="${opts_with_values[*]} -h --help -V --version --no-ask-password --slice-inherit"
+ local OPTS="${opts_with_values[*]} -h --help -V --version --no-ask-password --slice-inherit --empower"
local i
for (( i=1; i <= COMP_CWORD; i++ )); do
diff --git a/shell-completion/zsh/_run0 b/shell-completion/zsh/_run0
index 5998f41016..dc95486bef 100644
--- a/shell-completion/zsh/_run0
+++ b/shell-completion/zsh/_run0
@@ -52,6 +52,7 @@ local -a args=(
'--machine=[Execute the operation on a local container]:machine:_sd_machines'
{-h,--help}'[Show the help text and exit]'
'--version[Print a short version string and exit]'
+ '--empower[Give privileges to selected or current user]'
)
_arguments -S $args '*:: :{_normal -p $service}'
diff --git a/src/run/run.c b/src/run/run.c
index 1c01d4485b..b5030b9cb7 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -25,6 +25,7 @@
#include "bus-util.h"
#include "bus-wait-for-jobs.h"
#include "calendarspec.h"
+#include "capability-util.h"
#include "capsule-util.h"
#include "chase.h"
#include "env-util.h"
@@ -117,6 +118,7 @@ static char *arg_shell_prompt_prefix = NULL;
static int arg_lightweight = -1;
static char *arg_area = NULL;
static bool arg_via_shell = false;
+static bool arg_empower = false;
STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
@@ -244,6 +246,7 @@ static int help_sudo_mode(void) {
" --lightweight=BOOLEAN Control whether to register a session with service manager\n"
" or without\n"
" --area=AREA Home area to log into\n"
+ " --empower Give privileges to selected or current user\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
@@ -253,11 +256,15 @@ static int help_sudo_mode(void) {
return 0;
}
+static bool become_root(void) {
+ return !arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0");
+}
+
static bool privileged_execution(void) {
if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
return false;
- return !arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0");
+ return become_root() || arg_empower;
}
static int add_timer_property(const char *name, const char *val) {
@@ -859,6 +866,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
ARG_LIGHTWEIGHT,
ARG_AREA,
ARG_VIA_SHELL,
+ ARG_EMPOWER,
};
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
@@ -888,6 +896,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
{ "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX },
{ "lightweight", required_argument, NULL, ARG_LIGHTWEIGHT },
{ "area", required_argument, NULL, ARG_AREA },
+ { "empower", no_argument, NULL, ARG_EMPOWER },
{},
};
@@ -1027,6 +1036,10 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
arg_via_shell = true;
break;
+ case ARG_EMPOWER:
+ arg_empower = true;
+ break;
+
case '?':
return -EINVAL;
@@ -1034,9 +1047,13 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
assert_not_reached();
}
- if (!arg_exec_user && arg_area) {
+ if (!arg_exec_user && (arg_area || arg_empower)) {
/* If the user specifies --area= but not --user= then consider this an area switch request,
- * and default to logging into our own account */
+ * and default to logging into our own account.
+ *
+ * If the user specifies --empower but not --user= then consider this a request to empower
+ * the current user. */
+
arg_exec_user = getusername_malloc();
if (!arg_exec_user)
return log_oom();
@@ -1211,8 +1228,8 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
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");
+ arg_lightweight ? (arg_stdio == ARG_STDIO_PTY ? (become_root() ? "user-early-light" : "user-light") : "background-light") :
+ (arg_stdio == ARG_STDIO_PTY ? (become_root() ? "user-early" : "user") : "background");
log_debug("Setting XDG_SESSION_CLASS to '%s'.", class);
@@ -1371,6 +1388,12 @@ static int transient_service_set_properties(sd_bus_message *m, const char *pty_p
return bus_log_create_error(r);
}
+ if (arg_empower) {
+ r = sd_bus_message_append(m, "(sv)", "AmbientCapabilities", "t", CAP_MASK_ALL);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
if (arg_nice_set) {
r = sd_bus_message_append(m, "(sv)", "Nice", "i", arg_nice);
if (r < 0)
diff --git a/test/units/TEST-74-AUX-UTILS.run.sh b/test/units/TEST-74-AUX-UTILS.run.sh
index c7ca8ce615..f0799f6ca6 100755
--- a/test/units/TEST-74-AUX-UTILS.run.sh
+++ b/test/units/TEST-74-AUX-UTILS.run.sh
@@ -297,6 +297,14 @@ if [[ -e /usr/lib/pam.d/systemd-run0 ]] || [[ -e /etc/pam.d/systemd-run0 ]]; the
# Validate when we invoke run0 without a tty, that depending on --pty it either allocates a tty or not
assert_neq "$(run0 --pty tty < /dev/null)" "not a tty"
assert_eq "$(run0 --pipe tty < /dev/null)" "not a tty"
+
+ # Validate that --empower gives all capabilities to a non-root user.
+ caps="$(run0 -u testuser --empower systemd-analyze capability --mask "$(grep CapEff /proc/self/status | cut -d':' -f2)" --json=pretty | jq -r length)"
+ assert_neq "$caps" "0"
+
+ run0 -u testuser --empower touch /run/empower
+ assert_eq "$(stat -c "%U" /run/empower)" testuser
+ rm /run/empower
fi
# Tests whether intermediate disconnects corrupt us (modified testcase from https://github.com/systemd/systemd/issues/27204)