Index: kcheckpass.c
===================================================================
--- kcheckpass/kcheckpass.c	(revision 453871)
+++ kcheckpass/kcheckpass.c	(working copy)
@@ -14,7 +14,7 @@
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA  02110-1301, USA.
  *
  *
  *	kcheckpass is a simple password checker. Just invoke and
@@ -264,8 +264,13 @@
 
   va_start(ap, fmt);
   vfprintf(stderr, fmt, ap);
+  va_end(ap);
 }
 
+#ifndef O_NOFOLLOW
+# define O_NOFOLLOW 0
+#endif
+
 static void ATTR_NORETURN
 usage(int exitval)
 {
@@ -286,6 +291,14 @@
   exit(exitval);
 }
 
+static int exclusive_lock(int fd)
+{
+  struct flock lk;
+  lk.l_type = F_WRLCK;
+  lk.l_whence = SEEK_SET;
+  lk.l_start = lk.l_len = 0;
+  return fcntl(fd, F_SETLKW, &lk);
+}
 
 int
 main(int argc, char **argv)
@@ -299,10 +312,13 @@
   char		*p;
 #endif
   struct passwd	*pw;
-  int		c, nfd, lfd, numtries;
+  int		c, nfd, tfd, lfd;
   uid_t		uid;
-  long		lasttime;
+  time_t	lasttime;
   AuthReturn	ret;
+  char tmpname[64], fname[64], fcont[64];
+  time_t left = 3;
+  lfd = tfd = 0;
 
 #ifdef HAVE_OSF_C2_PASSWD
   initialize_osf_security(argc, argv);
@@ -371,6 +387,41 @@
       return AuthError;
     }
   }
+
+  /* see if we had already a failed attempt */
+  if ( uid != geteuid() ) {
+    strcpy(tmpname, "/var/lock/kcheckpass.tmp.XXXXXX");
+    if ((tfd=mkstemp(tmpname)) < 0)
+      return AuthError;
+
+    /* try locking out concurrent kcheckpass processes */
+    exclusive_lock(tfd);
+    
+    write(tfd, fcont, sprintf(fcont, "%lu\n", time(0)+left));
+    (void) lseek(tfd, 0, SEEK_SET);
+
+    sprintf(fname, "/var/lock/kcheckpass.%d", uid );
+
+    if ((lfd = open(fname, O_RDWR | O_NOFOLLOW)) >= 0) {
+      if (exclusive_lock(lfd) == 0) {
+        if ((c = read(lfd, fcont, sizeof(fcont)-1)) > 0 &&
+	    (fcont[c] = '\0', sscanf(fcont, "%ld", &lasttime) == 1))
+	  {
+            time_t ct = time(0);
+
+	    /* in case we were killed early, sleep the remaining time
+	     * to properly enforce invocation throttling and make sure
+	     * that users can't use kcheckpass for bruteforcing password
+             */
+            if(lasttime > ct && lasttime < ct + left)
+              sleep (lasttime - ct);
+          }
+      }
+      close(lfd);
+    }
+    rename(tmpname, fname);
+  }
+
   /* Now do the fandango */
   ret = Authenticate(
 #ifdef HAVE_PAM
@@ -379,35 +430,21 @@
                      method,
                      username, 
                      sfd < 0 ? conv_legacy : conv_server);
+
   if (ret == AuthOk || ret == AuthBad) {
     /* Security: Don't undermine the shadow system. */
     if (uid != geteuid()) {
-      char fname[32], fcont[32];
-      sprintf(fname, "/var/lock/kcheckpass.%d", uid);
-      if ((lfd = open(fname, O_RDWR | O_CREAT)) >= 0) {
-        struct flock lk;
-        lk.l_type = F_WRLCK;
-        lk.l_whence = SEEK_SET;
-        lk.l_start = lk.l_len = 0;
-	if (fcntl(lfd, F_SETLKW, &lk))
-          return AuthError;
-        if ((c = read(lfd, fcont, sizeof(fcont))) > 0 &&
-            (fcont[c] = 0, sscanf(fcont, "%ld %d\n", &lasttime, &numtries) == 2))
-        {
-          time_t left = lasttime - time(0);
-          if (numtries < 20)
-            numtries++;
-          left += 2 << (numtries > 10 ? numtries - 10 : 0);
-          if (left > 0)
-            sleep(left);
-        } else
-          numtries = 0;
-        if (ret == AuthBad) {
-          lseek(lfd, 0, SEEK_SET);
-          write(lfd, fcont, sprintf(fcont, "%ld %d\n", time(0), numtries));
-        } else
-          unlink(fname);
-      }
+      if (ret == AuthBad) {
+        write(tfd, fcont, sprintf(fcont, "%lu\n", time(0)+left));
+      } else
+        unlink(fname);
+	
+      unlink(tmpname);
+
+      if (ret == AuthBad)
+        sleep(left);  
+
+      close(tfd);
     }
     if (ret == AuthBad) {
       message("Authentication failure\n");
@@ -417,6 +454,7 @@
       }
     }
   }
+
   return ret;
 }