From f0c57c2b1129b17e68e54d08421d1f209f1b6c57 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 13 Sep 2012 11:58:00 +0200 Subject: [PATCH 208/208] runuser: add -u to not execute shell Signed-off-by: Karel Zak --- login-utils/runuser.1 | 20 ++++--- login-utils/su-common.c | 138 +++++++++++++++++++++++++++++++----------------- login-utils/su.1 | 1 + 3 files changed, 105 insertions(+), 54 deletions(-) diff --git a/login-utils/runuser.1 b/login-utils/runuser.1 index 66ad1c4..4620165 100644 --- a/login-utils/runuser.1 +++ b/login-utils/runuser.1 @@ -3,10 +3,21 @@ runuser \- run a command with substitute user and group ID .SH SYNOPSIS .B runuser -[options...] [\-] [user [args...]] +[options] -u +.IR user +.IR "command " [ argument ...] +.LP +.B runuser +[options] [-] +[ +.IR "user " [ argument ...] +] .SH DESCRIPTION .B runuser allows to run commands with substitute user and group ID. +If the option \fB\-u\fR not given, fallback to +.B su +compatible semantic and shell is executed. The difference between the commands .B runuser and @@ -36,12 +47,7 @@ and .B LOGNAME if the target .I user -is not root). It is recommended to always use the -.B \-\-login -option (instead it's shortcut -.BR \- ) -to avoid side effects caused by mixing environments. -.PP +is not root). This version of .B runuser uses PAM for session management. diff --git a/login-utils/su-common.c b/login-utils/su-common.c index ea6864e..4e1f6b2 100644 --- a/login-utils/su-common.c +++ b/login-utils/su-common.c @@ -439,7 +439,8 @@ modify_environment (const struct passwd *pw, const char *shell) if (term) xsetenv ("TERM", term, 1); xsetenv ("HOME", pw->pw_dir, 1); - xsetenv ("SHELL", shell, 1); + if (shell) + xsetenv ("SHELL", shell, 1); xsetenv ("USER", pw->pw_name, 1); xsetenv ("LOGNAME", pw->pw_name, 1); set_path(pw); @@ -451,7 +452,8 @@ modify_environment (const struct passwd *pw, const char *shell) if (change_environment) { xsetenv ("HOME", pw->pw_dir, 1); - xsetenv ("SHELL", shell, 1); + if (shell) + xsetenv ("SHELL", shell, 1); if (getlogindefs_bool ("ALWAYS_SET_PATH", 0)) set_path(pw); @@ -571,35 +573,47 @@ restricted_shell (const char *shell) static void __attribute__((__noreturn__)) usage (int status) { - if (status != EXIT_SUCCESS) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_invocation_short_name); - else - { - fputs(USAGE_HEADER, stdout); - printf (_(" %s [options] [-] [USER [arg]...]\n"), program_invocation_short_name); - fputs (_("\n\ - Change the effective user id and group id to that of USER.\n\ - A mere - implies -l. If USER not given, assume root.\n"), stdout); - fputs(USAGE_OPTIONS, stdout); - fputs (_("\ - -, -l, --login make the shell a login shell\n\ - -c, --command pass a single command to the shell with -c\n\ - --session-command pass a single command to the shell with -c\n\ - and do not create a new session\n\ - -g --group=group specify the primary group\n\ - -G --supp-group=group specify a supplemental group\n\ - -f, --fast pass -f to the shell (for csh or tcsh)\n\ - -m, --preserve-environment do not reset environment variables\n\ - -p same as -m\n\ - -s, --shell run shell if /etc/shells allows it\n\ -"), stdout); - - fputs(USAGE_SEPARATOR, stdout); - fputs(USAGE_HELP, stdout); - fputs(USAGE_VERSION, stdout); - printf(USAGE_MAN_TAIL("su(1)")); - } + if (su_mode == RUNUSER_MODE) { + fputs(USAGE_HEADER, stdout); + printf (_(" %s [options] -u COMMAND\n"), program_invocation_short_name); + printf (_(" %s [options] [-] [USER [arg]...]\n"), program_invocation_short_name); + fputs (_("\n" + "Run COMMAND with the effective id and group id. If -u not\n" + "given, fallback to su(1) compatible semantic and shell is executed.\n" + "The options -l, -c, -f, -s are mutually exclusive to -u.\n"), stdout); + + fputs(USAGE_OPTIONS, stdout); + + fputs (_( + " -u, --user username\n"), stdout); + + } else { + fputs(USAGE_HEADER, stdout); + printf (_(" %s [options] [-] [USER [arg]...]\n"), program_invocation_short_name); + fputs (_("\n" + "Change the effective user id and group id to that of USER.\n" + "A mere - implies -l. If USER not given, assume root.\n"), stdout); + + fputs(USAGE_OPTIONS, stdout); + } + + fputs (_( + " -m, -p, --preserve-environment do not reset environment variables\n" + " -g, --group specify the primary group\n" + " -G, --supp-group specify a supplemental group\n\n"), stdout); + + fputs (_( + " -, -l, --login make the shell a login shell\n" + " -c, --command pass a single command to the shell with -c\n" + " --session-command pass a single command to the shell with -c\n" + " and do not create a new session\n" + " -f, --fast pass -f to the shell (for csh or tcsh)\n" + " -s, --shell run shell if /etc/shells allows it\n"), stdout); + + fputs(USAGE_SEPARATOR, stdout); + fputs(USAGE_HELP, stdout); + fputs(USAGE_VERSION, stdout); + printf(USAGE_MAN_TAIL(su_mode == SU_MODE ? "su(1)" : "runuser(1)")); exit (status); } @@ -635,7 +649,7 @@ int su_main (int argc, char **argv, int mode) { int optc; - const char *new_user = DEFAULT_USER; + const char *new_user = DEFAULT_USER, *runuser_user = NULL; char *command = NULL; int request_same_session = 0; char *shell = NULL; @@ -655,6 +669,7 @@ su_main (int argc, char **argv, int mode) {"shell", required_argument, NULL, 's'}, {"group", required_argument, NULL, 'g'}, {"supp-group", required_argument, NULL, 'G'}, + {"user", required_argument, NULL, 'u'}, /* runuser only */ {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {NULL, 0, NULL, 0} @@ -670,7 +685,7 @@ su_main (int argc, char **argv, int mode) simulate_login = false; change_environment = true; - while ((optc = getopt_long (argc, argv, "c:fg:G:lmps:hV", longopts, NULL)) != -1) + while ((optc = getopt_long (argc, argv, "+c:fg:G:lmps:u:hV", longopts, NULL)) != -1) { switch (optc) { @@ -720,6 +735,12 @@ su_main (int argc, char **argv, int mode) shell = optarg; break; + case 'u': + if (su_mode != RUNUSER_MODE) + usage (EXIT_FAILURE); + runuser_user = optarg; + break; + case 'h': usage(0); @@ -739,8 +760,21 @@ su_main (int argc, char **argv, int mode) simulate_login = true; ++optind; } - if (optind < argc) + + /* if not "-u " specified then fallback to classic su(1) */ + if (!runuser_user && optind < argc) new_user = argv[optind++]; + else { + /* runuser -u */ + new_user = runuser_user; + if (shell || fast_startup || command || simulate_login) { + errx(EXIT_FAILURE, + _("options --{shell,fast,command,session-command,login} and " + "--user are mutually exclusive.")); + } + if (optind == argc) + errx(EXIT_FAILURE, _("COMMAND not specified.")); + } if ((num_supp_groups || use_gid) && restricted) errx(EXIT_FAILURE, _("only root can specify alternative groups")); @@ -784,18 +818,23 @@ su_main (int argc, char **argv, int mode) if (request_same_session || !command || !pw->pw_uid) same_session = 1; - if (!shell && !change_environment) - shell = getenv ("SHELL"); - if (shell && getuid () != 0 && restricted_shell (pw->pw_shell)) - { - /* The user being su'd to has a nonstandard shell, and so is - probably a uucp account or has restricted access. Don't - compromise the account by allowing access with a standard - shell. */ - warnx (_("using restricted shell %s"), pw->pw_shell); - shell = NULL; - } - shell = xstrdup (shell ? shell : pw->pw_shell); + /* initialize shell variable only if "-u " not specified */ + if (runuser_user) { + shell = NULL; + } else { + if (!shell && !change_environment) + shell = getenv ("SHELL"); + if (shell && getuid () != 0 && restricted_shell (pw->pw_shell)) + { + /* The user being su'd to has a nonstandard shell, and so is + probably a uucp account or has restricted access. Don't + compromise the account by allowing access with a standard + shell. */ + warnx (_("using restricted shell %s"), pw->pw_shell); + shell = NULL; + } + shell = xstrdup (shell ? shell : pw->pw_shell); + } init_groups (pw, groups, num_supp_groups); @@ -814,7 +853,12 @@ su_main (int argc, char **argv, int mode) if (simulate_login && chdir (pw->pw_dir) != 0) warn (_("warning: cannot change directory to %s"), pw->pw_dir); - run_shell (shell, command, argv + optind, max (0, argc - optind)); + if (shell) + run_shell (shell, command, argv + optind, max (0, argc - optind)); + else { + execvp(argv[optind], &argv[optind]); + err(EXIT_FAILURE, _("executing %s failed"), argv[optind]); + } } // vim: sw=2 cinoptions=>4,n-2,{2,^-2,\:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 diff --git a/login-utils/su.1 b/login-utils/su.1 index 59e1731..c82b941 100644 --- a/login-utils/su.1 +++ b/login-utils/su.1 @@ -216,6 +216,7 @@ command specific logindef config file global logindef config file .PD 1 .SH "SEE ALSO" +.BR runuser (8), .BR pam (8), .BR shells (5), .BR login.defs (5) -- 1.7.11.7