📄 su.c
字号:
environ = (char **) xmalloc (2 * sizeof (char *));
environ[0] = 0;
if (term)
xputenv (concat ("TERM", "=", term));
if (display)
xputenv (concat ("DISPLAY", "=", display));
if (xauthority)
xputenv (concat ("XAUTHORITY", "=", xauthority));
xputenv (concat ("HOME", "=", pw->pw_dir));
xputenv (concat ("SHELL", "=", shell));
xputenv (concat ("USER", "=", pw->pw_name));
xputenv (concat ("LOGNAME", "=", pw->pw_name));
xputenv (concat ("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)
{
xputenv (concat ("HOME", "=", pw->pw_dir));
xputenv (concat ("SHELL", "=", shell));
if (pw->pw_uid)
{
xputenv (concat ("USER", "=", pw->pw_name));
xputenv (concat ("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_FAILURE, errno, _("cannot set groups"));
endgrent ();
#endif
#ifdef USE_PAM
retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
if (retval != PAM_SUCCESS)
error (1, 0, pam_strerror(pamh, retval));
#endif /* USE_PAM */
if (setgid (pw->pw_gid))
error (EXIT_FAILURE, errno, _("cannot set group id"));
if (setuid (pw->pw_uid))
error (EXIT_FAILURE, errno, _("cannot set user id"));
}
#ifdef USE_PAM
static int caught=0;
/* Signal handler for parent process later */
static void su_catch_sig(int sig)
{
++caught;
}
int
pam_copyenv (pam_handle_t *pamh)
{
char **env;
env = pam_getenvlist(pamh);
if(env) {
while(*env) {
xputenv(*env);
env++;
}
}
return(0);
}
#endif
/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
If COMMAND is nonzero, pass it to the shell with the -c option.
If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
arguments. */
static void
run_shell (const char *shell, const char *command, char **additional_args, const struct passwd *pw)
{
const char **args;
int argno = 1;
#ifdef USE_PAM
int child;
sigset_t ourset, oldset;
struct sigaction oldaction;
int status;
retval = pam_open_session(pamh,0);
if (retval != PAM_SUCCESS) {
fprintf (stderr, "could not open session\n");
exit (1);
}
/* do this at the last possible moment, because environment variables may
be passed even in the session phase
*/
if(pam_copyenv(pamh) != PAM_SUCCESS)
fprintf (stderr, "error copying PAM environment\n");
/* parent only */
sigfillset(&ourset);
if (sigprocmask(SIG_BLOCK, &ourset, &oldset)) {
fprintf(stderr, "%s: signal malfunction\n", PROGRAM_NAME);
caught = 1;
}
if (!caught) {
struct sigaction action;
action.sa_handler = su_catch_sig;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
sigemptyset(&ourset);
if (sigaddset(&ourset, SIGTERM)
|| sigaddset(&ourset, SIGALRM)
|| sigaction(SIGTERM, &action, &oldaction)
|| sigprocmask(SIG_UNBLOCK, &ourset, NULL)) {
fprintf(stderr, "%s: signal masking malfunction\n", PROGRAM_NAME);
caught = 1;
}
}
child = fork();
if (child == 0) { /* child shell */
sigprocmask(SIG_SETMASK, &oldset, NULL);
if (!caught) sigaction (SIGTERM, &oldaction, NULL);
change_identity (pw);
pam_end(pamh, 0);
#endif
if (additional_args)
args = (const char **) xmalloc (sizeof (char *)
* (10 + elements (additional_args)));
else
args = (const char **) xmalloc (sizeof (char *) * 10);
if (simulate_login)
{
char *arg0;
char *shell_basename;
if(chdir(pw->pw_dir))
error(0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
shell_basename = base_name (shell);
arg0 = xmalloc (strlen (shell_basename) + 2);
arg0[0] = '-';
strcpy (arg0 + 1, shell_basename);
args[0] = arg0;
}
else
args[0] = base_name (shell);
if (fast_startup)
args[argno++] = "-f";
if (command)
{
args[argno++] = "-c";
args[argno++] = command;
}
if (additional_args)
for (; *additional_args; ++additional_args)
args[argno++] = *additional_args;
args[argno] = NULL;
execv (shell, (char **) args);
{
int exit_status = (errno == ENOENT ? 127 : 126);
error (0, errno, "%s", shell);
exit (exit_status);
}
#ifdef USE_PAM
} else if (child == -1) {
fprintf(stderr, "can not fork user shell: %s", strerror(errno));
exit(1);
}
if (!caught) {
do {
int pid;
pid = waitpid(-1, &status, WUNTRACED);
if (WIFSTOPPED(status)) {
kill(getpid(), SIGSTOP);
/* once we get here, we must have resumed */
kill(pid, SIGCONT);
}
} while (WIFSTOPPED(status));
}
if (caught) {
fprintf(stderr, "\nSession terminated, killing shell...");
kill (child, SIGTERM);
}
retval = pam_close_session(pamh, 0);
PAM_BAIL_P;
retval = pam_end(pamh, PAM_SUCCESS);
PAM_BAIL_P;
if (caught) {
sleep(2);
kill(child, SIGKILL);
fprintf(stderr, " ...killed.\n");
exit(-1);
}
exit (WEXITSTATUS(status));
#endif /* USE_PAM */
}
/* Return 1 if SHELL is a restricted shell (one not returned by
getusershell), else 0, meaning it is a standard shell. */
static int
restricted_shell (const char *shell)
{
char *line;
setusershell ();
while ((line = getusershell ()) != NULL)
{
if (*line != '#' && strcmp (line, shell) == 0)
{
endusershell ();
return 0;
}
}
endusershell ();
return 1;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
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, --commmand=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);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
close_stdout ();
}
exit (status);
}
int
main (int argc, char **argv)
{
int optc;
const char *new_user = DEFAULT_USER;
char *command = 0;
char **additional_args = 0;
char *shell = 0;
struct passwd *pw;
struct passwd pw_copy;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
fast_startup = 0;
simulate_login = 0;
change_environment = 1;
while ((optc = getopt_long (argc, argv, "c:flmps:", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'c':
command = optarg;
break;
case 'f':
fast_startup = 1;
break;
case 'l':
simulate_login = 1;
break;
case 'm':
case 'p':
change_environment = 0;
break;
case 's':
shell = optarg;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (optind < argc && !strcmp (argv[optind], "-"))
{
simulate_login = 1;
++optind;
}
if (optind < argc)
new_user = argv[optind++];
if (optind < argc)
additional_args = argv + optind;
pw = getpwnam (new_user);
if (pw == 0)
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. */
pw_copy = *pw;
pw = &pw_copy;
pw->pw_name = xstrdup (pw->pw_name);
pw->pw_dir = xstrdup (pw->pw_dir);
pw->pw_shell = xstrdup (pw->pw_shell);
if (!correct_password (pw))
{
#ifdef SYSLOG_FAILURE
log_su (pw, 0);
#endif
error (EXIT_FAILURE, 0, _("incorrect password"));
}
#ifdef SYSLOG_SUCCESS
else
{
log_su (pw, 1);
}
#endif
if (shell == 0 && change_environment == 0)
shell = getenv ("SHELL");
if (shell != 0 && getuid () && 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 = 0;
}
if (shell == 0)
{
shell = xstrdup (pw->pw_shell);
}
modify_environment (pw, shell);
#ifdef USE_PAM
setfsuid(pw->pw_uid);
setfsgid(pw->pw_gid);
#else
change_identity (pw);
#endif
run_shell (shell, command, additional_args, pw);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -