Blob Blame History Raw
diff -urNp coreutils-8.7-orig/AUTHORS coreutils-8.7/AUTHORS
--- coreutils-8.7-orig/AUTHORS	2010-10-11 19:35:11.000000000 +0200
+++ coreutils-8.7/AUTHORS	2010-11-15 10:08:04.222078001 +0100
@@ -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.7-orig/man/help2man coreutils-8.7/man/help2man
--- coreutils-8.7-orig/man/help2man	2010-10-11 19:35:11.000000000 +0200
+++ coreutils-8.7/man/help2man	2010-11-15 10:08:51.331054884 +0100
@@ -555,6 +555,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.7-orig/man/Makefile.am coreutils-8.7/man/Makefile.am
--- coreutils-8.7-orig/man/Makefile.am	2010-10-11 19:35:11.000000000 +0200
+++ coreutils-8.7/man/Makefile.am	2010-11-15 10:09:21.768922182 +0100
@@ -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.7-orig/man/runuser.x coreutils-8.7/man/runuser.x
--- coreutils-8.7-orig/man/runuser.x	1970-01-01 01:00:00.000000000 +0100
+++ coreutils-8.7/man/runuser.x	2010-11-15 10:09:57.437939015 +0100
@@ -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.7-orig/README coreutils-8.7/README
--- coreutils-8.7-orig/README	2010-10-11 19:35:11.000000000 +0200
+++ coreutils-8.7/README	2010-11-15 10:10:43.002922253 +0100
@@ -11,8 +11,8 @@ 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 realpath
-  rm rmdir runcon seq sha1sum sha224sum sha256sum sha384sum sha512sum shred
-  shuf sleep sort split stat stdbuf stty su sum sync tac tail tee test
+  rm rmdir 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
 
diff -urNp coreutils-8.7-orig/src/Makefile.am coreutils-8.7/src/Makefile.am
--- coreutils-8.7-orig/src/Makefile.am	2010-11-15 10:07:07.339171659 +0100
+++ coreutils-8.7/src/Makefile.am	2010-11-15 10:12:14.847094550 +0100
@@ -100,6 +100,7 @@ EXTRA_PROGRAMS = \
   rm		\
   rmdir		\
   runcon	\
+  runuser	\
   seq		\
   sha1sum	\
   sha224sum	\
@@ -300,6 +301,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) $(PAM_LIBS)
+
 remove_LDADD =
 mv_LDADD += $(remove_LDADD)
 rm_LDADD += $(remove_LDADD)
@@ -395,7 +400,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.7-orig/src/su.c coreutils-8.7/src/su.c
--- coreutils-8.7-orig/src/su.c	2010-11-15 10:07:07.372933288 +0100
+++ coreutils-8.7/src/su.c	2010-11-15 10:42:12.569159230 +0100
@@ -100,9 +100,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>
@@ -140,6 +146,9 @@
 #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)
      ATTRIBUTE_NORETURN;
@@ -169,6 +178,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}
@@ -444,6 +457,11 @@ correct_password (const struct passwd *p
       retval = pam_set_item (pamh, PAM_RUSER, (const void *) lpw->pw_name);
       PAM_BAIL_P (return false);
     }
+#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 (return false);
   retval = pam_acct_mgmt (pamh, 0);
@@ -454,6 +472,7 @@ correct_password (const struct passwd *p
       PAM_BAIL_P (return false);
     }
   PAM_BAIL_P (return false);
+#endif
   /* Must be authenticated if this point was reached.  */
   return true;
 #else /* !USE_PAM */
@@ -533,11 +552,22 @@ modify_environment (const struct passwd 
 /* Become the user and group(s) specified by PW.  */
 
 static void
-init_groups (const struct passwd *pw)
+init_groups (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
       cleanup_pam (PAM_ABORT);
@@ -639,6 +669,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\
@@ -651,6 +703,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 (_("\
@@ -672,6 +725,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]);
@@ -686,7 +745,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)
         {
@@ -716,6 +779,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);
@@ -754,7 +839,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);
@@ -784,7 +882,11 @@ main (int argc, char **argv)
     }
   shell = xstrdup (shell ? shell : pw->pw_shell);
 
-  init_groups (pw);
+  init_groups (pw
+#ifdef RUNUSER
+                   , groups, num_supp_groups
+#endif
+          );
 
 #ifdef USE_PAM
   create_watching_parent ();
diff -urNp coreutils-8.7-orig/tests/misc/help-version coreutils-8.7/tests/misc/help-version
--- coreutils-8.7-orig/tests/misc/help-version	2010-10-11 19:35:11.000000000 +0200
+++ coreutils-8.7/tests/misc/help-version	2010-11-15 10:45:18.473682325 +0100
@@ -32,6 +32,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
@@ -209,6 +210,7 @@ seq_setup () { args=10; }
 sleep_setup () { args=0; }
 su_setup () { args=--version; }
 stdbuf_setup () { args="-oL true"; }
+runuser_setup () { args=--version; }
 timeout_setup () { args=--version; }
 
 # I'd rather not run sync, since it spins up disks that I've
diff -urNp coreutils-8.7-orig/tests/misc/invalid-opt coreutils-8.7/tests/misc/invalid-opt
--- coreutils-8.7-orig/tests/misc/invalid-opt	2010-10-11 19:35:11.000000000 +0200
+++ coreutils-8.7/tests/misc/invalid-opt	2010-11-15 10:45:46.451938873 +0100
@@ -37,6 +37,7 @@ my %exit_status =
     sort => 2,
     stdbuf => 125,
     su => 125,
+    runuser => 125,
     test => 0,
     timeout => 125,
     true => 0,