From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / driver / passwd.c
index 066bc81f9c608d6a0178c5be12605b30556efaaf..ac5a3f0f546aeda1335c372f687fc85cb61a704b 100644 (file)
@@ -1,5 +1,5 @@
 /* passwd.c --- verifying typed passwords with the OS.
- * xscreensaver, Copyright (c) 1993-2004 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-2014 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
@@ -22,6 +22,8 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
+#include <time.h>
+#include <sys/time.h>
 
 #ifndef VMS
 # include <pwd.h>              /* for getpwuid() */
@@ -249,6 +251,8 @@ xss_authenticate(saver_info *si, Bool verbose_p)
 {
   int i, j;
 
+  si->unlock_state = ul_read;
+
   for (i = 0; i < countof(methods); i++)
     {
       if (!methods[i].initted_p)
@@ -267,6 +271,20 @@ xss_authenticate(saver_info *si, Bool verbose_p)
 
       check_for_leaks (methods[i].name);
 
+      /* If password authentication failed, but the password was NULL
+         (meaning the user just hit RET) then treat that as "cancel".
+         This means that if the password is literally NULL, it will
+         work; but if not, then NULL passwords are treated as cancel.
+       */
+      if (si->unlock_state == ul_fail &&
+          si->cached_passwd &&
+          !*si->cached_passwd)
+        {
+          fprintf (stderr, "%s: assuming null password means cancel.\n",
+                   blurb());
+          si->unlock_state = ul_cancel;
+        }
+
       if (si->unlock_state == ul_success)
         {
           /* If we successfully authenticated by method N, but attempting
@@ -287,6 +305,18 @@ xss_authenticate(saver_info *si, Bool verbose_p)
             }
           goto DONE;           /* Successfully authenticated! */
         }
+      else if (si->unlock_state == ul_cancel ||
+               si->unlock_state == ul_time)
+        {
+          /* If any auth method gets a cancel or timeout, don't try the
+             next auth method!  We're done! */
+          fprintf (stderr,
+                   "%s: authentication via %s %s.\n",
+                       blurb(), methods[i].name,
+                   (si->unlock_state == ul_cancel
+                    ? "cancelled" : "timed out"));
+          goto DONE;
+        }
     }
 
   if (verbose_p)
@@ -294,6 +324,9 @@ xss_authenticate(saver_info *si, Bool verbose_p)
 
   if (si->unlock_state == ul_fail)
     {
+      /* Note the time of the first failure */
+      if (si->unlock_failures == 0)
+        si->unlock_failure_time = time((time_t *) 0);
       si->unlock_failures++;
       do_syslog (si, verbose_p);
     }