X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fpasswd-pam.c;h=324e31fd197188e3e87b5c9192893744f7951124;hb=a1d41b2aa6e18bf9a49b914a99dda8232c5d7762;hp=a02cf81195226879c57d63e8336a2bd2a55f16af;hpb=df7adbee81405e2849728a24b498ad2117784b1f;p=xscreensaver diff --git a/driver/passwd-pam.c b/driver/passwd-pam.c index a02cf811..324e31fd 100644 --- a/driver/passwd-pam.c +++ b/driver/passwd-pam.c @@ -1,7 +1,7 @@ /* passwd-pam.c --- verifying typed passwords with PAM * (Pluggable Authentication Modules.) * written by Bill Nottingham (and jwz) for - * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski + * xscreensaver, Copyright (c) 1993-2001 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -55,6 +55,8 @@ extern char *blurb(void); #include +extern void block_sigchld (void); +extern void unblock_sigchld (void); /* blargh */ #undef Bool @@ -67,6 +69,13 @@ extern char *blurb(void); #undef countof #define countof(x) (sizeof((x))/sizeof(*(x))) +/* Some time between Red Hat 4.2 and 7.0, the words were transposed + in the various PAM_x_CRED macro names. Yay! + */ +#ifndef PAM_REFRESH_CRED +# define PAM_REFRESH_CRED PAM_CRED_REFRESH +#endif + static int pam_conversation (int nmsgs, const struct pam_message **msg, struct pam_response **resp, @@ -152,6 +161,7 @@ struct pam_closure { So we get around this by using a global variable instead. Shoot me! (I've been told this is bug 4092227, and is fixed in Solaris 7.) + (I've also been told that it's fixed in Solaris 2.6 by patch 106257-05.) */ static void *suns_pam_implementation_blows = 0; @@ -210,14 +220,46 @@ pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p) } /* Try to authenticate as the current user. + We must turn off our SIGCHLD handler for the duration of the call to + pam_authenticate(), because in some cases, the underlying PAM code + will do this: + + 1: fork a setuid subprocess to do some dirty work; + 2: read a response from that subprocess; + 3: waitpid(pid, ...) on that subprocess. + + If we (the ignorant parent process) have a SIGCHLD handler, then there's + a race condition between steps 2 and 3: if the subprocess exits before + waitpid() was called, then our SIGCHLD handler fires, and gets notified + of the subprocess death; then PAM's call to waitpid() fails, because the + process has already been reaped. + + I consider this a bug in PAM, since the caller should be able to have + whatever signal handlers it wants -- the PAM documentation doesn't say + "oh by the way, if you use PAM, you can't use SIGCHLD." */ + PAM_NO_DELAY(pamh); + + block_sigchld(); status = pam_authenticate (pamh, 0); + unblock_sigchld(); + if (verbose_p) fprintf (stderr, "%s: pam_authenticate (...) ==> %d (%s)\n", blurb(), status, PAM_STRERROR(pamh, status)); if (status == PAM_SUCCESS) /* Win! */ - goto DONE; + { + /* Each time we successfully authenticate, refresh credentials, + for Kerberos/AFS/DCE/etc. If this fails, just ignore that + failure and blunder along; it shouldn't matter. + */ + int status2 = pam_setcred (pamh, PAM_REFRESH_CRED); + if (verbose_p) + fprintf (stderr, "%s: pam_setcred (...) ==> %d (%s)\n", + blurb(), status2, PAM_STRERROR(pamh, status2)); + goto DONE; + } /* If that didn't work, set the user to root, and try to authenticate again. */