ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-1.27.tar.Z
[xscreensaver] / driver / lock.c
index 48b2f5260480544723bc54933e49195223138ac8..3fe3a1c2bc2f2a9fa64aad697e01e79bbcc38f1a 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
+/*    xscreensaver, Copyright (c) 1993-1995 Jamie Zawinski <jwz@netscape.com>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -9,35 +9,66 @@
  * implied warranty.
  */
 
+/* #### If anyone ever finishes the Athena locking code, remove this.
+   But until then, locking requires Motif.
+ */
+#if defined(NO_MOTIF) && !defined(NO_LOCKING)
+# define NO_LOCKING
+#endif
+
+
+#ifndef NO_LOCKING
+
 #if __STDC__
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #endif
 
+#ifdef  HAVE_SHADOW
+#include <shadow.h>
+#endif
+
 #include <pwd.h>
 #include <stdio.h>
 
 #include <X11/Intrinsic.h>
 
+#include "xscreensaver.h"
+
+extern char *screensaver_version;
+extern char *progname;
+extern XtAppContext app;
+extern Bool verbose_p;
+
+#ifdef SCO
+/* SCO has some kind of goofy, nonstandard security crap.  This stuff was
+   donated by one of their victims, I mean users, Didier Poirot <dp@chorus.fr>.
+ */
+# include <sys/security.h>
+# include <sys/audit.h>
+# include <prot.h>
+#endif
+
 #if !__STDC__
 # define _NO_PROTO
 #endif
 
-#include <Xm/Xm.h>
-#include <Xm/List.h>
-#include <Xm/TextF.h>
+#ifdef NO_MOTIF
 
-#include "xscreensaver.h"
+# include <X11/StringDefs.h>
+# include <X11/Xaw/Text.h>
+# include <X11/Xaw/Label.h>
 
-#ifndef NO_LOCKING
+#else /* Motif */
 
-Time passwd_timeout;
+# include <Xm/Xm.h>
+# include <Xm/List.h>
+# include <Xm/TextF.h>
 
-extern char *screensaver_version;
-extern char *progname;
-extern XtAppContext app;
-extern Bool verbose_p;
+#endif /* Motif */
+
+Time passwd_timeout;
 
 extern Widget passwd_dialog;
 extern Widget passwd_form;
@@ -48,7 +79,8 @@ extern Widget passwd_text;
 extern Widget passwd_done;
 extern Widget passwd_cancel;
 
-extern create_passwd_dialog ();
+extern create_passwd_dialog P((Widget));
+extern void ungrab_keyboard_and_mouse P((void));
 
 static enum { pw_read, pw_ok, pw_fail, pw_cancel, pw_time } passwd_state;
 static char typed_passwd [1024];
@@ -56,34 +88,75 @@ static char typed_passwd [1024];
 static char root_passwd [255];
 static char user_passwd [255];
 
+#ifdef HAVE_SHADOW
+# define PWTYPE struct spwd *
+# define PWSLOT sp_pwdp
+# define GETPW  getspnam
+#else
+# define PWTYPE struct passwd *
+# define PWSLOT pw_passwd
+# define GETPW  getpwnam
+#endif
+
+#ifdef SCO
+# define PRPWTYPE struct pr_passwd *
+# define GETPRPW getprpwnam
+#endif
+
 Bool
 lock_init ()
 {
   Bool ok = True;
-  struct passwd *p;
   char *u;
-  p = getpwnam ("root");
-  if (p && p->pw_passwd && p->pw_passwd[0] != '*')
-    strcpy (root_passwd, p->pw_passwd);
+  PWTYPE p = GETPW ("root");
+
+#ifdef SCO
+  PRPWTYPE prpwd = GETPRPW ("root");
+  if (prpwd && *prpwd->ufld.fd_encrypt)
+    strcpy (root_passwd, prpwd->ufld.fd_encrypt);
+#else /* !SCO */
+  if (p && p->PWSLOT && p->PWSLOT[0] != '*')
+    strcpy (root_passwd, p->PWSLOT);
+#endif /* !SCO */
   else
     {
       fprintf (stderr, "%s: couldn't get root's password\n", progname);
       strcpy (root_passwd, "*");
     }
 
-  u = getlogin ();
+  /* It has been reported that getlogin() returns the wrong user id on some
+     very old SGI systems... */
+  u = (char *) getlogin ();
   if (u)
-    p = getpwnam (u);
+    {
+#ifdef SCO
+      prpwd = GETPRPW (u);
+#endif /* SCO */
+      p = GETPW (u);
+    }
   else
     {
       /* getlogin() fails if not attached to a terminal;
         in that case, use getpwuid(). */
-      p = getpwuid (getuid ());
-      u = p->pw_name;
+      struct passwd *p2 = getpwuid (getuid ());
+      u = p2->pw_name;
+#ifdef HAVE_SHADOW
+      p = GETPW (u);
+#else
+      p = p2;
+#endif
     }
 
-  if (p && p->pw_passwd && p->pw_passwd[0] != '*')
-    strcpy (user_passwd, p->pw_passwd);
+#ifdef SCO
+  if (prpwd && *prpwd->ufld.fd_encrypt)
+    strcpy (user_passwd, prpwd->ufld.fd_encrypt);
+#else /* !SCO */
+  if (p && p->PWSLOT &&
+      /* p->PWSLOT[0] != '*' */                /* sensible */
+      (strlen (p->PWSLOT) > 4)         /* solaris */
+      )
+    strcpy (user_passwd, p->PWSLOT);
+#endif /* !SCO */
   else
     {
       fprintf (stderr, "%s: couldn't get password of \"%s\"\n", progname, u);
@@ -93,6 +166,14 @@ lock_init ()
   return ok;
 }
 
+
+\f
+#if defined(NO_MOTIF) || (XmVersion >= 1002)
+   /* The `destroy' bug apears to be fixed as of Motif 1.2.1, but
+      the `verify-callback' bug is still present. */
+# define DESTROY_WORKS
+#endif
+
 static void
 passwd_cancel_cb (button, client_data, call_data)
      Widget button;
@@ -117,12 +198,16 @@ passwd_done_cb (button, client_data, call_data)
     passwd_state = pw_fail;
 }
 
