From 928dd73762e69cfeaab4a7ec9dd8f30f86a45ed4 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Fri, 25 May 2012 18:10:25 +0200 Subject: su: remove program (util-linux is now the best source for it) * README: Omit "su" from list of programs. * src/su.c: Remove file. * src/Makefile.am: Remove su-related rules and variables. * tests/misc/su-fail: Remove test. * tests/Makefile.am (TESTS): Remove misc/su-fail. * tests/misc/invalid-opt: Remove su-related code. * src/.gitignore: Remove su. * man/su.x: Remove file. * man/Makefile.am (su.1): Remove rule. * po/POTFILES.in: Remove su.c from the list. * TODO: Remove ancient entry. * NEWS (Changes in behavior): Mention it. * doc/coreutils.texi: Remove su-related description. * AUTHORS: Remove su. * m4/lib-check.m4 (cu_LIB_CHECK): Remove file/macro. * configure.ac: Remove su-related code and sole use of cu_LIB_CHECK. * scripts/git-hooks/commit-msg: Remove su from this list, too. --- src/.gitignore | 1 - src/Makefile.am | 63 +------ src/su.c | 520 -------------------------------------------------------- 3 files changed, 2 insertions(+), 582 deletions(-) delete mode 100644 src/su.c (limited to 'src') diff --git a/src/.gitignore b/src/.gitignore index 9c4c9b717..d78178ce8 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -87,7 +87,6 @@ split stat stdbuf stty -su sum sync tac diff --git a/src/Makefile.am b/src/Makefile.am index 06ab61527..309950559 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,7 @@ # Hence, if you want to install programs from this list anyway, say A and B, # use --enable-install-program=A,B no_install__progs = \ - arch hostname su + arch hostname build_if_possible__progs = \ chroot \ @@ -32,7 +32,6 @@ build_if_possible__progs = \ pinky \ stdbuf \ stty \ - su \ uptime \ users \ who @@ -164,7 +163,7 @@ noinst_HEADERS = \ EXTRA_DIST = dcgen dircolors.hin tac-pipe.c \ wheel-gen.pl extract-magic c99-to-c89.diff BUILT_SOURCES = -CLEANFILES = $(SCRIPTS) su +CLEANFILES = $(SCRIPTS) # Also remove these sometimes-built programs. # For example, even when excluded, they're built via _sc_check-AUTHORS. @@ -268,7 +267,6 @@ split_LDADD = $(LDADD) stat_LDADD = $(LDADD) stdbuf_LDADD = $(LDADD) stty_LDADD = $(LDADD) -su_LDADD = $(LDADD) sum_LDADD = $(LDADD) sync_LDADD = $(LDADD) tac_LDADD = $(LDADD) @@ -357,9 +355,6 @@ factor_LDADD += $(LIB_GMP) # for getloadavg uptime_LDADD += $(GETLOADAVG_LIBS) -# for crypt -su_LDADD += $(LIB_CRYPT) - # for various ACL functions copy_LDADD += $(LIB_ACL) ls_LDADD += $(LIB_ACL) @@ -402,60 +397,6 @@ 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) - -installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'` - -setuid_root_mode = a=rx,u+s - -install_su = \ - if test "$(INSTALL_SU)" = yes; then \ - p=su; \ - echo " $(INSTALL_PROGRAM) $$p $(installed_su)"; \ - $(INSTALL_PROGRAM) $$p $(installed_su); \ - echo " chown root $(installed_su)"; \ - chown root $(installed_su); \ - echo " chmod $(setuid_root_mode) $(installed_su)"; \ - chmod $(setuid_root_mode) $(installed_su); \ - else \ - :; \ - fi - -install-root: su$(EXEEXT) - @$(install_su) - -install-exec-hook: su$(EXEEXT) - @if test "$(INSTALL_SU)" = yes; then \ - TMPFILE=$(DESTDIR)$(bindir)/.su-$$$$; \ - rm -f $$TMPFILE; \ - echo > $$TMPFILE; \ -## See if we can create a setuid root executable in $(bindir). -## If not, then don't even try to install su. - can_create_suid_root_executable=no; \ - chown root $$TMPFILE > /dev/null 2>&1 \ - && chmod $(setuid_root_mode) $$TMPFILE > /dev/null 2>&1 \ - && can_create_suid_root_executable=yes; \ - rm -f $$TMPFILE; \ - if test $$can_create_suid_root_executable = yes; then \ - $(install_su); \ - else \ - echo "WARNING: insufficient access; not installing su"; \ - echo "NOTE: to install su, run 'make install-root' as root"; \ - rm -f $(installed_su); \ - fi; \ - else :; \ - fi - -uninstall-local: -# Remove su only if it's one we installed. - @if test "$(INSTALL_SU)" = yes; then \ - if grep '$(PACKAGE_NAME)' $(installed_su) > /dev/null 2>&1; then \ - echo " rm -f $(installed_su)"; \ - rm -f $(installed_su); \ - else :; \ - fi; \ - fi - copy_sources = copy.c cp-hash.c extent-scan.c extent-scan.h # Use 'ginstall' in the definition of PROGRAMS and in dependencies to avoid diff --git a/src/su.c b/src/su.c deleted file mode 100644 index bb54cc33a..000000000 --- a/src/su.c +++ /dev/null @@ -1,520 +0,0 @@ -/* su for GNU. Run a shell with substitute user and group IDs. - Copyright (C) 1992-2012 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* Run a shell with the real and effective UID and GID and groups - of USER, default 'root'. - - The shell run is taken from USER's password entry, /bin/sh if - none is specified there. If the account has a password, su - prompts for a password unless run by a user with real UID 0. - - Does not change the current directory. - Sets 'HOME' and 'SHELL' from the password entry for USER, and if - USER is not root, sets 'USER' and 'LOGNAME' to USER. - The subshell is not a login shell. - - If one or more ARGs are given, they are passed as additional - arguments to the subshell. - - Does not handle /bin/sh or other shells specially - (setting argv[0] to "-su", passing -c only to certain shells, etc.). - I don't see the point in doing that, and it's ugly. - - This program intentionally does not support a "wheel group" that - restricts who can su to UID 0 accounts. RMS considers that to - be fascist. - - Compile-time options: - -DSYSLOG_SUCCESS Log successful su's (by default, to root) with syslog. - -DSYSLOG_FAILURE Log failed su's (by default, to root) with syslog. - - -DSYSLOG_NON_ROOT Log all su's, not just those to root (UID 0). - Never logs attempted su's to nonexistent accounts. - - Written by David MacKenzie . */ - -#include -#include -#include -#include -#include -#include - -#include "system.h" -#include "getpass.h" - -#if HAVE_SYSLOG_H && HAVE_SYSLOG -# include -#else -# undef SYSLOG_SUCCESS -# undef SYSLOG_FAILURE -# undef SYSLOG_NON_ROOT -#endif - -#if HAVE_SYS_PARAM_H -# include -#endif - -#ifndef HAVE_ENDGRENT -# define endgrent() ((void) 0) -#endif - -#ifndef HAVE_ENDPWENT -# define endpwent() ((void) 0) -#endif - -#if HAVE_SHADOW_H -# include -#endif - -#include "error.h" - -/* The official name of this program (e.g., no 'g' prefix). */ -#define PROGRAM_NAME "su" - -#define AUTHORS proper_name ("David MacKenzie") - -#if HAVE_PATHS_H -# include -#endif - -/* The default PATH for simulated logins to non-superuser accounts. */ -#ifdef _PATH_DEFPATH -# define DEFAULT_LOGIN_PATH _PATH_DEFPATH -#else -# define DEFAULT_LOGIN_PATH ":/usr/ucb:/bin:/usr/bin" -#endif - -/* The default PATH for simulated logins to superuser accounts. */ -#ifdef _PATH_DEFPATH_ROOT -# define DEFAULT_ROOT_LOGIN_PATH _PATH_DEFPATH_ROOT -#else -# define DEFAULT_ROOT_LOGIN_PATH "/usr/ucb:/bin:/usr/bin:/etc" -#endif - -/* The shell to run if none is given in the user's passwd entry. */ -#define DEFAULT_SHELL "/bin/sh" - -/* The user to become if none is specified. */ -#define DEFAULT_USER "root" - -char *crypt (char const *key, char const *salt); - -static void run_shell (char const *, char const *, char **, size_t) - ATTRIBUTE_NORETURN; - -/* If true, pass the '-f' option to the subshell. */ -static bool fast_startup; - -/* If true, simulate a login instead of just starting a shell. */ -static bool simulate_login; - -/* If true, change some environment vars to indicate the user su'd to. */ -static bool change_environment; - -static struct option const longopts[] = -{ - {"command", required_argument, NULL, 'c'}, - {"fast", no_argument, NULL, 'f'}, - {"login", no_argument, NULL, 'l'}, - {"preserve-environment", no_argument, NULL, 'p'}, - {"shell", required_argument, NULL, 's'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -/* Add NAME=VAL to the environment, checking for out of memory errors. */ - -static void -xsetenv (char const *name, char const *val) -{ - size_t namelen = strlen (name); - size_t vallen = strlen (val); - char *string = xmalloc (namelen + 1 + vallen + 1); - strcpy (string, name); - string[namelen] = '='; - strcpy (string + namelen + 1, val); - if (putenv (string) != 0) - xalloc_die (); -} - -#if defined SYSLOG_SUCCESS || defined SYSLOG_FAILURE -/* Log the fact that someone has run su to the user given by PW; - if SUCCESSFUL is true, they gave the correct password, etc. */ - -static void -log_su (struct passwd const *pw, bool successful) -{ - const char *new_user, *old_user, *tty; - -# ifndef SYSLOG_NON_ROOT - if (pw->pw_uid) - return; -# endif - new_user = pw->pw_name; - /* The utmp entry (via getlogin) is probably the best way to identify - the user, especially if someone su's from a su-shell. */ - old_user = getlogin (); - if (!old_user) - { - /* getlogin can fail -- usually due to lack of utmp entry. - Resort to getpwuid. */ - errno = 0; - uid_t ruid = getuid (); - uid_t NO_UID = -1; - struct passwd *pwd = (ruid == NO_UID && errno ? NULL : getpwuid (ruid)); - old_user = (pwd ? pwd->pw_name : ""); - } - tty = ttyname (STDERR_FILENO); - if (!tty) - tty = "none"; - /* 4.2BSD openlog doesn't have the third parameter. */ - openlog (last_component (program_name), 0 -# ifdef LOG_AUTH - , LOG_AUTH -# endif - ); - syslog (LOG_NOTICE, -# ifdef SYSLOG_NON_ROOT - "%s(to %s) %s on %s", -# else - "%s%s on %s", -# endif - successful ? "" : "FAILED SU ", -# ifdef SYSLOG_NON_ROOT - new_user, -# endif - old_user, tty); - closelog (); -} -#endif - -/* Ask the user for a password. - Return true if the user gives the correct password for entry PW, - false if not. Return true without asking for a password if run by UID 0 - or if PW has an empty password. */ - -static bool -correct_password (const struct passwd *pw) -{ - char *unencrypted, *encrypted, *correct; -#if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP - /* Shadow passwd stuff for SVR3 and maybe other systems. */ - struct spwd *sp = getspnam (pw->pw_name); - - endspent (); - if (sp) - correct = sp->sp_pwdp; - else -#endif - correct = pw->pw_passwd; - - if (getuid () == 0 || !correct || correct[0] == '\0') - return true; - - unencrypted = getpass (_("Password:")); - if (!unencrypted) - { - error (0, 0, _("getpass: cannot open /dev/tty")); - return false; - } - encrypted = crypt (unencrypted, correct); - memset (unencrypted, 0, strlen (unencrypted)); - return STREQ (encrypted, correct); -} - -/* Update 'environ' for the new shell based on PW, with SHELL being - the value for the SHELL environment variable. */ - -static void -modify_environment (const struct passwd *pw, const char *shell) -{ - if (simulate_login) - { - /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH. - Unset all other environment variables. */ - char const *term = getenv ("TERM"); - if (term) - term = xstrdup (term); - environ = xmalloc ((6 + !!term) * sizeof (char *)); - environ[0] = NULL; - if (term) - xsetenv ("TERM", term); - xsetenv ("HOME", pw->pw_dir); - xsetenv ("SHELL", shell); - xsetenv ("USER", pw->pw_name); - xsetenv ("LOGNAME", pw->pw_name); - xsetenv ("PATH", (pw->pw_uid - ? DEFAULT_LOGIN_PATH - : DEFAULT_ROOT_LOGIN_PATH)); - } - else - { - /* Set HOME, SHELL, and if not becoming a super-user, - USER and LOGNAME. */ - if (change_environment) - { - xsetenv ("HOME", pw->pw_dir); - xsetenv ("SHELL", shell); - if (pw->pw_uid) - { - xsetenv ("USER", pw->pw_name); - xsetenv ("LOGNAME", pw->pw_name); - } - } - } -} - -/* Become the user and group(s) specified by PW. */ - -static void -change_identity (const struct passwd *pw) -{ -#ifdef HAVE_INITGROUPS - errno = 0; - if (initgroups (pw->pw_name, pw->pw_gid) == -1) - error (EXIT_CANCELED, errno, _("cannot set groups")); - endgrent (); -#endif - if (setgid (pw->pw_gid)) - error (EXIT_CANCELED, errno, _("cannot set group id")); - if (setuid (pw->pw_uid)) - error (EXIT_CANCELED, errno, _("cannot set user id")); -} - -/* Run SHELL, or DEFAULT_SHELL if SHELL is empty. - If COMMAND is nonzero, pass it to the shell with the -c option. - Pass ADDITIONAL_ARGS to the shell as more arguments; there - are N_ADDITIONAL_ARGS extra arguments. */ - -static void -run_shell (char const *shell, char const *command, char **additional_args, - size_t n_additional_args) -{ - size_t n_args = 1 + fast_startup + 2 * !!command + n_additional_args + 1; - char const **args = xnmalloc (n_args, sizeof *args); - size_t argno = 1; - - if (simulate_login) - { - char *arg0; - char *shell_basename; - - shell_basename = last_component (shell); - arg0 = xmalloc (strlen (shell_basename) + 2); - arg0[0] = '-'; - strcpy (arg0 + 1, shell_basename); - args[0] = arg0; - } - else - args[0] = last_component (shell); - if (fast_startup) - args[argno++] = "-f"; - if (command) - { - args[argno++] = "-c"; - args[argno++] = command; - } - memcpy (args + argno, additional_args, n_additional_args * sizeof *args); - args[argno + n_additional_args] = NULL; - execv (shell, (char **) args); - - { - int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE); - error (0, errno, "%s", shell); - exit (exit_status); - } -} - -/* Return true if SHELL is a restricted shell (one not returned by - getusershell), else false, meaning it is a standard shell. */ - -static bool -restricted_shell (const char *shell) -{ - char *line; - - setusershell (); - while ((line = getusershell ()) != NULL) - { - if (*line != '#' && STREQ (line, shell)) - { - endusershell (); - return false; - } - } - endusershell (); - return true; -} - -void -usage (int status) -{ - if (status != EXIT_SUCCESS) - emit_try_help (); - else - { - printf (_("Usage: %s [OPTION]... [-] [USER [ARG]...]\n"), program_name); - fputs (_("\ -Change the effective user id and group id to that of USER.\n\ -\n\ - -, -l, --login make the shell a login shell\n\ - -c, --command=COMMAND pass a single COMMAND to the shell with -c\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\ -"), stdout); - fputs (HELP_OPTION_DESCRIPTION, stdout); - fputs (VERSION_OPTION_DESCRIPTION, stdout); - fputs (_("\ -\n\ -A mere - implies -l. If USER not given, assume root.\n\ -"), stdout); - emit_ancillary_info (); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - int optc; - const char *new_user = DEFAULT_USER; - char *command = NULL; - char *shell = NULL; - struct passwd *pw; - struct passwd pw_copy; - - initialize_main (&argc, &argv); - set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - initialize_exit_failure (EXIT_CANCELED); - atexit (close_stdout); - - fast_startup = false; - simulate_login = false; - change_environment = true; - - while ((optc = getopt_long (argc, argv, "c:flmps:", longopts, NULL)) != -1) - { - switch (optc) - { - case 'c': - command = optarg; - break; - - case 'f': - fast_startup = true; - break; - - case 'l': - simulate_login = true; - break; - - case 'm': - case 'p': - change_environment = false; - break; - - case 's': - shell = optarg; - break; - - case_GETOPT_HELP_CHAR; - - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - - default: - usage (EXIT_CANCELED); - } - } - - if (optind < argc && STREQ (argv[optind], "-")) - { - simulate_login = true; - ++optind; - } - if (optind < argc) - new_user = argv[optind++]; - - pw = getpwnam (new_user); - if (! (pw && pw->pw_name && pw->pw_name[0] && pw->pw_dir && pw->pw_dir[0] - && pw->pw_passwd)) - error (EXIT_CANCELED, 0, _("user %s does not exist"), new_user); - - /* Make a copy of the password information and point pw at the local - copy instead. Otherwise, some systems (e.g. GNU/Linux) would clobber - the static data through the getlogin call from log_su. - Also, make sure pw->pw_shell is a nonempty string. - It may be NULL when NEW_USER is a username that is retrieved via NIS (YP), - but that doesn't have a default shell listed. */ - pw_copy = *pw; - pw = &pw_copy; - pw->pw_name = xstrdup (pw->pw_name); - pw->pw_passwd = xstrdup (pw->pw_passwd); - pw->pw_dir = xstrdup (pw->pw_dir); - pw->pw_shell = xstrdup (pw->pw_shell && pw->pw_shell[0] - ? pw->pw_shell - : DEFAULT_SHELL); - endpwent (); - - if (!correct_password (pw)) - { -#ifdef SYSLOG_FAILURE - log_su (pw, false); -#endif - error (EXIT_CANCELED, 0, _("incorrect password")); - } -#ifdef SYSLOG_SUCCESS - else - { - log_su (pw, true); - } -#endif - - 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. */ - error (0, 0, _("using restricted shell %s"), pw->pw_shell); - shell = NULL; - } - shell = xstrdup (shell ? shell : pw->pw_shell); - modify_environment (pw, shell); - - change_identity (pw); - if (simulate_login && chdir (pw->pw_dir) != 0) - error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir); - - /* error() flushes stderr, but does not check for write failure. - Normally, we would catch this via our atexit() hook of - close_stdout, but execv() gets in the way. If stderr - encountered a write failure, there is no need to try calling - error() again. */ - if (ferror (stderr)) - exit (EXIT_CANCELED); - - run_shell (shell, command, argv + optind, MAX (0, argc - optind)); -} -- cgit v1.2.3-70-g09d2