core: accept "|" ExecStart= prefix to spawn target user's shell; teach run0 about the new logic (#37071)
I've always been reluctant to invoke the current user's shell in another user's context, hence was fully grounded in `sudo -i`. With this bit in place `run0` will finally be feature-complete on my side ;-)
This commit is contained in:
+48
-12
@@ -4588,12 +4588,11 @@ int exec_invoke(
|
||||
const CGroupContext *cgroup_context,
|
||||
int *exit_status) {
|
||||
|
||||
_cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **joined_exec_search_path = NULL, **accum_env = NULL, **replaced_argv = NULL;
|
||||
_cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **joined_exec_search_path = NULL, **accum_env = NULL;
|
||||
int r;
|
||||
const char *username = NULL, *groupname = NULL;
|
||||
_cleanup_free_ char *home_buffer = NULL, *memory_pressure_path = NULL, *own_user = NULL;
|
||||
const char *pwent_home = NULL, *shell = NULL;
|
||||
char **final_argv = NULL;
|
||||
dev_t journal_stream_dev = 0;
|
||||
ino_t journal_stream_ino = 0;
|
||||
bool needs_sandboxing, /* Do we need to set up full sandboxing? (i.e. all namespacing, all MAC stuff, caps, yadda yadda */
|
||||
@@ -4823,7 +4822,7 @@ int exec_invoke(
|
||||
|
||||
if (context->user)
|
||||
u = context->user;
|
||||
else if (context->pam_name) {
|
||||
else if (context->pam_name || FLAGS_SET(command->flags, EXEC_COMMAND_VIA_SHELL)) {
|
||||
/* If PAM is enabled but no user name is explicitly selected, then use our own one. */
|
||||
own_user = getusername_malloc();
|
||||
if (!own_user) {
|
||||
@@ -5422,17 +5421,26 @@ int exec_invoke(
|
||||
/* Now that the mount namespace has been set up and privileges adjusted, let's look for the thing we
|
||||
* shall execute. */
|
||||
|
||||
const char *path = command->path;
|
||||
|
||||
if (FLAGS_SET(command->flags, EXEC_COMMAND_VIA_SHELL)) {
|
||||
if (shell_is_placeholder(shell)) {
|
||||
log_debug("Shell prefixing requested for user without default shell, using /bin/sh: %s",
|
||||
strna(username));
|
||||
assert(streq(path, _PATH_BSHELL));
|
||||
} else
|
||||
path = shell;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *executable = NULL;
|
||||
_cleanup_close_ int executable_fd = -EBADF;
|
||||
r = find_executable_full(command->path, /* root= */ NULL, context->exec_search_path, false, &executable, &executable_fd);
|
||||
r = find_executable_full(path, /* root= */ NULL, context->exec_search_path, false, &executable, &executable_fd);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_EXEC;
|
||||
log_struct_errno(LOG_NOTICE, r,
|
||||
LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED_STR),
|
||||
LOG_EXEC_MESSAGE(params,
|
||||
"Unable to locate executable '%s': %m",
|
||||
command->path),
|
||||
LOG_ITEM("EXECUTABLE=%s", command->path));
|
||||
LOG_EXEC_MESSAGE(params, "Unable to locate executable '%s': %m", path),
|
||||
LOG_ITEM("EXECUTABLE=%s", path));
|
||||
/* If the error will be ignored by manager, tune down the log level here. Missing executable
|
||||
* is very much expected in this case. */
|
||||
return r != -ENOMEM && FLAGS_SET(command->flags, EXEC_COMMAND_IGNORE_FAILURE) ? 1 : r;
|
||||
@@ -5843,10 +5851,13 @@ int exec_invoke(
|
||||
strv_free_and_replace(accum_env, ee);
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(command->flags, EXEC_COMMAND_NO_ENV_EXPAND)) {
|
||||
_cleanup_strv_free_ char **replaced_argv = NULL, **argv_via_shell = NULL;
|
||||
char **final_argv = FLAGS_SET(command->flags, EXEC_COMMAND_VIA_SHELL) ? strv_skip(command->argv, 1) : command->argv;
|
||||
|
||||
if (final_argv && !FLAGS_SET(command->flags, EXEC_COMMAND_NO_ENV_EXPAND)) {
|
||||
_cleanup_strv_free_ char **unset_variables = NULL, **bad_variables = NULL;
|
||||
|
||||
r = replace_env_argv(command->argv, accum_env, &replaced_argv, &unset_variables, &bad_variables);
|
||||
r = replace_env_argv(final_argv, accum_env, &replaced_argv, &unset_variables, &bad_variables);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_MEMORY;
|
||||
return log_error_errno(r, "Failed to replace environment variables: %m");
|
||||
@@ -5862,8 +5873,33 @@ int exec_invoke(
|
||||
_cleanup_free_ char *jb = strv_join(bad_variables, ", ");
|
||||
log_warning("Invalid environment variable name evaluates to an empty string: %s", strna(jb));
|
||||
}
|
||||
} else
|
||||
final_argv = command->argv;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(command->flags, EXEC_COMMAND_VIA_SHELL)) {
|
||||
r = strv_extendf(&argv_via_shell, "%s%s", command->argv[0][0] == '-' ? "-" : "", path);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_MEMORY;
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (!strv_isempty(final_argv)) {
|
||||
_cleanup_free_ char *cmdline_joined = NULL;
|
||||
|
||||
cmdline_joined = strv_join(final_argv, " ");
|
||||
if (!cmdline_joined) {
|
||||
*exit_status = EXIT_MEMORY;
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = strv_extend_many(&argv_via_shell, "-c", cmdline_joined);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_MEMORY;
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
final_argv = argv_via_shell;
|
||||
}
|
||||
|
||||
log_command_line(context, params, "Executing", executable, final_argv);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user