-#ifdef VERIFY_CALLBACK_WORKS
+#if !defined(NO_MOTIF) && defined(VERIFY_CALLBACK_WORKS)
 
   /* ####  It looks to me like adding any modifyVerify callback causes
      ####  Motif 1.1.4 to free the the TextF_Value() twice.  I can't see
      ####  the bug in the Motif source, but Purify complains, even if
      ####  check_passwd_cb() is a no-op.
+
+     ####  Update: Motif 1.2.1 also loses, but in a different way: it
+     ####  writes beyond the end of a malloc'ed block in ModifyVerify().
+     ####  Probably this block is the text field's text.
    */
 
 static void 
@@ -180,6 +265,27 @@ Ctrl<Key>M:                done()\n\
 static char translations[] = "<Key>:keypress()";
 #endif
 
+static void
+text_field_set_string (widget, text, position)
+     Widget widget;
+     char *text;
+     int position;
+{
+#ifdef NO_MOTIF
+  XawTextBlock block;
+  block.firstPos = 0;
+  block.length = strlen (text);
+  block.ptr = text;
+  block.format = 0;
+  XawTextReplace (widget, 0, -1, &block);
+  XawTextSetInsertionPoint (widget, position);
+#else  /* !NO_MOTIF */
+  XmTextFieldSetString (widget, text);
+  XmTextFieldSetInsertionPosition (widget, position);
+#endif /* !NO_MOTIF */
+}
+
+
 static void
 keypress (w, event, argv, argc)
      Widget w;
@@ -205,8 +311,8 @@ keypress (w, event, argv, argc)
   s [++i] = 0;
   while (i--)
     s [i] = '*';
-  XmTextFieldSetString (passwd_text, s);
-  XmTextFieldSetInsertionPosition (passwd_text, j + 1);
+
+  text_field_set_string (passwd_text, s, j + 1);
 }
 
 static void
@@ -225,8 +331,8 @@ backspace (w, event, argv, argc)
   s [i] = 0;
   while (i--)
     s [i] = '*';
-  XmTextFieldSetString (passwd_text, s);
-  XmTextFieldSetInsertionPosition (passwd_text, j + 1);
+
+  text_field_set_string (passwd_text, s, j + 1);
 }
 
 static void
@@ -237,7 +343,7 @@ kill_line (w, event, argv, argc)
      Cardinal *argc;
 {
   memset (typed_passwd, 0, sizeof (typed_passwd));
-  XmTextFieldSetString (passwd_text, "");
+  text_field_set_string (passwd_text, "", 0);
 }
 
 static void
@@ -250,7 +356,7 @@ done (w, event, argv, argc)
   passwd_done_cb (w, 0, 0);
 }
 
-#endif /* !VERIFY_CALLBACK_WORKS */
+#endif /* !VERIFY_CALLBACK_WORKS || NO_MOTIF */
 
 static void
 format_into_label (widget, string)
