ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-5.01.tar.gz
[xscreensaver] / driver / passwd-pam.c
index 324e31fd197188e3e87b5c9192893744f7951124..a4b132123f7c8ce63078961b80617466efef6a54 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-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
@@ -52,10 +52,12 @@ extern char *blurb(void);
 #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 */
@@ -87,6 +89,8 @@ struct pam_closure {
   Bool verbose_p;
 };
 
+Bool pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
+Bool pam_priv_init (int argc, char **argv, Bool verbose_p);
 
 #ifdef HAVE_PAM_FAIL_DELAY
    /* We handle delays ourself.*/
@@ -179,6 +183,8 @@ pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p)
   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;
@@ -212,11 +218,12 @@ pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p)
      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.
@@ -241,8 +248,11 @@ pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p)
 
   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)
@@ -250,32 +260,59 @@ pam_passwd_valid_p (const char *typed_passwd, Bool 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));
       goto DONE;
     }
 
+#ifdef ALLOW_ROOT_PASSWD
   /* 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));
 
+#endif /* ALLOW_ROOT_PASSWD */
+
  DONE:
   if (user) free (user);
   if (pamh)
@@ -307,7 +344,11 @@ pam_priv_init (int argc, char **argv, Bool verbose_p)
   const char file2[] = "/etc/pam.conf";
   struct stat st;
 
-  if (stat (dir, &st) == 0 && st.st_mode & S_IFDIR)
+# ifndef S_ISDIR
+#  define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+# endif
+
+  if (stat (dir, &st) == 0 && S_ISDIR(st.st_mode))
     {
       if (stat (file, &st) != 0)
         fprintf (stderr,