http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / driver / passwd.c
index d5a358c571569daafc7c892bd3413a921175eac5..066bc81f9c608d6a0178c5be12605b30556efaaf 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
 
-extern char *blurb(void);
+#ifndef VMS
+# include <pwd.h>              /* for getpwuid() */
+#else /* VMS */
+# include "vms-pwd.h"
+#endif /* VMS */
+
+#ifdef HAVE_SYSLOG
+# include <syslog.h>
+#endif /* HAVE_SYSLOG */
+
+#include <X11/Intrinsic.h>
+
+#include "xscreensaver.h"
+#include "auth.h"
+
+extern const char *blurb(void);
 extern void check_for_leaks (const char *where);
 
 
@@ -42,6 +58,8 @@ struct auth_methods {
   Bool (*init) (int argc, char **argv, Bool verbose_p);
   Bool (*priv_init) (int argc, char **argv, Bool verbose_p);
   Bool (*valid_p) (const char *typed_passwd, Bool verbose_p);
+  void (*try_unlock) (saver_info *si, Bool verbose_p,
+                     Bool (*valid_p)(const char *typed_passwd, Bool verbose_p));
   Bool initted_p;
   Bool priv_initted_p;
 };
@@ -53,7 +71,8 @@ extern Bool kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
 #endif
 #ifdef HAVE_PAM
 extern Bool pam_priv_init (int argc, char **argv, Bool verbose_p);
-extern Bool pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
+extern void pam_try_unlock (saver_info *si, Bool verbose_p,
+                           Bool (*valid_p)(const char *typed_passwd, Bool verbose_p));
 #endif
 #ifdef PASSWD_HELPER_PROGRAM
 extern Bool ext_priv_init (int argc, char **argv, Bool verbose_p);
@@ -63,6 +82,9 @@ extern Bool pwent_lock_init (int argc, char **argv, Bool verbose_p);
 extern Bool pwent_priv_init (int argc, char **argv, Bool verbose_p);
 extern Bool pwent_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
 
