/* su for GNU. Run a shell with substitute user and group IDs.
- Copyright (C) 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1992-2003 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
#define getusershell _getusershell_sys_proto_
#include "system.h"
+#include "dirname.h"
#undef getusershell
# undef SYSLOG_NON_ROOT
#endif
-#ifdef _POSIX_VERSION
-# include <limits.h>
-#else /* not _POSIX_VERSION */
-struct passwd *getpwuid ();
-struct group *getgrgid ();
-uid_t getuid ();
+#if HAVE_SYS_PARAM_H
# include <sys/param.h>
-#endif /* not _POSIX_VERSION */
+#endif
#ifndef HAVE_ENDGRENT
# define endgrent() ((void) 0)
#include "error.h"
+/* The official name of this program (e.g., no `g' prefix). */
+#define PROGRAM_NAME "su"
+
+#define WRITTEN_BY _("Written by David MacKenzie.")
+
#if HAVE_PATHS_H
# include <paths.h>
#endif
void endusershell ();
void setusershell ();
-char *base_name ();
-char *xstrdup ();
-
extern char **environ;
+static void run_shell (const char *, const char *, char **)
+ ATTRIBUTE_NORETURN;
+
/* The name this program was run with. */
char *program_name;
-/* If nonzero, display usage information and exit. */
-static int show_help;
-
-/* If nonzero, print the version on standard output and exit. */
-static int show_version;
-
/* If nonzero, pass the `-f' option to the subshell. */
static int fast_startup;
static struct option const longopts[] =
{
{"command", required_argument, 0, 'c'},
- {"fast", no_argument, &fast_startup, 1},
- {"help", no_argument, &show_help, 1},
- {"login", no_argument, &simulate_login, 1},
+ {"fast", no_argument, NULL, 'f'},
+ {"login", no_argument, NULL, 'l'},
{"preserve-environment", no_argument, &change_environment, 0},
{"shell", required_argument, 0, 's'},
- {"version", no_argument, &show_version, 1},
+ {GETOPT_HELP_OPTION_DECL},
+ {GETOPT_VERSION_OPTION_DECL},
{0, 0, 0, 0}
};
/* Add VAL to the environment, checking for out of memory errors. */
static void
-xputenv (const char *val)
+xputenv (char *val)
{
if (putenv (val))
- error (1, 0, _("virtual memory exhausted"));
+ xalloc_die ();
}
/* Return a newly-allocated string whose contents concatenate
concat (const char *s1, const char *s2, const char *s3)
{
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+ char *result = xmalloc (len1 + len2 + len3 + 1);
strcpy (result, s1);
strcpy (result + len1, s2);
correct_password (const struct passwd *pw)
{
char *unencrypted, *encrypted, *correct;
-#ifdef HAVE_SHADOW_H
+#if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP
/* Shadow passwd stuff for SVR3 and maybe other systems. */
struct spwd *sp = getspnam (pw->pw_name);
/* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
Unset all other environment variables. */
term = getenv ("TERM");
- environ = (char **) xmalloc (2 * sizeof (char *));
+ environ = xmalloc (2 * sizeof (char *));
environ[0] = 0;
if (term)
xputenv (concat ("TERM", "=", term));
#ifdef HAVE_INITGROUPS
errno = 0;
if (initgroups (pw->pw_name, pw->pw_gid) == -1)
- error (1, errno, _("cannot set groups"));
+ error (EXIT_FAILURE, errno, _("cannot set groups"));
endgrent ();
#endif
if (setgid (pw->pw_gid))
- error (1, errno, _("cannot set group id"));
+ error (EXIT_FAILURE, errno, _("cannot set group id"));
if (setuid (pw->pw_uid))
- error (1, errno, _("cannot set user id"));
+ error (EXIT_FAILURE, errno, _("cannot set user id"));
}
/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
int argno = 1;
if (additional_args)
- args = (const char **) xmalloc (sizeof (char *)
+ args = xmalloc (sizeof (char *)
* (10 + elements (additional_args)));
else
- args = (const char **) xmalloc (sizeof (char *) * 10);
+ args = xmalloc (sizeof (char *) * 10);
if (simulate_login)
{
char *arg0;
args[argno++] = *additional_args;
args[argno] = NULL;
execv (shell, (char **) args);
- error (1, errno, _("cannot run %s"), shell);
+
+ {
+ int exit_status = (errno == ENOENT ? 127 : 126);
+ error (0, errno, "%s", shell);
+ exit (exit_status);
+ }
}
/* Return 1 if SHELL is a restricted shell (one not returned by
return 1;
}
-static void
+void
usage (int status)
{
if (status != 0)
else
{
printf (_("Usage: %s [OPTION]... [-] [USER [ARG]...]\n"), program_name);
- printf (_("\
+ fputs (_("\
Change the effective user id and group id to that of USER.\n\
\n\
-, -l, --login make the shell a login shell\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\
- --help display this help and exit\n\
- --version output version information and exit\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\
-"));
- puts (_("\nReport bugs to <sh-utils-bugs@gnu.org>."));
+"), stdout);
+ printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
struct passwd *pw;
struct passwd pw_copy;
+ initialize_main (&argc, &argv);
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
+ atexit (close_stdout);
+
fast_startup = 0;
simulate_login = 0;
change_environment = 1;
shell = optarg;
break;
+ case_GETOPT_HELP_CHAR;
+
+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, WRITTEN_BY);
+
default:
- usage (1);
+ usage (EXIT_FAILURE);
}
}
- if (show_version)
- {
- printf ("su (%s) %s\n", GNU_PACKAGE, VERSION);
- exit (0);
- }
-
- if (show_help)
- usage (0);
-
if (optind < argc && !strcmp (argv[optind], "-"))
{
simulate_login = 1;
pw = getpwnam (new_user);
if (pw == 0)
- error (1, 0, _("user %s does not exist"), new_user);
+ error (EXIT_FAILURE, 0, _("user %s does not exist"), new_user);
endpwent ();
+ /* Make sure pw->pw_shell is non-NULL. 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. */
+ if (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
+ pw->pw_shell = (char *) DEFAULT_SHELL;
+
/* Make a copy of the password information and point pw at the local
copy instead. Otherwise, some systems (e.g. Linux) would clobber
the static data through the getlogin call from log_su. */
#ifdef SYSLOG_FAILURE
log_su (pw, 0);
#endif
- error (1, 0, _("incorrect password"));
+ error (EXIT_FAILURE, 0, _("incorrect password"));
}
#ifdef SYSLOG_SUCCESS
else
}
#endif
- if (pw->pw_shell == 0 || pw->pw_shell[0] == 0)
- pw->pw_shell = (char *) DEFAULT_SHELL;
if (shell == 0 && change_environment == 0)
shell = getenv ("SHELL");
if (shell != 0 && getuid () && restricted_shell (pw->pw_shell))