/* passwd-pam.c --- verifying typed passwords with PAM
* (Pluggable Authentication Modules.)
* written by Bill Nottingham <notting@redhat.com> (and jwz) for
- * xscreensaver, Copyright (c) 1993-2001 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-2003 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
#include <pwd.h>
#include <grp.h>
#include <security/pam_appl.h>
+#include <signal.h>
+#include <errno.h>
#include <sys/stat.h>
-extern void block_sigchld (void);
+extern sigset_t block_sigchld (void);
extern void unblock_sigchld (void);
/* blargh */
#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,
struct pam_conv pc;
struct pam_closure c;
char *user = 0;
+ sigset_t set;
+ struct timespec timeout;
struct passwd *p = getpwuid (getuid ());
if (!p) return False;
far as PAM is concerned...)
*/
{
- const char *tty = ":0.0";
- status = pam_set_item (pamh, PAM_TTY, strdup(tty));
+ char *tty = strdup (":0.0");
+ status = pam_set_item (pamh, PAM_TTY, tty);
if (verbose_p)
fprintf (stderr, "%s: pam_set_item (p, PAM_TTY, \"%s\") ==> %d (%s)\n",
blurb(), tty, status, PAM_STRERROR(pamh, status));
+ free (tty);
}
/* Try to authenticate as the current user.
PAM_NO_DELAY(pamh);
- block_sigchld();
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 1;
+ set = block_sigchld();
status = pam_authenticate (pamh, 0);
+ sigtimedwait (&set, NULL, &timeout);
unblock_sigchld();
if (verbose_p)
blurb(), status, PAM_STRERROR(pamh, status));
if (status == PAM_SUCCESS) /* Win! */
{
+ int status2;
+
+ /* We don't actually care if the account modules fail or succeed,
+ * but we need to run them anyway because certain pam modules
+ * depend on side effects of the account modules getting run.
+ */
+ status2 = pam_acct_mgmt (pamh, 0);
+
+ if (verbose_p)
+ fprintf (stderr, "%s: pam_acct_mgmt (...) ==> %d (%s)\n",
+ blurb(), status2, PAM_STRERROR(pamh, status2));
+
/* 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.
+
+ Note: this used to be PAM_REFRESH_CRED instead of
+ PAM_REINITIALIZE_CRED, but Jason Heiss <jheiss@ee.washington.edu>
+ says that the Linux PAM library ignores that one, and only refreshes
+ credentials when using PAM_REINITIALIZE_CRED.
*/
- int status2 = pam_setcred (pamh, PAM_REFRESH_CRED);
+ status2 = pam_setcred (pamh, PAM_REINITIALIZE_CRED);
if (verbose_p)
fprintf (stderr, "%s: pam_setcred (...) ==> %d (%s)\n",
blurb(), status2, PAM_STRERROR(pamh, status2));
/* If that didn't work, set the user to root, and try to authenticate again.
*/
- c.user = "root";
- status = pam_set_item (pamh, PAM_USER, strdup(c.user));
+ if (user) free (user);
+ user = strdup ("root");
+ c.user = user;
+ status = pam_set_item (pamh, PAM_USER, c.user);
if (verbose_p)
fprintf (stderr, "%s: pam_set_item(p, PAM_USER, \"%s\") ==> %d (%s)\n",
blurb(), c.user, status, PAM_STRERROR(pamh, status));
if (status != PAM_SUCCESS) goto DONE;
PAM_NO_DELAY(pamh);
+
+ set = block_sigchld();
status = pam_authenticate (pamh, 0);
+ sigtimedwait(&set, NULL, &timeout);
+ unblock_sigchld();
+
if (verbose_p)
fprintf (stderr, "%s: pam_authenticate (...) ==> %d (%s)\n",
blurb(), status, PAM_STRERROR(pamh, status));