+Bool lock_priv_init (int argc, char **argv, Bool verbose_p);
+Bool lock_init (int argc, char **argv, Bool verbose_p);
+Bool passwd_valid_p (const char *typed_passwd, Bool verbose_p);
 
 /* The authorization methods to try, in order.
    Note that the last one (the pwent version) is actually two auth methods,
@@ -70,19 +92,19 @@ extern Bool pwent_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
    (It's all in the same file since the APIs are randomly nearly-identical.)
  */
 struct auth_methods methods[] = {
-# ifdef HAVE_KERBEROS
-  { "Kerberos",         kerberos_lock_init, 0, kerberos_passwd_valid_p,
+# ifdef HAVE_PAM
+  { "PAM",              0, pam_priv_init, 0, pam_try_unlock,
                         False, False },
 # endif
-# ifdef HAVE_PAM
-  { "PAM",              0, pam_priv_init, pam_passwd_valid_p, 
+# ifdef HAVE_KERBEROS
+  { "Kerberos",         kerberos_lock_init, 0, kerberos_passwd_valid_p, 0,
                         False, False },
 # endif
 # ifdef PASSWD_HELPER_PROGRAM
-  { "external",                0, ext_priv_init, ext_passwd_valid_p,
+  { "external",                0, ext_priv_init, ext_passwd_valid_p, 0,
                        False, False },
-#endif
-  { "normal",           pwent_lock_init, pwent_priv_init, pwent_passwd_valid_p,
+# endif
+  { "normal",           pwent_lock_init, pwent_priv_init, pwent_passwd_valid_p, 0,
                         False, False }
 };
 
@@ -135,18 +157,117 @@ lock_init (int argc, char **argv, Bool verbose_p)
 }
 
 
-Bool 
-passwd_valid_p (const char *typed_passwd, Bool verbose_p)
+/* A basic auth driver that simply prompts for a password then runs it through
+ * valid_p to determine whether the password is correct.
+ */
+static void
+try_unlock_password(saver_info *si,
+                  Bool verbose_p,
+                  Bool (*valid_p)(const char *typed_passwd, Bool verbose_p))
+{
+  struct auth_message message;
+  struct auth_response *response = NULL;
+
+  memset(&message, 0, sizeof(message));
+
+  if (verbose_p)
+    fprintf(stderr, "%s: non-PAM password auth.\n", blurb());
+
+  /* Call the auth_conv function with "Password:", then feed
+   * the result into valid_p()
+   */
+  message.type = AUTH_MSGTYPE_PROMPT_NOECHO;
+  message.msg = "Password:";
+
+  si->unlock_cb(1, &message, &response, si);
+
+  if (!response)
+    return;
+
+  if (valid_p (response->response, verbose_p))
+    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 */
+
+  if (response->response)
+    free(response->response);
+  free(response);
+}
+
+
+/* Write a password failure to the system log.
+ */
+static void
+do_syslog (saver_info *si, Bool verbose_p)
+{
+# ifdef HAVE_SYSLOG
+  struct passwd *pw = getpwuid (getuid ());
+  char *d = DisplayString (si->dpy);
+  char *u = (pw && pw->pw_name ? pw->pw_name : "???");
+  int opt = 0;
+  int fac = 0;
+
+#  ifdef LOG_PID
+  opt = LOG_PID;
+#  endif
+
+#  if defined(LOG_AUTHPRIV)
+  fac = LOG_AUTHPRIV;
+#  elif defined(LOG_AUTH)
+  fac = LOG_AUTH;
+#  else
+  fac = LOG_DAEMON;
+#  endif
+
+  if (!d) d = "";
+
+#  undef FMT
+#  define FMT "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\""
+
+  if (verbose_p)
+    fprintf (stderr, "%s: syslog: " FMT "\n", blurb(), 
+             si->unlock_failures, d, u);
+
+  openlog (progname, opt, fac);
+  syslog (LOG_NOTICE, FMT, si->unlock_failures, d, u);
+  closelog ();
+
+# endif /* HAVE_SYSLOG */
+}
+
+
+
+/**
+ * Runs through each authentication driver calling its try_unlock function.
+ * Called xss_authenticate() because AIX beat us to the name authenticate().
+ */
+void
+xss_authenticate(saver_info *si, Bool verbose_p)
 {
   int i, j;
+
   for (i = 0; i < countof(methods); i++)
     {
-      int ok_p = (methods[i].initted_p &&
-                  methods[i].valid_p (typed_passwd, verbose_p));
+      if (!methods[i].initted_p)
+        continue;
+
+      if (si->cached_passwd != NULL && methods[i].valid_p)
+       si->unlock_state = (methods[i].valid_p(si->cached_passwd, verbose_p) == True)
+                          ? ul_success : ul_fail;
+      else if (methods[i].try_unlock != NULL)
+        methods[i].try_unlock(si, verbose_p, methods[i].valid_p);
+      else if (methods[i].valid_p)
+        try_unlock_password(si, verbose_p, methods[i].valid_p);
+      else /* Ze goggles, zey do nozing! */
+        fprintf(stderr, "%s: authentication method %s does nothing.\n",
+                blurb(), methods[i].name);
 
       check_for_leaks (methods[i].name);
 
-      if (ok_p)
+      if (si->unlock_state == ul_success)
         {
           /* If we successfully authenticated by method N, but attempting
              to authenticate by method N-1 failed, mention that (since if
@@ -157,19 +278,29 @@ passwd_valid_p (const char *typed_passwd, Bool verbose_p)
             {
               for (j = 0; j < i; j++)
                 if (methods[j].initted_p)
-                  fprintf (stderr,
-                           "%s: authentication via %s passwords failed.\n",
-                           blurb(), methods[j].name);
+                    fprintf (stderr,
+                             "%s: authentication via %s failed.\n",
+                             blurb(), methods[j].name);
               fprintf (stderr,
-                       "%s: authentication via %s passwords succeeded.\n",
+                       "%s: authentication via %s succeeded.\n",
                        blurb(), methods[i].name);
             }
-
-          return True;         /* Successfully authenticated! */
+          goto DONE;           /* Successfully authenticated! */
         }
     }
 
-  return False;                        /* Authentication failure. */
+  if (verbose_p)
+    fprintf(stderr, "%s: All authentication mechanisms failed.\n", blurb());
+
+  if (si->unlock_state == ul_fail)
+    {
+      si->unlock_failures++;
+      do_syslog (si, verbose_p);
+    }
+
+DONE:
+  if (si->auth_finished_cb)
+    si->auth_finished_cb (si);
 }
 
 #endif /* NO_LOCKING -- whole file */