]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
runuser: new command (derived from su(1))
authorKarel Zak <kzak@redhat.com>
Wed, 29 Aug 2012 15:34:26 +0000 (17:34 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 4 Sep 2012 15:00:31 +0000 (17:00 +0200)
 This command is based on su(1), the differences:

 - based on Fedora runuser su(1) patch
 - not installed with suid rights
 - allowed for root users only
 - don't ask for password
 - uses PAM session, for example:

$ cat /etc/pam.d/runuser
auth sufficient pam_rootok.so
session optional pam_keyinit.so revoke
session required pam_limits.so
session required pam_unix.so

$ cat /etc/pam.d/runuser-l
auth include runuser
session optional pam_keyinit.so force revoke
session include runuser

Signed-off-by: Karel Zak <kzak@redhat.com>
.gitignore
configure.ac
login-utils/Makemodule.am
login-utils/runuser.1 [new file with mode: 0644]
login-utils/runuser.c [new file with mode: 0644]
login-utils/su-common.c

index fbc563632181fe160fcc724111f9d6ea1b19236b..5be008f580a35e47974ff5def974570a772c569f 100644 (file)
@@ -138,6 +138,7 @@ tests/run.sh.trs
 /resizepart
 /rev
 /rtcwake
+/runuser
 /sample-mkfs
 /sample-partitions
 /sample-superblocks
index 54096dd955ca3abf4f79e10949a2af6f2ddf8168..ead559c30c531ab502d5846cc742897c8a00d9c3 100644 (file)
@@ -1154,6 +1154,15 @@ UL_REQUIRES_HAVE([su], [security_pam_misc_h], [PAM header file])
 AM_CONDITIONAL(BUILD_SU, test "x$build_su" = xyes)
 
 
+AC_ARG_ENABLE([runuser],
+  AS_HELP_STRING([--disable-runuser], [do not build runuser]),
+  [], enable_runuser=yes
+)
+UL_BUILD_INIT([runuser])
+UL_REQUIRES_HAVE([runuser], [security_pam_misc_h], [PAM header file])
+AM_CONDITIONAL(BUILD_RUNUSER, test "x$build_runuser" = xyes)
+
+
 AC_ARG_ENABLE([schedutils],
   AS_HELP_STRING([--disable-schedutils], [do not build chrt, ionice, teskset]),
   [], enable_schedutils=yes
index 7310145e9693bd2f9329830a5f9f8518fca136e4..755a361dd8d859cc85850912630bd85c4bd64c81 100644 (file)
@@ -92,6 +92,19 @@ su_LDADD = $(LDADD) -lpam -lpam_misc
 endif
 
 
+if BUILD_RUNUSER
+bin_PROGRAMS += runuser
+dist_man_MANS += login-utils/runuser.1
+runuser_SOURCES = \
+       login-utils/runuser.c \
+       login-utils/su-common.c \
+       login-utils/su-common.h \
+       login-utils/logindefs.c \
+       login-utils/logindefs.h
+runuser_LDADD = $(LDADD) -lpam -lpam_misc
+endif
+
+
 if BUILD_NEWGRP
 usrbin_exec_PROGRAMS += newgrp
 dist_man_MANS += login-utils/newgrp.1
diff --git a/login-utils/runuser.1 b/login-utils/runuser.1
new file mode 100644 (file)
index 0000000..66ad1c4
--- /dev/null
@@ -0,0 +1,230 @@
+.TH RUNUSER "1" "August 2012" "util-linux" "User Commands"
+.SH NAME
+runuser \- run a command with substitute user and group ID
+.SH SYNOPSIS
+.B runuser
+[options...] [\-] [user [args...]]
+.SH DESCRIPTION
+.B runuser
+allows to run commands with substitute user and group ID.
+The difference between the commands
+.B runuser
+and
+.B su
+is that
+.B runuser
+does not ask for password, because it may be executed by root user only.
+The command
+.B runuser
+does not have to be installed with suid permissions.
+.PP
+When called without arguments
+.B runuser
+defaults to running an interactive shell as
+.IR root .
+.PP
+For backward compatibility
+.B runuser
+defaults to not change the current directory and to only set the
+environment variables
+.B HOME
+and
+.B SHELL
+(plus
+.B USER
+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
+This version of
+.B runuser
+uses PAM for session management.
+.SH OPTIONS
+.TP
+\fB\-c\fR \fIcommand\fR, \fB\-\-command\fR=\fIcommand\fR
+Pass
+.I command
+to the shell with the
+.B \-c
+option.
+.TP
+\fB\-\-session\-command\fR=\fIcommand\fR
+Same as
+.B \-c
+but do not create a new session (discouraged).
+.TP
+\fB\-f\fR, \fB\-\-fast\fR
+Pass
+.B \-f
+to the shell which may or may not be useful depending on the
+shell.
+.TP
+\fB\-g\fR, \fB\-\-group\fR=\fIgroup\fR\fR
+specify the primary group, this option is allowed for root user only
+.TP
+\fB\-G\fR, \fB\-\-supp-group\fR=\fIgroup\fR\fR
+specify a supplemental group, this option is allowed for root user only
+.TP
+\fB\-\fR, \fB\-l\fR, \fB\-\-login\fR
+Starts the shell as login shell with an environment similar to a real
+login:
+.RS 10
+.TP
+o
+clears all environment variables except for
+.B TERM
+.TP
+o
+initializes the environment variables
+.BR HOME ,
+.BR SHELL ,
+.BR USER ,
+.BR LOGNAME ,
+.B PATH
+.TP
+o
+changes to the target user's home directory
+.TP
+o
+sets argv[0] of the shell to
+.RB ' \- '
+in order to make the shell a login shell
+.RE
+.TP
+\fB\-m\fR, \fB\-p\fR, \fB\-\-preserve-environment\fR
+Preserves the whole environment, ie does not set
+.BR HOME ,
+.BR SHELL ,
+.B USER
+nor
+.BR LOGNAME .
+.TP
+\fB\-s\fR \fISHELL\fR, \fB\-\-shell\fR=\fISHELL\fR
+Runs the specified shell instead of the default.  The shell to run is
+selected according to the following rules in order:
+.RS 10
+.TP
+o
+the shell specified with
+.B \-\-shell
+.TP
+o
+The shell specified in the environment variable
+.B SHELL
+if the
+.B \-\-preserve-environment
+option is used.
+.TP
+o
+the shell listed in the passwd entry of the target user
+.TP
+o
+/bin/sh
+.RE
+.IP
+If the target user has a restricted shell (i.e. not listed in
+/etc/shells) the
+.B \-\-shell
+option and the
+.B SHELL
+environment variables are ignored unless the calling user is root.
+.TP
+\fB\-\-help\fR
+Display help text and exit.
+.TP
+\fB\-\-version\fR
+Display version information and exit.
+.SH CONFIG FILES
+.B runuser
+reads the
+.I /etc/default/runuser
+and
+.I /etc/login.defs
+configuration files.  The following configuration items are relevant
+for
+.BR runuser :
+.PP
+.B ENV_PATH
+(string)
+.RS 4
+Defines the PATH environment variable for a regular user.  The
+default value is
+.IR /usr/local/bin:\:/bin:\:/usr/bin .
+.RE
+.PP
+.B ENV_ROOTPATH
+(string)
+.br
+.B ENV_SUPATH
+(string)
+.RS 4
+Defines the PATH environment variable for root. The default value is
+.IR /usr/local/sbin:\:/usr/local/bin:\:/sbin:\:/bin:\:/usr/sbin:\:/usr/bin .
+.RE
+.PP
+.B ALWAYS_SET_PATH
+(boolean)
+.RS 4
+If set to
+.I yes
+and \-\-login and \-\-preserve\-environment were not specified
+.B runuser
+initializes
+.BR PATH .
+.RE
+.SH EXIT STATUS
+.B runuser
+normally returns the exit status of the command it executed.  If the
+command was killed by a signal,
+.B runuser
+returns the number of the signal plus 128.
+.PP
+Exit status generated by
+.B runuser
+itself:
+.RS 10
+.TP
+1
+Generic error before executing the requested command
+.TP
+126
+The requested command could not be executed
+.TP
+127
+The requested command could was not found
+.RE
+.SH FILES
+.PD 0
+.TP 17
+/etc/pam.d/runuser
+default PAM configuration file
+.TP
+/etc/pam.d/runuser-l
+PAM configuration file if \-\-login is specified
+.TP
+/etc/default/runuser
+runuser specific logindef config file
+.TP
+/etc/login.defs
+global logindef config file
+.PD 1
+.SH "SEE ALSO"
+.BR pam (8),
+.BR shells (5),
+.BR login.defs (5),
+.BR su (1)
+.SH AUTHOR
+Derived from coreutils' su which was based on an implemenation from
+David MacKenzie and Fedora runuser command from Dan Walsh.
+.SH AVAILABILITY
+The runuser command is part of the util-linux package and is
+available from
+.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
+Linux Kernel Archive
+.UE .
diff --git a/login-utils/runuser.c b/login-utils/runuser.c
new file mode 100644 (file)
index 0000000..d761a14
--- /dev/null
@@ -0,0 +1,7 @@
+
+#include "su-common.h"
+
+int main(int argv, char **argc)
+{
+       return su_main(argv, argc, RUNUSER_MODE);
+}
index 4fc425055a30b21f78f1dbe01dd648c86fe3dd88..d1fecd70162abc2cce3274bd0e956104efbf8772 100644 (file)
@@ -65,8 +65,14 @@ enum
 #include "env.h"
 
 /* name of the pam configuration files. separate configs for su and su -  */
-#define PAM_SERVICE_NAME "su"
-#define PAM_SERVICE_NAME_L "su-l"
+#define PAM_SRVNAME_SU "su"
+#define PAM_SRVNAME_SU_L "su-l"
+
+#define PAM_SRVNAME_RUNUSER "runuser"
+#define PAM_SRVNAME_RUNUSER_L "runuser-l"
+
+#define _PATH_LOGINDEFS_SU     "/etc/defaults/su"
+#define _PATH_LOGINDEFS_RUNUSER "/etc/defaults/runuser"
 
 #define is_pam_failure(_rc)    ((_rc) != PAM_SUCCESS)
 
@@ -106,6 +112,8 @@ static bool _pam_cred_established;
 static sig_atomic_t volatile caught_signal = false;
 static pam_handle_t *pamh = NULL;
 
+static int restricted = 1;     /* zero for root user */
+
 static struct option const longopts[] =
 {
   {"command", required_argument, NULL, 'c'},
@@ -146,7 +154,8 @@ log_su (struct passwd const *pw, bool successful)
 
   openlog (program_invocation_short_name, 0 , LOG_AUTH);
   syslog (LOG_NOTICE, "%s(to %s) %s on %s",
-         successful ? "" : "FAILED SU ",
+         successful ? "" :
+         su_mode == RUNUSER_MODE ? "FAILED RUNUSER " : "FAILED SU ",
          new_user, old_user, tty);
   closelog ();
 }
@@ -315,11 +324,19 @@ static void
 authenticate (const struct passwd *pw)
 {
   const struct passwd *lpw;
-  const char *cp;
+  const char *cp, *srvname = NULL;
   int retval;
 
-  retval = pam_start (simulate_login ? PAM_SERVICE_NAME_L : PAM_SERVICE_NAME,
-                     pw->pw_name, &conv, &pamh);
+  switch (su_mode) {
+  case SU_MODE:
+    srvname = simulate_login ? PAM_SRVNAME_SU_L : PAM_SRVNAME_SU;
+    break;
+  case RUNUSER_MODE:
+    srvname = simulate_login ? PAM_SRVNAME_RUNUSER_L : PAM_SRVNAME_RUNUSER;
+    break;
+  }
+
+  retval = pam_start (srvname, pw->pw_name, &conv, &pamh);
   if (is_pam_failure(retval))
     goto done;
 
@@ -344,6 +361,17 @@ authenticate (const struct passwd *pw)
        goto done;
     }
 
+  if (su_mode == RUNUSER_MODE)
+    {
+      /*
+       * This is the only difference between runuser(1) and su(1). The command
+       * runuser(1) does not required authentication, because user is root.
+       */
+      if (restricted)
+       errx(EXIT_FAILURE, _("may not be used by non-root users"));
+      return;
+    }
+
   retval = pam_authenticate (pamh, 0);
   if (is_pam_failure(retval))
     goto done;
@@ -691,7 +719,15 @@ usage (int status)
 static
 void load_config(void)
 {
-  logindefs_load_file("/etc/default/su");
+  switch (su_mode) {
+  case SU_MODE:
+    logindefs_load_file(_PATH_LOGINDEFS_SU);
+    break;
+  case RUNUSER_MODE:
+    logindefs_load_file(_PATH_LOGINDEFS_RUNUSER);
+    break;
+  }
+
   logindefs_load_file(_PATH_LOGINDEFS);
 }
 
@@ -722,7 +758,6 @@ su_main (int argc, char **argv, int mode)
   gid_t groups[NGROUPS_MAX];
   int num_supp_groups = 0;
   int use_gid = 0;
-  int restricted;
 
   setlocale (LC_ALL, "");
   bindtextdomain (PACKAGE, LOCALEDIR);