@@ -259,22 +365,38 @@ format_into_label (widget, string)
 {
   char *label;
   char buf [255];
-  XmString xm_label = 0;
-  XmString new_xm_label;
   Arg av[10];
   int ac = 0;
+
+#ifdef NO_MOTIF
+  XtSetArg (av [ac], XtNlabel, &label); ac++;
+  XtGetValues (widget, av, ac);
+#else  /* Motif */
+  XmString xm_label = 0;
+  XmString new_xm_label;
   XtSetArg (av [ac], XmNlabelString, &xm_label); ac++;
   XtGetValues (widget, av, ac);
   XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
-  if (!strcmp (label, XtName (widget)))
+#endif /* Motif */
+
+  if (!label || !strcmp (label, XtName (widget)))
     strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
   else
     sprintf (buf, label, string);
-  new_xm_label = XmStringCreate (buf, XmSTRING_DEFAULT_CHARSET);
+
   ac = 0;
+
+#ifdef NO_MOTIF
+  XtSetArg (av [ac], XtNlabel, buf); ac++;
+#else  /* Motif */
+  new_xm_label = XmStringCreate (buf, XmSTRING_DEFAULT_CHARSET);
   XtSetArg (av [ac], XmNlabelString, new_xm_label); ac++;
+#endif /* Motif */
+
   XtSetValues (widget, av, ac);
+#ifndef NO_MOTIF
   XmStringFree (new_xm_label);
+#endif
   XtFree (label);
 }
 
@@ -305,8 +427,8 @@ roger (button, client_data, call_data)
   if (size > 40) size -= 30;
   x = (xgwa.width - size) / 2;
   y = (xgwa.height - size) / 2;
-  XtSetArg (av [ac], XmNforeground, &fg); ac++;
-  XtSetArg (av [ac], XmNbackground, &bg); ac++;
+  XtSetArg (av [ac], XtNforeground, &fg); ac++;
+  XtSetArg (av [ac], XtNbackground, &bg); ac++;
   XtGetValues (button, av, ac);
   /* if it's black on white, swap it cause it looks better (hack hack) */
   if (fg == BlackPixelOfScreen (screen) && bg == WhitePixelOfScreen (screen))
@@ -321,6 +443,17 @@ roger (button, client_data, call_data)
   XFreeGC (dpy, erase_gc);
 }
 
+#ifdef NO_MOTIF
+
+static void
+make_passwd_dialog (parent)
+     Widget parent;
+{
+  abort (); /* #### */
+}
+
+#else  /* Motif */
+
 static void
 make_passwd_dialog (parent)
      Widget parent;
@@ -340,11 +473,20 @@ make_passwd_dialog (parent)
   XtOverrideTranslations (passwd_text, XtParseTranslationTable (translations));
 #endif
 
+#if !defined(NO_MOTIF) && (XmVersion >= 1002)
+  /* The focus stuff changed around; this didn't exist in 1.1.5. */
+  XtVaSetValues (passwd_form, XmNinitialFocus, passwd_text, 0);
+#endif
+
+  /* Another random thing necessary in 1.2.1 but not 1.1.5... */
+  XtVaSetValues (roger_label, XmNborderWidth, 2, 0);
+
   pw = getpwuid (getuid ());
   format_into_label (passwd_label3, (pw->pw_name ? pw->pw_name : "???"));
   format_into_label (passwd_label1, screensaver_version);
 }
 
+#endif /* Motif */
 
 extern void idle_timer ();
 
