From 7ebfb5c90fdd47f1eef75b82c23bfcca5b4de6af Mon Sep 17 00:00:00 2001 From: nekral-guest Date: Mon, 13 Jun 2011 18:26:26 +0000 Subject: [PATCH] * lib/prototypes.h, src/suauth.c, src/su.c (check_su_auth): Do not use the pwent global variable to communicate between APIs of different files. Added boolean parameter su_to_root to check_su_auth(). * src/su.c (check_perms): Return the passwd entry of the finally authenticated user. Remove usage of the pwent variable. * src/su.c: The password of the caller is the one from the spwd structure only if the passwd's password is 'x'. --- ChangeLog | 8 ++++ lib/prototypes.h | 4 +- src/su.c | 104 +++++++++++++++++++++++------------------------ src/suauth.c | 15 +++---- 4 files changed, 67 insertions(+), 64 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6fc552d5..1871ff09 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,14 @@ restricted_shell is called only once. This will allow moving the environment definition after the switch to the new user. * src/su.c: Extract the authentication from the main function. + * lib/prototypes.h, src/suauth.c, src/su.c (check_su_auth): Do not + use the pwent global variable to communicate between APIs of + different files. Added boolean parameter su_to_root to + check_su_auth(). + * src/su.c (check_perms): Return the passwd entry of the finally + authenticated user. Remove usage of the pwent variable. + * src/su.c: The password of the caller is the one from the + spwd structure only if the passwd's password is 'x'. 2011-06-10 Nicolas François diff --git a/lib/prototypes.h b/lib/prototypes.h index a8993268..344d30fd 100644 --- a/lib/prototypes.h +++ b/lib/prototypes.h @@ -348,7 +348,9 @@ extern int safe_system (const char *command, extern long strtoday (const char *); /* suauth.c */ -extern int check_su_auth (const char *actual_id, const char *wanted_id); +extern int check_su_auth (const char *actual_id, + const char *wanted_id, + bool su_to_root); /* sulog.c */ extern void sulog (const char *tty, diff --git a/src/su.c b/src/su.c index 8938533f..e3b9d5ec 100644 --- a/src/su.c +++ b/src/su.c @@ -93,8 +93,6 @@ static int caught = 0; static pid_t pid_child = 0; #endif -extern struct passwd pwent; - /* * External identifiers */ @@ -114,7 +112,7 @@ static RETSIGTYPE kill_child (int unused(s)); static RETSIGTYPE die (int); static bool iswheel (const char *); #endif /* !USE_PAM */ -static void check_perms (void); +static struct passwd * check_perms (void); #ifndef USE_PAM /* @@ -181,12 +179,12 @@ static bool restricted_shell (const char *shellstr) return true; } -static void su_failure (const char *tty) +static void su_failure (const char *tty, bool su_to_root) { sulog (tty, false, oldname, name); /* log failed attempt */ #ifdef USE_SYSLOG if (getdef_bool ("SYSLOG_SU_ENAB")) { - SYSLOG (((0 != pwent.pw_uid) ? LOG_INFO : LOG_NOTICE, + SYSLOG ((su_to_root ? LOG_NOTICE : LOG_INFO, "- %s %s:%s", tty, ('\0' != oldname[0]) ? oldname : "???", ('\0' != name[0]) ? name : "???")); @@ -413,28 +411,18 @@ static void usage (int status) * In case of subsystem login, the user is first authenticated in the * caller's root subsystem, and then in the user's target subsystem. */ -static void check_perms (void) +static struct passwd * check_perms (void) { /* * The password file entries for the user is gotten and the account * validated. */ - pw = xgetpwnam (name); + struct passwd *pw = xgetpwnam (name); if (NULL == pw) { (void) fprintf (stderr, _("Unknown id: %s\n"), name); closelog (); exit (1); } -#ifndef USE_PAM - spwd = NULL; - if (strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING) == 0) { - spwd = getspnam (name); /* !USE_PAM, no need for xgetspnam */ - if (NULL != spwd) { - pw->pw_passwd = spwd->sp_pwdp; - } - } -#endif /* !USE_PAM */ - pwent = *pw; #ifndef USE_PAM /* @@ -456,7 +444,7 @@ static void check_perms (void) */ if (!amroot) { - if ( (0 == pwent.pw_uid) + if ( (0 == pw->pw_uid) && getdef_bool ("SU_WHEEL_ONLY") && !iswheel (oldname)) { fprintf (stderr, @@ -465,15 +453,22 @@ static void check_perms (void) exit (1); } #ifdef SU_ACCESS - switch (check_su_auth (oldname, name)) { + spwd = getspnam (name); /* !USE_PAM, no need for xgetspnam */ + if (strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING) == 0) { + if (NULL != spwd) { + pw->pw_passwd = spwd->sp_pwdp; + } + } + + switch (check_su_auth (oldname, name, 0 == pw->pw_uid)) { case 0: /* normal su, require target user's password */ break; case 1: /* require no password */ - pwent.pw_passwd = ""; /* XXX warning: const */ + pw->pw_passwd = ""; /* XXX warning: const */ break; case 2: /* require own password */ puts (_("(Enter your own password)")); - pwent.pw_passwd = oldpass; + pw->pw_passwd = oldpass; break; default: /* access denied (-1) or unexpected value */ fprintf (stderr, @@ -494,7 +489,7 @@ static void check_perms (void) pam_strerror (pamh, ret))); fprintf (stderr, _("%s: %s\n"), Prog, pam_strerror (pamh, ret)); (void) pam_end (pamh, ret); - su_failure (tty); + su_failure (tty, 0 == pw->pw_uid); } ret = pam_acct_mgmt (pamh, 0); @@ -512,7 +507,7 @@ static void check_perms (void) _("%s: %s\n"), Prog, pam_strerror (pamh, ret)); (void) pam_end (pamh, ret); - su_failure (tty); + su_failure (tty, 0 == pw->pw_uid); } } else { SYSLOG ((LOG_ERR, "pam_acct_mgmt: %s", @@ -521,7 +516,7 @@ static void check_perms (void) _("%s: %s\n"), Prog, pam_strerror (pamh, ret)); (void) pam_end (pamh, ret); - su_failure (tty); + su_failure (tty, 0 == pw->pw_uid); } } #else /* !USE_PAM */ @@ -537,11 +532,11 @@ static void check_perms (void) * character. */ if ( !amroot - && (pw_auth (pwent.pw_passwd, name, PW_SU, (char *) 0) != 0)) { - SYSLOG (((pwent.pw_uid != 0)? LOG_NOTICE : LOG_WARN, + && (pw_auth (pw->pw_passwd, name, PW_SU, (char *) 0) != 0)) { + SYSLOG (((pw->pw_uid != 0)? LOG_NOTICE : LOG_WARN, "Authentication failed for %s", name)); fprintf(stderr, _("%s: Authentication failure\n"), Prog); - su_failure (tty); + su_failure (tty, 0 == pw->pw_uid); } (void) signal (SIGQUIT, oldsig); @@ -551,7 +546,7 @@ static void check_perms (void) * expired password. */ if ((!amroot) && (NULL != spwd)) { - (void) expire (&pwent, spwd); + (void) expire (pw, spwd); } /* @@ -561,14 +556,14 @@ static void check_perms (void) * the account. */ if (!amroot) { - if (!isttytime (pwent.pw_name, "SU", time ((time_t *) 0))) { - SYSLOG (((0 != pwent.pw_uid) ? LOG_WARN : LOG_CRIT, + if (!isttytime (name, "SU", time ((time_t *) 0))) { + SYSLOG (((0 != pw->pw_uid) ? LOG_WARN : LOG_CRIT, "SU by %s to restricted account %s", oldname, name)); fprintf (stderr, _("%s: You are not authorized to su at that time\n"), Prog); - su_failure (tty); + su_failure (tty, 0 == pw->pw_uid); } } #endif /* !USE_PAM */ @@ -581,13 +576,14 @@ static void check_perms (void) * the shell specified in /etc/passwd (not the one specified with * --shell, which will be the one executed in the chroot later). */ - if ('*' == pwent.pw_shell[0]) { /* subsystem root required */ - subsystem (&pwent); /* change to the subsystem root */ + if ('*' == pw->pw_shell[0]) { /* subsystem root required */ + subsystem (pw); /* change to the subsystem root */ endpwent (); /* close the old password databases */ endspent (); return check_perms (); /* authenticate in the subsystem */ } + return pw; } /* @@ -622,8 +618,6 @@ int main (int argc, char **argv) RETSIGTYPE (*oldsig) (int); int is_console = 0; - struct spwd *spwd = 0; - #ifdef SU_ACCESS char *oldpass; #endif @@ -748,7 +742,7 @@ int main (int argc, char **argv) root_pw = getpwuid (0); if (NULL == root_pw) { SYSLOG ((LOG_CRIT, "There is no UID 0 user.")); - su_failure (tty); + su_failure (tty, true); } (void) strcpy (name, root_pw->pw_name); } @@ -770,7 +764,7 @@ int main (int argc, char **argv) Prog); SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)", (unsigned long) my_uid)); - su_failure (tty); + su_failure (tty, true); // FIXME: at this time I do not know the target UID } STRFCPY (oldname, pw->pw_name); @@ -780,9 +774,11 @@ int main (int argc, char **argv) * Sort out the password of user calling su, in case needed later * -- chris */ - spwd = getspnam (oldname); /* !USE_PAM, no need for xgetspnam */ - if (NULL != spwd) { - pw->pw_passwd = spwd->sp_pwdp; + if (strcmp (pw->pw_passwd, SHADOW_PASSWD_STRING) == 0) { + struct spwd *spwd = getspnam (oldname); + if (NULL != spwd) { + pw->pw_passwd = spwd->sp_pwdp; + } } oldpass = xstrdup (pw->pw_passwd); #endif /* SU_ACCESS */ @@ -810,7 +806,7 @@ int main (int argc, char **argv) } #endif /* USE_PAM */ - check_perms (); + pw = check_perms (); /* If the user do not want to change the environment, * use the current SHELL. @@ -825,7 +821,7 @@ int main (int argc, char **argv) * must be the one specified in /etc/passwd. */ if ( !amroot - && restricted_shell (pwent.pw_shell)) { + && restricted_shell (pw->pw_shell)) { shellstr = NULL; change_environment = true; } @@ -834,7 +830,7 @@ int main (int argc, char **argv) * in /etc/passwd. */ if (NULL == shellstr) { - shellstr = (char *) strdup (pwent.pw_shell); + shellstr = (char *) strdup (pw->pw_shell); } /* @@ -905,9 +901,9 @@ int main (int argc, char **argv) } } - cp = getdef_str ((pwent.pw_uid == 0) ? "ENV_SUPATH" : "ENV_PATH"); + cp = getdef_str ((pw->pw_uid == 0) ? "ENV_SUPATH" : "ENV_PATH"); if (NULL == cp) { - addenv ((pwent.pw_uid == 0) ? "PATH=/sbin:/bin:/usr/sbin:/usr/bin" : "PATH=/bin:/usr/bin", NULL); + addenv ((pw->pw_uid == 0) ? "PATH=/sbin:/bin:/usr/sbin:/usr/bin" : "PATH=/bin:/usr/bin", NULL); } else if (strchr (cp, '=') != NULL) { addenv (cp, NULL); } else { @@ -931,7 +927,7 @@ int main (int argc, char **argv) #ifdef USE_PAM /* set primary group id and supplementary groups */ - if (setup_groups (&pwent) != 0) { + if (setup_groups (pw) != 0) { pam_end (pamh, PAM_ABORT); exit (1); } @@ -976,7 +972,7 @@ int main (int argc, char **argv) } /* become the new user */ - if (change_uid (&pwent) != 0) { + if (change_uid (pw) != 0) { pam_close_session (pamh, 0); pam_setcred (pamh, PAM_DELETE_CRED); (void) pam_end (pamh, PAM_ABORT); @@ -987,22 +983,22 @@ int main (int argc, char **argv) /* no limits if su from root (unless su must fake login's behavior) */ if (!amroot || fakelogin) { - setup_limits (&pwent); + setup_limits (pw); } - if (setup_uid_gid (&pwent, is_console) != 0) { + if (setup_uid_gid (pw, is_console) != 0) { exit (1); } #endif /* !USE_PAM */ if (change_environment) { if (fakelogin) { - pwent.pw_shell = shellstr; - setup_env (&pwent); + pw->pw_shell = shellstr; + setup_env (pw); } else { - addenv ("HOME", pwent.pw_dir); - addenv ("USER", pwent.pw_name); - addenv ("LOGNAME", pwent.pw_name); + addenv ("HOME", pw->pw_dir); + addenv ("USER", pw->pw_name); + addenv ("LOGNAME", pw->pw_name); addenv ("SHELL", shellstr); } } diff --git a/src/suauth.c b/src/suauth.c index a2c6735a..a5bbe4c4 100644 --- a/src/suauth.c +++ b/src/suauth.c @@ -48,11 +48,6 @@ #define DENY -1 #define OWNPWORD 2 -/* - * Global variables - */ -struct passwd pwent; - #ifdef SU_ACCESS /* Really, I could do with a few const char's here defining all the @@ -65,7 +60,9 @@ static int isgrp (const char *, const char *); static int lines = 0; -int check_su_auth (const char *actual_id, const char *wanted_id) +int check_su_auth (const char *actual_id, + const char *wanted_id, + bool su_to_root) { int posn, endline; const char field[] = ":"; @@ -131,7 +128,7 @@ int check_su_auth (const char *actual_id, const char *wanted_id) if (!applies (actual_id, from_users)) continue; if (!strcmp (action, "DENY")) { - SYSLOG ((pwent.pw_uid ? LOG_NOTICE : LOG_WARN, + SYSLOG ((su_to_root ? LOG_WARN : LOG_NOTICE, "DENIED su from '%s' to '%s' (%s)\n", actual_id, wanted_id, SUAUTHFILE)); fputs (_("Access to su to that account DENIED.\n"), @@ -139,14 +136,14 @@ int check_su_auth (const char *actual_id, const char *wanted_id) fclose (authfile_fd); return DENY; } else if (!strcmp (action, "NOPASS")) { - SYSLOG ((pwent.pw_uid ? LOG_INFO : LOG_NOTICE, + SYSLOG ((su_to_root ? LOG_NOTICE : LOG_INFO, "NO password asked for su from '%s' to '%s' (%s)\n", actual_id, wanted_id, SUAUTHFILE)); fputs (_("Password authentication bypassed.\n"),stderr); fclose (authfile_fd); return NOPWORD; } else if (!strcmp (action, "OWNPASS")) { - SYSLOG ((pwent.pw_uid ? LOG_INFO : LOG_NOTICE, + SYSLOG ((su_to_root ? LOG_NOTICE : LOG_INFO, "su from '%s' to '%s': asking for user's own password (%s)\n", actual_id, wanted_id, SUAUTHFILE)); fputs (_("Please enter your OWN password as authentication.\n"),