From d8c2f623ab9d9e7da1490244cb8c77c3017545dc Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 29 Aug 2012 17:34:26 +0200 Subject: [PATCH 202/208] runuser: new command (derived from su(1)) 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 --- .gitignore | 1 + configure.ac | 9 ++ login-utils/Makemodule.am | 13 +++ login-utils/runuser.1 | 230 ++++++++++++++++++++++++++++++++++++++++++++++ login-utils/runuser.c | 7 ++ login-utils/su-common.c | 51 ++++++++-- 6 files changed, 303 insertions(+), 8 deletions(-) create mode 100644 login-utils/runuser.1 create mode 100644 login-utils/runuser.c #diff --git a/.gitignore b/.gitignore #index fbc5636..5be008f 100644 #--- a/.gitignore #+++ b/.gitignore #@@ -138,6 +138,7 @@ tests/run.sh.trs # /resizepart # /rev # /rtcwake #+/runuser # /sample-mkfs # /sample-partitions # /sample-superblocks diff --git a/configure.ac b/configure.ac index 87e85fa..83ef6ce 100644 --- a/configure.ac +++ b/configure.ac @@ -1149,6 +1149,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 diff --git a/login-utils/Makemodule.am b/login-utils/Makemodule.am index b918f00..e26d9a7 100644 --- a/login-utils/Makemodule.am +++ b/login-utils/Makemodule.am @@ -93,6 +93,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 index 0000000..66ad1c4 --- /dev/null +++ b/login-utils/runuser.1 @@ -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 index 0000000..d4f37f4 --- /dev/null +++ b/login-utils/runuser.c @@ -0,0 +1,7 @@ + +#include "su-common.h" + +int main(int argc, char **argv) +{ + return su_main(argc, argv, RUNUSER_MODE); +} diff --git a/login-utils/su-common.c b/login-utils/su-common.c index f1f46aa..770f455 100644 --- a/login-utils/su-common.c +++ b/login-utils/su-common.c @@ -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; @@ -567,7 +595,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); } @@ -598,7 +634,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); -- 1.7.11.7