From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / driver / passwd-pam.c
index 334d12b913c83d8d42d7822099d47b727853a86c..d463bc2de068da1e0129e4f012ed53ce2b08ba60 100644 (file)
@@ -1,7 +1,7 @@
 /* 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-2008 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-2017 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
@@ -77,9 +77,12 @@ extern void unblock_sigchld (void);
 /* 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
+#if !defined(PAM_REFRESH_CRED) && defined(PAM_CRED_REFRESH)
 # define PAM_REFRESH_CRED PAM_CRED_REFRESH
 #endif
+#if !defined(PAM_REINITIALIZE_CRED) && defined(PAM_CRED_REINITIALIZE)
+# define PAM_REINITIALIZE_CRED PAM_CRED_REINITIALIZE
+#endif
 
 static int pam_conversation (int nmsgs,
                              const struct pam_message **msg,
@@ -181,8 +184,10 @@ pam_try_unlock(saver_info *si, Bool verbose_p,
   pam_handle_t *pamh = 0;
   int status = -1;
   struct pam_conv pc;
+# ifdef HAVE_SIGTIMEDWAIT
   sigset_t set;
   struct timespec timeout;
+# endif /* HAVE_SIGTIMEDWAIT */
 
   pc.conv = &pam_conversation;
   pc.appdata_ptr = (void *) si;
@@ -240,9 +245,12 @@ pam_try_unlock(saver_info *si, Bool verbose_p,
   if (verbose_p)
     fprintf (stderr, "%s:   pam_authenticate (...) ...\n", blurb());
 
+# ifdef HAVE_SIGTIMEDWAIT
   timeout.tv_sec = 0;
   timeout.tv_nsec = 1;
-  set = block_sigchld();
+  set =
+# endif /* HAVE_SIGTIMEDWAIT */
+    block_sigchld();
   status = pam_authenticate (pamh, 0);
 # ifdef HAVE_SIGTIMEDWAIT
   sigtimedwait (&set, NULL, &timeout);
@@ -258,9 +266,22 @@ pam_try_unlock(saver_info *si, Bool 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);
 
@@ -282,16 +303,28 @@ pam_try_unlock(saver_info *si, Bool verbose_p,
                      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.
-
-         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.
        */
+
+#if defined(__linux__)
+      /* Apparently the Linux PAM library ignores PAM_REFRESH_CRED and only
+         refreshes credentials when using PAM_REINITIALIZE_CRED. */
       status2 = pam_setcred (pamh, PAM_REINITIALIZE_CRED);
+#else
+      /* But Solaris requires PAM_REFRESH_CRED or extra prompts appear. */
+      status2 = pam_setcred (pamh, PAM_REFRESH_CRED);
+#endif
+
       if (verbose_p)
         fprintf (stderr, "%s:   pam_setcred (...) ==> %d (%s)\n",
                  blurb(), status2, PAM_STRERROR(pamh, status2));
@@ -452,6 +485,14 @@ pam_conversation (int nmsgs,
 
   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)