/* 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-2003 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-2012 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
PAM_NO_DELAY(pamh);
+ if (verbose_p)
+ fprintf (stderr, "%s: pam_authenticate (...) ...\n", blurb());
+
timeout.tv_sec = 0;
timeout.tv_nsec = 1;
set = block_sigchld();
status = pam_authenticate (pamh, 0);
+# ifdef HAVE_SIGTIMEDWAIT
sigtimedwait (&set, NULL, &timeout);
+ /* #### What is the portable thing to do if we don't have it? */
+# endif /* HAVE_SIGTIMEDWAIT */
unblock_sigchld();
if (verbose_p)
{
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.
+ /* On most systems, it doesn't matter whether the account modules
+ are run, or whether they fail or succeed.
+
+ On some systems, the account modules fail, because they were
+ never configured properly, but it's necessary to run them anyway
+ because certain PAM modules depend on side effects of the account
+ modules having been run.
+
+ And on still other systems, the account modules are actually
+ used, and failures in them should be considered to be true!
+
+ So:
+ - We run the account modules on all systems.
+ - Whether we ignore them is a configure option.
+
+ It's all kind of a mess.
*/
status2 = pam_acct_mgmt (pamh, 0);
blurb(), status2, PAM_STRERROR(pamh, status2));
}
+ /* If 'configure' requested that we believe the results of PAM
+ account module failures, then obey that status code.
+ Otherwise ignore it.
+ */
+#ifdef PAM_CHECK_ACCOUNT_TYPE
+ status = status2;
+#endif
+
/* 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.
(status2 == PAM_SUCCESS ? "Success" : "Failure"));
}
- si->unlock_state = (status == PAM_SUCCESS) ? ul_success : ul_fail;
+ if (status == PAM_SUCCESS)
+ si->unlock_state = ul_success; /* yay */
+ else if (si->unlock_state == ul_cancel ||
+ si->unlock_state == ul_time)
+ ; /* more specific failures ok */
+ else
+ si->unlock_state = ul_fail; /* generic failure */
}
struct auth_response *authresp = 0;
struct pam_response *pam_responses;
saver_info *si = (saver_info *) vsaver_info;
+ Bool verbose_p;
/* On SunOS 5.6, the `closure' argument always comes in as random garbage. */
si = (saver_info *) suns_pam_implementation_blows;
+ verbose_p = si->prefs.verbose_p;
+
/* Converting the PAM prompts into the XScreenSaver native format.
* It was a design goal to collapse (INFO,PROMPT) pairs from PAM
* into a single call to the unlock_cb function. The unlock_cb function
if (!pam_responses || !messages)
goto end;
+ if (verbose_p)
+ fprintf (stderr, "%s: pam_conversation (", blurb());
+
for (i = 0; i < nmsgs; ++i)
{
+ if (verbose_p && i > 0) fprintf (stderr, ", ");
+
messages[i].msg = msg[i]->msg;
- /* Default fallback of PROMPT_ECHO */
- messages[i].type =
- msg[i]->msg_style == PAM_PROMPT_ECHO_OFF
- ? AUTH_MSGTYPE_PROMPT_NOECHO
- : msg[i]->msg_style == PAM_PROMPT_ECHO_ON
- ? AUTH_MSGTYPE_PROMPT_ECHO
- : msg[i]->msg_style == PAM_ERROR_MSG
- ? AUTH_MSGTYPE_ERROR
- : msg[i]->msg_style == PAM_TEXT_INFO
- ? AUTH_MSGTYPE_INFO
- : AUTH_MSGTYPE_PROMPT_ECHO;
+ switch (msg[i]->msg_style) {
+ case PAM_PROMPT_ECHO_OFF: messages[i].type = AUTH_MSGTYPE_PROMPT_NOECHO;
+ if (verbose_p) fprintf (stderr, "ECHO_OFF");
+ break;
+ case PAM_PROMPT_ECHO_ON: messages[i].type = AUTH_MSGTYPE_PROMPT_ECHO;
+ if (verbose_p) fprintf (stderr, "ECHO_ON");
+ break;
+ case PAM_ERROR_MSG: messages[i].type = AUTH_MSGTYPE_ERROR;
+ if (verbose_p) fprintf (stderr, "ERROR_MSG");
+ break;
+ case PAM_TEXT_INFO: messages[i].type = AUTH_MSGTYPE_INFO;
+ if (verbose_p) fprintf (stderr, "TEXT_INFO");
+ break;
+ default: messages[i].type = AUTH_MSGTYPE_PROMPT_ECHO;
+ if (verbose_p) fprintf (stderr, "PROMPT_ECHO");
+ break;
+ }
+
+ if (verbose_p)
+ fprintf (stderr, "=\"%s\"", msg[i]->msg ? msg[i]->msg : "(null)");
}
+ if (verbose_p)
+ fprintf (stderr, ") ...\n");
+
ret = si->unlock_cb(nmsgs, messages, &authresp, si);
+ /* #### If the user times out, or hits ESC or Cancel, we return PAM_CONV_ERR,
+ and PAM logs this as an authentication failure. It would be nice if
+ there was some way to indicate that this was a "cancel" rather than
+ a "fail", so that it wouldn't show up in syslog, but I think the
+ only options are PAM_SUCCESS and PAM_CONV_ERR. (I think that
+ PAM_ABORT means "internal error", not "cancel".) Bleh.
+ */
+
if (ret == 0)
{
for (i = 0; i < nmsgs; ++i)
if (authresp)
free(authresp);
+ if (verbose_p)
+ fprintf (stderr, "%s: pam_conversation (...) ==> %s\n", blurb(),
+ (ret == 0 ? "PAM_SUCCESS" : "PAM_CONV_ERR"));
+
if (ret == 0)
{
*resp = pam_responses;