http://ftp.x.org/contrib/applications/xscreensaver-3.03.tar.gz
[xscreensaver] / driver / lock.c
index 7a3ed6a259ffbf3ca1a6a5a6da6fdae625f8c64f..8a00b3ba154869df0ed8c0a25fb5d513ea0e4f51 100644 (file)
 #include "xscreensaver.h"
 #include "resources.h"
 
+#ifdef HAVE_SYSLOG
+# include <syslog.h>
+#endif /* HAVE_SYSLOG */
+
 #ifdef _VROOT_H_
 ERROR!  You must not include vroot.h in this file.
 #endif
@@ -35,7 +39,7 @@ extern char *getenv(const char *name);
 extern int validate_user(char *name, char *password);
 
 static Bool
-vms_passwd_valid_p(char *pw)
+vms_passwd_valid_p(char *pw, Bool verbose_p)
 {
   return (validate_user (getenv("USER"), typed_passwd) == 1);
 }
@@ -48,7 +52,7 @@ vms_passwd_valid_p(char *pw)
 #undef MAX
 #define MAX(a,b) ((a)>(b)?(a):(b))
 
-enum passwd_state { pw_read, pw_ok, pw_fail, pw_cancel, pw_time };
+enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
 
 struct passwd_dialog_data {
 
@@ -58,8 +62,10 @@ struct passwd_dialog_data {
   int i_beam;
 
   float ratio;
+  Position x, y;
   Dimension width;
   Dimension height;
+  Dimension border_width;
 
   char *heading_label;
   char *body_label;
@@ -93,6 +99,8 @@ struct passwd_dialog_data {
 
   Dimension thermo_field_x, thermo_field_y;
   Dimension thermo_field_height;
+
+  Pixmap save_under;
 };
 
 
@@ -100,7 +108,6 @@ void
 make_passwd_window (saver_info *si)
 {
   struct passwd *p = getpwuid (getuid ());
-  int x, y, bw;
   XSetWindowAttributes attrs;
   unsigned long attrmask = 0;
   Screen *screen = si->default_screen->screen;
@@ -294,23 +301,49 @@ make_passwd_window (saver_info *si)
     Dimension w = WidthOfScreen(screen);
     Dimension h = HeightOfScreen(screen);
     if (si->prefs.debug_p) w /= 2;
-    x = ((w + pw->width) / 2) - pw->width;
-    y = ((h + pw->height) / 2) - pw->height;
-    if (x < 0) x = 0;
-    if (y < 0) y = 0;
+    pw->x = ((w + pw->width) / 2) - pw->width;
+    pw->y = ((h + pw->height) / 2) - pw->height;
+    if (pw->x < 0) pw->x = 0;
+    if (pw->y < 0) pw->y = 0;
   }
 
-  bw = get_integer_resource ("passwd.borderWidth", "Dialog.BorderWidth");
+  pw->border_width = get_integer_resource ("passwd.borderWidth",
+                                           "Dialog.BorderWidth");
 
   si->passwd_dialog =
     XCreateWindow (si->dpy,
                   RootWindowOfScreen(screen),
-                  x, y, pw->width, pw->height, bw,
+                  pw->x, pw->y, pw->width, pw->height, pw->border_width,
                   DefaultDepthOfScreen (screen), InputOutput,
                   DefaultVisualOfScreen(screen),
                   attrmask, &attrs);
   XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
 
+
+  /* Before mapping the window, save the bits that are underneath the
+     rectangle the window will occlude.  When we lower the window, we
+     restore these bits.  This works, because the running screenhack
+     has already been sent SIGSTOP, so we know nothing else is drawing
+     right now! */
+  {
+    XGCValues gcv;
+    GC gc;
+    pw->save_under = XCreatePixmap (si->dpy,
+                                    si->default_screen->screensaver_window,
+                                    pw->width + (pw->border_width*2) + 1,
+                                    pw->height + (pw->border_width*2) + 1,
+                                    si->default_screen->current_depth);
+    gcv.function = GXcopy;
+    gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
+    XCopyArea (si->dpy, si->default_screen->screensaver_window,
+               pw->save_under, gc,
+               pw->x - pw->border_width, pw->y - pw->border_width,
+               pw->width + (pw->border_width*2) + 1,
+               pw->height + (pw->border_width*2) + 1,
+               0, 0);
+    XFreeGC (si->dpy, gc);
+  }
+
   XMapRaised (si->dpy, si->passwd_dialog);
   XSync (si->dpy, False);
 
@@ -599,6 +632,24 @@ destroy_passwd_window (saver_info *si)
       si->passwd_dialog = 0;
     }
   
+  if (pw->save_under)
+    {
+      XGCValues gcv;
+      GC gc;
+      gcv.function = GXcopy;
+      gc = XCreateGC (si->dpy, si->default_screen->screensaver_window,
+                      GCFunction, &gcv);
+      XCopyArea (si->dpy, pw->save_under,
+                 si->default_screen->screensaver_window, gc,
+                 0, 0,
+                 pw->width + (pw->border_width*2) + 1,
+                 pw->height + (pw->border_width*2) + 1,
+                 pw->x - pw->border_width, pw->y - pw->border_width);
+      XFreePixmap (si->dpy, pw->save_under);
+      pw->save_under = 0;
+      XFreeGC (si->dpy, gc);
+    }
+
   if (pw->heading_label) free (pw->heading_label);
   if (pw->body_label)    free (pw->body_label);
   if (pw->user_label)    free (pw->user_label);
@@ -668,6 +719,7 @@ passwd_animate_timer (XtPointer closure, XtIntervalId *id)
 static void
 handle_passwd_key (saver_info *si, XKeyEvent *event)
 {
+  saver_preferences *p = &si->prefs;
   passwd_dialog_data *pw = si->pw_data;
   int pw_size = sizeof (pw->typed_passwd) - 1;
   char *typed_passwd = pw->typed_passwd;
@@ -696,10 +748,18 @@ handle_passwd_key (saver_info *si, XKeyEvent *event)
     case '\012': case '\015':                          /* Enter */
       if (pw->state != pw_read)
        ;  /* already done? */
-      else if (passwd_valid_p (typed_passwd))
-       pw->state = pw_ok;
+      else if (typed_passwd[0] == 0)
+       pw->state = pw_null;
       else
-       pw->state = pw_fail;
+        {
+          update_passwd_window (si, "Checking...", pw->ratio);
+          XSync (si->dpy, False);
+          if (passwd_valid_p (typed_passwd, p->verbose_p))
+            pw->state = pw_ok;
+          else
+            pw->state = pw_fail;
+          update_passwd_window (si, "", pw->ratio);
+        }
       break;
 
     default:
@@ -726,6 +786,7 @@ handle_passwd_key (saver_info *si, XKeyEvent *event)
 static void
 passwd_event_loop (saver_info *si)
 {
+  saver_preferences *p = &si->prefs;
   char *msg = 0;
   XEvent event;
   passwd_animate_timer ((XtPointer) si, 0);
@@ -744,15 +805,83 @@ passwd_event_loop (saver_info *si)
   switch (si->pw_data->state)
     {
     case pw_ok:   msg = 0; break;
+    case pw_null: msg = ""; break;
     case pw_time: msg = "Timed out!"; break;
     default:      msg = "Sorry!"; break;
     }
 
+  if (si->pw_data->state == pw_fail)
+    si->unlock_failures++;
+
+  if (p->verbose_p)
+    switch (si->pw_data->state)
+      {
+      case pw_ok:
+       fprintf (stderr, "%s: password correct.\n", blurb()); break;
+      case pw_fail:
+       fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
+      case pw_null:
+      case pw_cancel:
+       fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
+      case pw_time:
+       fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
+      default: break;
+      }
+
+#ifdef HAVE_SYSLOG
+  if (si->pw_data->state == pw_fail)
+    {
+      /* If they typed a password (as opposed to just hitting return) and
+        the password was invalid, log it.
+      */
+      struct passwd *pw = getpwuid (getuid ());
+      char *d = DisplayString (si->dpy);
+      char *u = (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 = "";
+      openlog (progname, opt, fac);
+      syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
+             si->unlock_failures, d, u);
+      closelog ();
+    }
+#endif /* HAVE_SYSLOG */
+
+  if (si->pw_data->state == pw_fail)
+    XBell (si->dpy, False);
+
+  if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
+    {
+      if (si->unlock_failures == 1)
+       fprintf (real_stderr,
+                "%s: WARNING: 1 failed attempt to unlock the screen.\n",
+                blurb());
+      else
+       fprintf (real_stderr,
+                "%s: WARNING: %d failed attempts to unlock the screen.\n",
+                blurb(), si->unlock_failures);
+      fflush (real_stderr);
+
+      si->unlock_failures = 0;
+    }
+
   if (msg)
     {
       si->pw_data->i_beam = 0;
       update_passwd_window (si, msg, 0.0);
-      XBell (si->dpy, False);
       XSync (si->dpy, False);
       sleep (1);
 
@@ -765,13 +894,18 @@ passwd_event_loop (saver_info *si)
     }
 }
 
+
 Bool
 unlock_p (saver_info *si)
 {
+  saver_preferences *p = &si->prefs;
   Screen *screen = si->default_screen->screen;
   Colormap cmap = DefaultColormapOfScreen (screen);
   Bool status;
 
+  if (p->verbose_p)
+    fprintf (stderr, "%s: prompting for password.\n", blurb());
+
   if (si->pw_data || si->passwd_dialog)
     destroy_passwd_window (si);