| diff -urNp coreutils-8.1-orig/AUTHORS coreutils-8.1/AUTHORS |
| |
| |
| @@ -65,6 +65,7 @@ readlink: Dmitry V. Levin |
| rm: Paul Rubin, David MacKenzie, Richard M. Stallman, Jim Meyering |
| rmdir: David MacKenzie |
| runcon: Russell Coker |
| +runuser: David MacKenzie, Dan Walsh |
| seq: Ulrich Drepper |
| sha1sum: Ulrich Drepper, Scott Miller, David Madore |
| sha224sum: Ulrich Drepper, Scott Miller, David Madore |
| diff -urNp coreutils-8.1-orig/man/help2man coreutils-8.1/man/help2man |
| |
| |
| @@ -556,6 +556,9 @@ while (length) |
| $include{$sect} .= $content; |
| } |
| |
| +# There is no info documentation for runuser (shared with su). |
| +$opt_no_info = 1 if $program eq 'runuser'; |
| + |
| # Refer to the real documentation. |
| unless ($opt_no_info) |
| { |
| diff -urNp coreutils-8.1-orig/man/Makefile.am coreutils-8.1/man/Makefile.am |
| |
| |
| @@ -94,6 +94,7 @@ readlink.1: $(common_dep) $(srcdir)/read |
| rm.1: $(common_dep) $(srcdir)/rm.x ../src/rm.c |
| rmdir.1: $(common_dep) $(srcdir)/rmdir.x ../src/rmdir.c |
| runcon.1: $(common_dep) $(srcdir)/runcon.x ../src/runcon.c |
| +runuser.1: $(common_dep) $(srcdir)/runuser.x ../src/su.c |
| seq.1: $(common_dep) $(srcdir)/seq.x ../src/seq.c |
| sha1sum.1: $(common_dep) $(srcdir)/sha1sum.x ../src/md5sum.c |
| sha224sum.1: $(common_dep) $(srcdir)/sha224sum.x ../src/md5sum.c |
| diff -urNp coreutils-8.1-orig/man/runuser.x coreutils-8.1/man/runuser.x |
| |
| |
| @@ -0,0 +1,12 @@ |
| +[NAME] |
| +runuser \- run a shell with substitute user and group IDs |
| +[DESCRIPTION] |
| +.\" Add any additional description here |
| +[SEE ALSO] |
| +.TP |
| +More detailed Texinfo documentation could be found by command |
| +.TP |
| +\t\fBinfo coreutils \(aqsu invocation\(aq\fR\t |
| +.TP |
| +since the command \fBrunuser\fR is trimmed down version of command \fBsu\fR. |
| +.br |
| diff -urNp coreutils-8.1-orig/README coreutils-8.1/README |
| |
| |
| @@ -12,10 +12,10 @@ The programs that can be built with this |
| factor false fmt fold groups head hostid hostname id install join kill |
| link ln logname ls md5sum mkdir mkfifo mknod mktemp mv nice nl nohup |
| nproc od paste pathchk pinky pr printenv printf ptx pwd readlink rm rmdir |
| - runcon seq sha1sum sha224sum sha256sum sha384sum sha512sum shred shuf |
| - sleep sort split stat stdbuf stty su sum sync tac tail tee test timeout |
| - touch tr true truncate tsort tty uname unexpand uniq unlink uptime users |
| - vdir wc who whoami yes |
| + runcon runuser seq sha1sum sha224sum sha256sum sha384sum sha512sum shred |
| + shuf sleep sort split stat stdbuf stty su sum sync tac tail tee test |
| + timeout touch tr true truncate tsort tty uname unexpand uniq unlink uptime |
| + users vdir wc who whoami yes |
| |
| See the file NEWS for a list of major changes in the current release. |
| |
| diff -urNp coreutils-8.1-orig/src/Makefile.am coreutils-8.1/src/Makefile.am |
| |
| |
| @@ -100,6 +100,7 @@ EXTRA_PROGRAMS = \ |
| rm \ |
| rmdir \ |
| runcon \ |
| + runuser \ |
| seq \ |
| sha1sum \ |
| sha224sum \ |
| @@ -296,6 +297,10 @@ cp_LDADD += $(copy_LDADD) |
| ginstall_LDADD += $(copy_LDADD) |
| mv_LDADD += $(copy_LDADD) |
| |
| +runuser_SOURCES = su.c |
| +runuser_CFLAGS = -DRUNUSER -DAUTHORS="\"David MacKenzie, Dan Walsh\"" |
| +runuser_LDADD = $(LDADD) $(LIB_CRYPT) @LIB_PAM@ |
| + |
| remove_LDADD = |
| mv_LDADD += $(remove_LDADD) |
| rm_LDADD += $(remove_LDADD) |
| @@ -396,7 +401,7 @@ RELEASE_YEAR = \ |
| `sed -n '/.*COPYRIGHT_YEAR = \([0-9][0-9][0-9][0-9]\) };/s//\1/p' \ |
| $(top_srcdir)/lib/version-etc.c` |
| |
| -all-local: su$(EXEEXT) |
| +all-local: su$(EXEEXT) runuser |
| |
| installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'` |
| |
| diff -urNp coreutils-8.1-orig/src/su.c coreutils-8.1/src/su.c |
| |
| |
| @@ -102,9 +102,15 @@ |
| #include "error.h" |
| |
| /* The official name of this program (e.g., no `g' prefix). */ |
| +#ifndef RUNUSER |
| #define PROGRAM_NAME "su" |
| +#else |
| +#define PROGRAM_NAME "runuser" |
| +#endif |
| |
| +#ifndef AUTHORS |
| #define AUTHORS proper_name ("David MacKenzie") |
| +#endif |
| |
| #if HAVE_PATHS_H |
| # include <paths.h> |
| @@ -142,9 +148,16 @@ |
| #ifndef USE_PAM |
| char *crypt (char const *key, char const *salt); |
| #endif |
| +#ifndef CHECKPASSWD |
| +#define CHECKPASSWD 1 |
| +#endif |
| |
| static void run_shell (char const *, char const *, char **, size_t, |
| - const struct passwd *) |
| + const struct passwd * |
| +#ifdef RUNUSER |
| + , gid_t *groups, int num_groups |
| +#endif |
| + ) |
| #ifdef USE_PAM |
| ; |
| #else |
| @@ -171,6 +184,10 @@ static struct option const longopts[] = |
| {"login", no_argument, NULL, 'l'}, |
| {"preserve-environment", no_argument, NULL, 'p'}, |
| {"shell", required_argument, NULL, 's'}, |
| +#ifdef RUNUSER |
| + {"group", required_argument, NULL, 'g'}, |
| + {"supp-group", required_argument, NULL, 'G'}, |
| +#endif |
| {GETOPT_HELP_OPTION_DECL}, |
| {GETOPT_VERSION_OPTION_DECL}, |
| {NULL, 0, NULL, 0} |
| @@ -272,10 +289,12 @@ correct_password (const struct passwd *p |
| retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh); |
| PAM_BAIL_P; |
| |
| +#ifndef RUNUSER |
| if (getuid() != 0 && !isatty(0)) { |
| fprintf(stderr, "standard in must be a tty\n"); |
| exit(1); |
| } |
| +#endif |
| |
| caller = getpwuid(getuid()); |
| if(caller != NULL && caller->pw_name != NULL) { |
| @@ -292,6 +311,11 @@ correct_password (const struct passwd *p |
| retval = pam_set_item(pamh, PAM_TTY, tty_name); |
| PAM_BAIL_P; |
| } |
| +#ifdef RUNUSER |
| + if (getuid() != geteuid()) |
| + /* safety net: deny operation if we are suid by accident */ |
| + error(EXIT_FAILURE, 1, "runuser may not be setuid"); |
| +#else |
| retval = pam_authenticate(pamh, 0); |
| PAM_BAIL_P; |
| retval = pam_acct_mgmt(pamh, 0); |
| @@ -301,6 +325,7 @@ correct_password (const struct passwd *p |
| PAM_BAIL_P; |
| } |
| PAM_BAIL_P; |
| +#endif |
| /* must be authenticated if this point was reached */ |
| return 1; |
| #else /* !USE_PAM */ |
| @@ -382,11 +407,22 @@ modify_environment (const struct passwd |
| /* Become the user and group(s) specified by PW. */ |
| |
| static void |
| -change_identity (const struct passwd *pw) |
| +change_identity (const struct passwd *pw |
| +#ifdef RUNUSER |
| + , gid_t *groups, int num_groups |
| +#endif |
| + ) |
| { |
| #ifdef HAVE_INITGROUPS |
| + int rc = 0; |
| errno = 0; |
| - if (initgroups (pw->pw_name, pw->pw_gid) == -1) { |
| +#ifdef RUNUSER |
| + if (num_groups) |
| + rc = setgroups(num_groups, groups); |
| + else |
| +#endif |
| + rc = initgroups(pw->pw_name, pw->pw_gid); |
| + if (rc == -1) { |
| #ifdef USE_PAM |
| pam_close_session(pamh, 0); |
| pam_end(pamh, PAM_ABORT); |
| @@ -433,7 +469,11 @@ pam_copyenv (pam_handle_t *pamh) |
| |
| static void |
| run_shell (char const *shell, char const *command, char **additional_args, |
| - size_t n_additional_args, const struct passwd *pw) |
| + size_t n_additional_args, const struct passwd *pw |
| +#ifdef RUNUSER |
| + , gid_t *groups, int num_groups |
| +#endif |
| + ) |
| { |
| size_t n_args = 1 + fast_startup + 2 * !!command + n_additional_args + 1; |
| char const **args = xnmalloc (n_args, sizeof *args); |
| @@ -464,7 +504,11 @@ run_shell (char const *shell, char const |
| |
| child = fork(); |
| if (child == 0) { /* child shell */ |
| - change_identity (pw); |
| + change_identity (pw |
| +#ifdef RUNUSER |
| + , groups, num_groups |
| +#endif |
| + ); |
| pam_end(pamh, 0); |
| if (!same_session) |
| setsid (); |
| @@ -608,6 +652,28 @@ usage (int status) |
| else |
| { |
| printf (_("Usage: %s [OPTION]... [-] [USER [ARG]...]\n"), program_name); |
| +#ifdef RUNUSER |
| + printf (_("\ |
| +Change the effective user id and group id to that of USER. Only session PAM\n\ |
| +hooks are run, and there is no password prompt. This command is useful only\n\ |
| +when run as the root user. If run as a non-root user without privilege\n\ |
| +to set user ID, the command will fail as the binary is not setuid.\n\ |
| +As %s doesn't run auth and account PAM hooks, it runs with lower overhead\n\ |
| +than su.\n\ |
| +\n\ |
| + -, -l, --login make the shell a login shell, uses runuser-l\n\ |
| + PAM file instead of default one\n\ |
| + -g --group=group specify the primary group\n\ |
| + -G --supp-group=group specify a supplemental group\n\ |
| + -c, --command=COMMAND pass a single COMMAND to the shell with -c\n\ |
| + --session-command=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\ |
| + -m, --preserve-environment do not reset environment variables\n\ |
| + -p same as -m\n\ |
| + -s, --shell=SHELL run SHELL if /etc/shells allows it\n\ |
| +"), program_name); |
| +#else |
| fputs (_("\ |
| Change the effective user id and group id to that of USER.\n\ |
| \n\ |
| @@ -620,6 +686,7 @@ Change the effective user id and group i |
| -p same as -m\n\ |
| -s, --shell=SHELL run SHELL if /etc/shells allows it\n\ |
| "), stdout); |
| +#endif |
| fputs (HELP_OPTION_DESCRIPTION, stdout); |
| fputs (VERSION_OPTION_DESCRIPTION, stdout); |
| fputs (_("\ |
| @@ -641,6 +708,12 @@ main (int argc, char **argv) |
| char *shell = NULL; |
| struct passwd *pw; |
| struct passwd pw_copy; |
| +#ifdef RUNUSER |
| + struct group *gr; |
| + gid_t groups[NGROUPS_MAX]; |
| + int num_supp_groups = 0; |
| + int use_gid = 0; |
| +#endif |
| |
| initialize_main (&argc, &argv); |
| set_program_name (argv[0]); |
| @@ -655,7 +728,11 @@ main (int argc, char **argv) |
| simulate_login = false; |
| change_environment = true; |
| |
| - while ((optc = getopt_long (argc, argv, "c:flmps:", longopts, NULL)) != -1) |
| + while ((optc = getopt_long (argc, argv, "c:flmps:" |
| +#ifdef RUNUSER |
| + "g:G:" |
| +#endif |
| + , longopts, NULL)) != -1) |
| { |
| switch (optc) |
| { |
| @@ -685,6 +762,28 @@ main (int argc, char **argv) |
| shell = optarg; |
| break; |
| |
| +#ifdef RUNUSER |
| + case 'g': |
| + gr = getgrnam(optarg); |
| + if (!gr) |
| + error (EXIT_FAILURE, 0, _("group %s does not exist"), optarg); |
| + use_gid = 1; |
| + groups[0] = gr->gr_gid; |
| + break; |
| + |
| + case 'G': |
| + num_supp_groups++; |
| + if (num_supp_groups >= NGROUPS_MAX) |
| + error (EXIT_FAILURE, 0, |
| + _("Can't specify more than %d supplemental groups"), |
| + NGROUPS_MAX - 1); |
| + gr = getgrnam(optarg); |
| + if (!gr) |
| + error (EXIT_FAILURE, 0, _("group %s does not exist"), optarg); |
| + groups[num_supp_groups] = gr->gr_gid; |
| + break; |
| +#endif |
| + |
| case_GETOPT_HELP_CHAR; |
| |
| case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); |
| @@ -723,7 +822,20 @@ main (int argc, char **argv) |
| : DEFAULT_SHELL); |
| endpwent (); |
| |
| - if (!correct_password (pw)) |
| +#ifdef RUNUSER |
| + if (num_supp_groups && !use_gid) |
| + { |
| + pw->pw_gid = groups[1]; |
| + memmove (groups, groups + 1, sizeof(gid_t) * num_supp_groups); |
| + } |
| + else if (use_gid) |
| + { |
| + pw->pw_gid = groups[0]; |
| + num_supp_groups++; |
| + } |
| +#endif |
| + |
| + if (CHECKPASSWD && !correct_password (pw)) |
| { |
| #ifdef SYSLOG_FAILURE |
| log_su (pw, false); |
| @@ -755,7 +867,11 @@ main (int argc, char **argv) |
| modify_environment (pw, shell); |
| |
| #ifndef USE_PAM |
| - change_identity (pw); |
| + change_identity (pw |
| +#ifdef RUNUSER |
| + , groups, num_supp_groups |
| +#endif |
| + ); |
| #endif |
| |
| /* error() flushes stderr, but does not check for write failure. |
| @@ -766,5 +882,9 @@ main (int argc, char **argv) |
| if (ferror (stderr)) |
| exit (EXIT_CANCELED); |
| |
| - run_shell (shell, command, argv + optind, MAX (0, argc - optind), pw); |
| + run_shell (shell, command, argv + optind, MAX (0, argc - optind), pw |
| +#ifdef RUNUSER |
| + , groups, num_supp_groups |
| +#endif |
| + ); |
| } |
| diff -urNp coreutils-8.1-orig/tests/misc/help-version coreutils-8.1/tests/misc/help-version |
| |
| |
| @@ -34,6 +34,7 @@ expected_failure_status_nohup=125 |
| expected_failure_status_stdbuf=125 |
| expected_failure_status_su=125 |
| expected_failure_status_timeout=125 |
| +expected_failure_status_runuser=125 |
| expected_failure_status_printenv=2 |
| expected_failure_status_tty=3 |
| expected_failure_status_sort=2 |
| @@ -153,6 +154,7 @@ seq_args=10 |
| sleep_args=0 |
| su_args=--version |
| stdbuf_args="-oL true" |
| +runuser_args=--version |
| timeout_args=--version |
| |
| # I'd rather not run sync, since it spins up disks that I've |
| diff -urNp coreutils-8.1-orig/tests/misc/invalid-opt coreutils-8.1/tests/misc/invalid-opt |
| |
| |
| @@ -37,6 +37,7 @@ my %exit_status = |
| sort => 2, |
| stdbuf => 125, |
| su => 125, |
| + runuser => 125, |
| test => 0, |
| timeout => 125, |
| true => 0, |