@@ -357,7 +499,7 @@ passwd_idle_timer (junk1, junk2)
      XtPointer junk2;
 {
   Display *dpy = XtDisplay (passwd_form);
-  Window window = XtWindow (passwd_form);
+  Window window = XtWindow (XtParent(passwd_done));
   static Dimension x, y, d, s, ss;
   static GC gc = 0;
   int max = passwd_timeout / 1000;
@@ -369,18 +511,33 @@ passwd_idle_timer (junk1, junk2)
       Arg av [10];
       int ac = 0;
       XGCValues gcv;
-      unsigned long fg, bg;
-      XtSetArg (av [ac], XmNheight, &d); ac++;
-      XtGetValues (passwd_done, av, ac);
-      ac = 0;
-      XtSetArg (av [ac], XmNwidth, &x); ac++;
-      XtSetArg (av [ac], XmNheight, &y); ac++;
-      XtSetArg (av [ac], XmNforeground, &fg); ac++;
-      XtSetArg (av [ac], XmNbackground, &bg); ac++;
-      XtGetValues (passwd_form, av, ac);
-      x -= d;
-      y -= d;
-      d -= 4;
+      unsigned long fg, bg, ts, bs;
+      Dimension w = 0, h = 0;
+      XtVaGetValues(XtParent(passwd_done),
+                   XmNwidth, &w,
+                   0);
+      XtVaGetValues(passwd_done,
+                   XmNheight, &h,
+                   XmNy, &y,
+                   XtNforeground, &fg,
+                   XtNbackground, &bg,
+                   XmNtopShadowColor, &ts,
+                   XmNbottomShadowColor, &bs,
+                   0);
+
+      if (ts != bg && ts != fg)
+       fg = ts;
+      if (bs != bg && bs != fg)
+       fg = bs;
+
+      d = h / 2;
+      if (d & 1) d++;
+
+      x = (w / 2);
+
+      x -= d/2;
+      y += d/2;
+
       gcv.foreground = fg;
       if (gc) XFreeGC (dpy, gc);
       gc = XCreateGC (dpy, window, GCForeground, &gcv);
@@ -395,7 +552,8 @@ passwd_idle_timer (junk1, junk2)
 
   if (--passwd_idle_timer_tick)
     {
-      id = XtAppAddTimeOut (app, 1000, passwd_idle_timer, 0);
+      id = XtAppAddTimeOut (app, 1000,
+                           (XtTimerCallbackProc) passwd_idle_timer, 0);
       XFillArc (dpy, window, gc, x, y, d, d, ss, s);
       ss += s;
     }
@@ -413,7 +571,7 @@ pop_passwd_dialog (parent)
   int revert_to;
   typed_passwd [0] = 0;
   passwd_state = pw_read;
-  XmTextFieldSetString (passwd_text, "");
+  text_field_set_string (passwd_text, "", 0);
 
   XGetInputFocus (dpy, &focus, &revert_to);
 #ifndef DESTROY_WORKS
@@ -423,20 +581,28 @@ pop_passwd_dialog (parent)
      doesn't work right either, so we hack the window directly. FMH.
    */
   if (XtWindow (passwd_form))
-    XMapWindow (dpy, XtWindow (passwd_dialog));
+    XMapRaised (dpy, XtWindow (passwd_dialog));
 #endif
-  pop_up_dialog_box (passwd_dialog, passwd_form, 2);
 
+  pop_up_dialog_box (passwd_dialog, passwd_form, 2);
   XtManageChild (passwd_form);
-  XSetInputFocus (dpy, XtWindow (passwd_dialog), revert_to, CurrentTime);
-  XmProcessTraversal (passwd_text, 0);
+
+#if !defined(NO_MOTIF) && (XmVersion < 1002)
+  /* The focus stuff changed around; this causes problems in 1.2.1
+     but is necessary in 1.1.5. */
+  XmProcessTraversal (passwd_text, XmTRAVERSE_CURRENT);
+#endif
 
   passwd_idle_timer_tick = passwd_timeout / 1000;
-  id = XtAppAddTimeOut (app, 1000, passwd_idle_timer, 0);
+  id = XtAppAddTimeOut (app, 1000, (XtTimerCallbackProc) passwd_idle_timer, 0);
 
 
   XGrabServer (dpy);                           /* ############ DANGER! */
 
+  /* this call to ungrab used to be in main_loop() - see comment in
+      xscreensaver.c around line 696. */
+  ungrab_keyboard_and_mouse ();
+
   while (passwd_state == pw_read)
     {
       XEvent event;
@@ -462,13 +628,15 @@ pop_passwd_dialog (parent)
        case pw_cancel: lose = 0; break;
        default: abort ();
        }
+#ifndef NO_MOTIF
       XmProcessTraversal (passwd_cancel, 0); /* turn off I-beam */
+#endif
       if (lose)
        {
-         XmTextFieldSetString (passwd_text, lose);
-         XmTextFieldSetInsertionPosition (passwd_text, strlen (lose) + 1);
+         text_field_set_string (passwd_text, lose, strlen (lose) + 1);
          passwd_idle_timer_tick = 1;
-         id = XtAppAddTimeOut (app, 3000, passwd_idle_timer, 0);
+         id = XtAppAddTimeOut (app, 3000,
+                               (XtTimerCallbackProc) passwd_idle_timer, 0);
          while (1)
            {
              XEvent event;
@@ -481,10 +649,10 @@ pop_passwd_dialog (parent)
        }
     }
   memset (typed_passwd, 0, sizeof (typed_passwd));
-  XmTextFieldSetString (passwd_text, "");
+  text_field_set_string (passwd_text, "", 0);
   XtSetKeyboardFocus (parent, None);
 
-#ifndef DESTROY_WORKS
+#ifdef DESTROY_WORKS
   XtDestroyWidget (passwd_dialog);
   passwd_dialog = 0;
 #else