open-src/app/xlock/sun-src/xlock.c
changeset 546 f3f84c886c69
child 907 3c35d611cdaa
equal deleted inserted replaced
545:43240086238f 546:f3f84c886c69
       
     1 #pragma ident   "@(#)xlock.c 35.11     08/09/18 SMI"
       
     2 /*
       
     3  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
       
     4  * Use is subject to license terms.
       
     5  *
       
     6  * Permission is hereby granted, free of charge, to any person obtaining a
       
     7  * copy of this software and associated documentation files (the
       
     8  * "Software"), to deal in the Software without restriction, including
       
     9  * without limitation the rights to use, copy, modify, merge, publish,
       
    10  * distribute, and/or sell copies of the Software, and to permit persons
       
    11  * to whom the Software is furnished to do so, provided that the above
       
    12  * copyright notice(s) and this permission notice appear in all copies of
       
    13  * the Software and that both the above copyright notice(s) and this
       
    14  * permission notice appear in supporting documentation.
       
    15  *
       
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
       
    17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       
    18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
       
    19  * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
       
    20  * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
       
    21  * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
       
    22  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
       
    23  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
       
    24  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
       
    25  *
       
    26  * Except as contained in this notice, the name of a copyright holder
       
    27  * shall not be used in advertising or otherwise to promote the sale, use
       
    28  * or other dealings in this Software without prior written authorization
       
    29  * of the copyright holder.
       
    30  */
       
    31 /*
       
    32  * xlock.c - X11 client to lock a display and show a screen saver.
       
    33  *
       
    34  * Copyright (c) 1988-91 by Patrick J. Naughton.
       
    35  *
       
    36  * Permission to use, copy, modify, and distribute this software and its
       
    37  * documentation for any purpose and without fee is hereby granted,
       
    38  * provided that the above copyright notice appear in all copies and that
       
    39  * both that copyright notice and this permission notice appear in
       
    40  * supporting documentation.
       
    41  *
       
    42  * This file is provided AS IS with no warranties of any kind.  The author
       
    43  * shall have no liability with respect to the infringement of copyrights,
       
    44  * trade secrets or any patents by this file or any part thereof.  In no
       
    45  * event will the author be liable for any lost revenue or profits or
       
    46  * other special, indirect and consequential damages.
       
    47  *
       
    48  * Comments and additions should be sent to the author:
       
    49  *
       
    50  *		       [email protected]
       
    51  *
       
    52  *		       Patrick J. Naughton
       
    53  *		       MS 10-20
       
    54  *		       Sun Laboritories, Inc.
       
    55  *		       2550 Garcia Ave
       
    56  *		       Mountain View, CA  94043
       
    57  *
       
    58  * Revision History:
       
    59  * 
       
    60  * 24-Jun-91: make foreground and background color get used on mono.
       
    61  * 24-May-91: added -usefirst.
       
    62  * 16-May-91: added pyro and random modes.
       
    63  *	      ripped big comment block out of all other files.
       
    64  * 08-Jan-91: fix some problems with password entry.
       
    65  *	      removed renicing code.
       
    66  * 29-Oct-90: added cast to XFree() arg.
       
    67  *	      added volume arg to call to XBell().
       
    68  * 28-Oct-90: center prompt screen.
       
    69  *	      make sure Xlib input buffer does not use up all of swap.
       
    70  *	      make displayed text come from resource file for better I18N.
       
    71  *	      add backward compatible signal handlers for pre 4.1 machines.
       
    72  * 31-Aug-90: added blank mode.
       
    73  *	      added swarm mode.
       
    74  *	      moved usleep() and seconds() out to usleep.c.
       
    75  *	      added SVR4 defines to xlock.h
       
    76  * 29-Jul-90: added support for multiple screens to be locked by one xlock.
       
    77  *	      moved global defines to xlock.h
       
    78  *	      removed use of allowsig().
       
    79  * 07-Jul-90: reworked commandline args and resources to use Xrm.
       
    80  *	      moved resource processing out to resource.c
       
    81  * 02-Jul-90: reworked colors to not use dynamic colormap.
       
    82  * 23-May-90: added autoraise when obscured.
       
    83  * 15-Apr-90: added hostent alias searching for host authentication.
       
    84  * 18-Feb-90: added SunOS3.5 fix.
       
    85  *	      changed -mono -> -color, and -saver -> -lock.
       
    86  *	      allow non-locking screensavers to display on remote machine.
       
    87  *	      added -echokeys to disable echoing of '?'s on input.
       
    88  *	      cleaned up all of the parameters and defaults.
       
    89  * 20-Dec-89: added -xhost to allow access control list to be left alone.
       
    90  *	      added -screensaver (don't disable screen saver) for the paranoid.
       
    91  *	      Moved seconds() here from all of the display mode source files.
       
    92  *	      Fixed bug with calling XUngrabHosts() in finish().
       
    93  * 19-Dec-89: Fixed bug in GrabPointer.
       
    94  *	      Changed fontname to XLFD style.
       
    95  * 23-Sep-89: Added fix to allow local hostname:0 as a display.
       
    96  *	      Put empty case for Enter/Leave events.
       
    97  *	      Moved colormap installation later in startup.
       
    98  * 20-Sep-89: Linted and made -saver mode grab the keyboard and mouse.
       
    99  *	      Replaced SunView code for life mode with Jim Graham's version,
       
   100  *		so I could contrib it without legal problems.
       
   101  *	      Sent to expo for X11R4 contrib.
       
   102  * 19-Sep-89: Added '?'s on input.
       
   103  * 27-Mar-89: Added -qix mode.
       
   104  *	      Fixed GContext->GC.
       
   105  * 20-Mar-89: Added backup font (fixed) if XQueryLoadFont() fails.
       
   106  *	      Changed default font to lucida-sans-24.
       
   107  * 08-Mar-89: Added -nice, -mode and -display, built vector for life and hop.
       
   108  * 24-Feb-89: Replaced hopalong display with life display from SunView1.
       
   109  * 22-Feb-89: Added fix for color servers with n < 8 planes.
       
   110  * 16-Feb-89: Updated calling conventions for XCreateHsbColormap();
       
   111  *	      Added -count for number of iterations per color.
       
   112  *	      Fixed defaulting mechanism.
       
   113  *	      Ripped out VMS hacks.
       
   114  *	      Sent to expo for X11R3 contrib.
       
   115  * 15-Feb-89: Changed default font to pellucida-sans-18.
       
   116  * 20-Jan-89: Added -verbose and fixed usage message.
       
   117  * 19-Jan-89: Fixed monochrome gc bug.
       
   118  * 16-Dec-88: Added SunView style password prompting.
       
   119  * 19-Sep-88: Changed -color to -mono. (default is color on color displays).
       
   120  *	      Added -saver option. (just do display... don't lock.)
       
   121  * 31-Aug-88: Added -time option.
       
   122  *	      Removed code for fractals to separate file for modularity.
       
   123  *	      Added signal handler to restore host access.
       
   124  *	      Installs dynamic colormap with a Hue Ramp.
       
   125  *	      If grabs fail then exit.
       
   126  *	      Added VMS Hacks. (password 'iwiwuu').
       
   127  *	      Sent to expo for X11R2 contrib.
       
   128  * 08-Jun-88: Fixed root password pointer problem and changed PASSLENGTH to 20.
       
   129  * 20-May-88: Added -root to allow root to unlock.
       
   130  * 12-Apr-88: Added root password override.
       
   131  *	      Added screen saver override.
       
   132  *	      Removed XGrabServer/XUngrabServer.
       
   133  *	      Added access control handling instead.
       
   134  * 01-Apr-88: Added XGrabServer/XUngrabServer for more security.
       
   135  * 30-Mar-88: Removed startup password requirement.
       
   136  *	      Removed cursor to avoid phosphor burn.
       
   137  * 27-Mar-88: Rotate fractal by 45 degrees clockwise.
       
   138  * 24-Mar-88: Added color support. [-color]
       
   139  *	      wrote the man page.
       
   140  * 23-Mar-88: Added HOPALONG routines from Scientific American Sept. 86 p. 14.
       
   141  *	      added password requirement for invokation
       
   142  *	      removed option for command line password
       
   143  *	      added requirement for display to be "unix:0".
       
   144  * 22-Mar-88: Recieved Walter Milliken's comp.windows.x posting.
       
   145  *
       
   146  */
       
   147 
       
   148 #include <stdio.h>
       
   149 #include <signal.h>
       
   150 #include <string.h>
       
   151 #ifdef SYSV
       
   152 #include <shadow.h>
       
   153 #endif
       
   154 #include <pwd.h>
       
   155 
       
   156 #include "xlock.h"
       
   157 #include <X11/cursorfont.h>
       
   158 #include <X11/Xatom.h>
       
   159 
       
   160 #ifdef USE_PAM
       
   161 # include <security/pam_appl.h>
       
   162 # ifndef XLOCK_PAM_SERVICE
       
   163 #  define XLOCK_PAM_SERVICE "xlock"
       
   164 # endif
       
   165 # define PAM_ERROR_PRINT(pamfunc)	\
       
   166  if (verbose) { \
       
   167    fprintf(stderr, "%s: %s failure: %s\n", ProgramName, pamfunc, \
       
   168      pam_strerror(pamh, pam_error)); \
       
   169  }
       
   170 # ifdef sun
       
   171 #  include <deflt.h>
       
   172 # endif
       
   173 #endif
       
   174 
       
   175 char       *ProgramName;	/* argv[0] */
       
   176 perscreen   Scr[MAXSCREENS];
       
   177 Display    *dsp = NULL;		/* server display connection */
       
   178 int         screen;		/* current screen */
       
   179 void        (*callback) () = NULL;
       
   180 void        (*init) () = NULL;
       
   181 
       
   182 static int  screens;		/* number of screens */
       
   183 static Window win[MAXSCREENS];	/* window used to cover screen */
       
   184 static Window icon[MAXSCREENS];	/* window used during password typein */
       
   185 static Window root[MAXSCREENS];	/* convenience pointer to the root window */
       
   186 static GC   textgc[MAXSCREENS];	/* graphics context used for text rendering */
       
   187 static XColor fgcol[MAXSCREENS];/* used for text rendering */
       
   188 static XColor bgcol[MAXSCREENS];/* background of text screen */
       
   189 XColor ssblack[MAXSCREENS];/* black color for screen saver screen */
       
   190 XColor sswhite[MAXSCREENS];/* white color for screen saver screen */
       
   191 static int  iconx[MAXSCREENS];	/* location of left edge of icon */
       
   192 static int  icony[MAXSCREENS];	/* location of top edge of icon */
       
   193 static Cursor mycursor;		/* blank cursor */
       
   194 static Cursor passwdcursor;	/* cursor used in getPassword */
       
   195 static Pixmap lockc;
       
   196 static Pixmap lockm;		/* pixmaps for cursor and mask */
       
   197 static char no_bits[] = {0};	/* dummy array for the blank cursor */
       
   198 static int  passx;		/* position of the ?'s */
       
   199 static int  passy;
       
   200 static XFontStruct *font;
       
   201 static int  sstimeout;		/* screen saver parameters */
       
   202 static int  ssinterval;
       
   203 static int  ssblanking;
       
   204 static int  ssexposures;
       
   205 
       
   206 static char buffer[PAM_MAX_RESP_SIZE];
       
   207 static Bool reallyechokeys = False; /* Echo real keys instead of ?'s */
       
   208 static Bool stoptryingfornow = False;
       
   209 
       
   210 #define FALLBACK_FONTNAME	"fixed"
       
   211 #define ICONW			64
       
   212 #define ICONH			64
       
   213 
       
   214 #ifdef DEBUG
       
   215 #define WIDTH WidthOfScreen(scr) - 100
       
   216 #define HEIGHT HeightOfScreen(scr) - 100
       
   217 #define CWMASK CWBackPixel | CWEventMask | CWColormap
       
   218 #else
       
   219 #define WIDTH WidthOfScreen(scr)
       
   220 #define HEIGHT HeightOfScreen(scr)
       
   221 #define CWMASK CWOverrideRedirect | CWBackPixel | CWEventMask | CWColormap
       
   222 #endif
       
   223 
       
   224 #define AllPointerEventMask \
       
   225 	(ButtonPressMask | ButtonReleaseMask | \
       
   226 	EnterWindowMask | LeaveWindowMask | \
       
   227 	PointerMotionMask | PointerMotionHintMask | \
       
   228 	Button1MotionMask | Button2MotionMask | \
       
   229 	Button3MotionMask | Button4MotionMask | \
       
   230 	Button5MotionMask | ButtonMotionMask | \
       
   231 	KeymapStateMask)
       
   232 
       
   233 /* VARARGS1 */
       
   234 void
       
   235 error(s1, s2)
       
   236     char       *s1, *s2;
       
   237 {
       
   238     fprintf(stderr, s1, ProgramName, s2);
       
   239     exit(1);
       
   240 }
       
   241 
       
   242 /*
       
   243  * Server access control support.
       
   244  */
       
   245 
       
   246 static XHostAddress *XHosts;	/* the list of "friendly" client machines */
       
   247 static int  HostAccessCount;	/* the number of machines in XHosts */
       
   248 static Bool HostAccessState;	/* whether or not we even look at the list */
       
   249 
       
   250 static void
       
   251 XGrabHosts(dsp)
       
   252     Display    *dsp;
       
   253 {
       
   254     XHosts = XListHosts(dsp, &HostAccessCount, &HostAccessState);
       
   255     if (XHosts)
       
   256 	XRemoveHosts(dsp, XHosts, HostAccessCount);
       
   257     XEnableAccessControl(dsp);
       
   258 }
       
   259 
       
   260 static void
       
   261 XUngrabHosts(dsp)
       
   262     Display    *dsp;
       
   263 {
       
   264     if (XHosts) {
       
   265 	XAddHosts(dsp, XHosts, HostAccessCount);
       
   266 	XFree((char *) XHosts);
       
   267     }
       
   268     if (HostAccessState == False)
       
   269 	XDisableAccessControl(dsp);
       
   270 }
       
   271 
       
   272 
       
   273 /*
       
   274  * Simple wrapper to get an asynchronous grab on the keyboard and mouse.
       
   275  * If either grab fails, we sleep for one second and try again since some
       
   276  * window manager might have had the mouse grabbed to drive the menu choice
       
   277  * that picked "Lock Screen..".  If either one fails the second time we print
       
   278  * an error message and exit.
       
   279  */
       
   280 static void
       
   281 GrabKeyboardAndMouse()
       
   282 {
       
   283     Status      status;
       
   284 
       
   285     status = XGrabKeyboard(dsp, win[0], True,
       
   286 			   GrabModeAsync, GrabModeAsync, CurrentTime);
       
   287     if (status != GrabSuccess) {
       
   288 	sleep(1);
       
   289 	status = XGrabKeyboard(dsp, win[0], True,
       
   290 			       GrabModeAsync, GrabModeAsync, CurrentTime);
       
   291 
       
   292 	if (status != GrabSuccess)
       
   293 	    error("%s: couldn't grab keyboard! (%d)\n", status);
       
   294     }
       
   295     status = XGrabPointer(dsp, win[0], True, AllPointerEventMask,
       
   296 			  GrabModeAsync, GrabModeAsync, None, mycursor,
       
   297 			  CurrentTime);
       
   298     if (status != GrabSuccess) {
       
   299 	sleep(1);
       
   300 	status = XGrabPointer(dsp, win[0], True, AllPointerEventMask,
       
   301 			      GrabModeAsync, GrabModeAsync, None, mycursor,
       
   302 			      CurrentTime);
       
   303 
       
   304 	if (status != GrabSuccess)
       
   305 	    error("%s: couldn't grab pointer! (%d)\n", status);
       
   306     }
       
   307 }
       
   308 
       
   309 
       
   310 /*
       
   311  * Assuming that we already have an asynch grab on the pointer,
       
   312  * just grab it again with a new cursor shape and ignore the return code.
       
   313  */
       
   314 static void
       
   315 XChangeGrabbedCursor(cursor)
       
   316     Cursor      cursor;
       
   317 {
       
   318 #ifndef DEBUG
       
   319     (void) XGrabPointer(dsp, win[0], True, AllPointerEventMask,
       
   320 		    GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
       
   321 #endif
       
   322 }
       
   323 
       
   324 
       
   325 /*
       
   326  * Restore all grabs, reset screensaver, restore colormap, close connection.
       
   327  */
       
   328 static void
       
   329 finish()
       
   330 {
       
   331     XSync(dsp, False);
       
   332     if (!nolock && !allowaccess)
       
   333 	XUngrabHosts(dsp);
       
   334     XUngrabPointer(dsp, CurrentTime);
       
   335     XUngrabKeyboard(dsp, CurrentTime);
       
   336     if (!enablesaver)
       
   337 	XSetScreenSaver(dsp, sstimeout, ssinterval, ssblanking, ssexposures);
       
   338     XFlush(dsp);
       
   339     XCloseDisplay(dsp);
       
   340 }
       
   341 
       
   342 
       
   343 static int
       
   344 ReadXString(s, slen)
       
   345     char       *s;
       
   346     int         slen;
       
   347 {
       
   348     XEvent      event;
       
   349     char        keystr[20];
       
   350     char        c;
       
   351     int         i;
       
   352     int         bp;
       
   353     int         len;
       
   354     int         thisscreen = screen;
       
   355     char	pwbuf[PAM_MAX_RESP_SIZE];
       
   356 
       
   357     for (screen = 0; screen < screens; screen++)
       
   358 	if (thisscreen == screen)
       
   359 	    init(icon[screen]);
       
   360 	else
       
   361 	    init(win[screen]);
       
   362     bp = 0;
       
   363     *s = 0;
       
   364     while (True) {
       
   365 	unsigned long lasteventtime = seconds();
       
   366 	while (!XPending(dsp)) {
       
   367 	    for (screen = 0; screen < screens; screen++)
       
   368 		if (thisscreen == screen)
       
   369 		    callback(icon[screen]);
       
   370 		else
       
   371 		    callback(win[screen]);
       
   372 	    XFlush(dsp);
       
   373 	    usleep(delay);
       
   374 	    if (seconds() - lasteventtime > timeout) {
       
   375 		screen = thisscreen;
       
   376 		stoptryingfornow = True;
       
   377 		return 1;
       
   378 	    }
       
   379 	}
       
   380 	screen = thisscreen;
       
   381 	XNextEvent(dsp, &event);
       
   382 	switch (event.type) {
       
   383 	case KeyPress:
       
   384 	    len = XLookupString((XKeyEvent *) & event, keystr, 20, NULL, NULL);
       
   385 	    for (i = 0; i < len; i++) {
       
   386 		c = keystr[i];
       
   387 		switch (c) {
       
   388 		case 8:	/* ^H */
       
   389 		case 127:	/* DEL */
       
   390 		    if (bp > 0)
       
   391 			bp--;
       
   392 		    break;
       
   393 		case 10:	/* ^J */
       
   394 		case 13:	/* ^M */
       
   395 		    s[bp] = '\0';
       
   396 	            /*
       
   397 	             * eat all events if there are more than enough pending... this
       
   398 	             * keeps the Xlib event buffer from growing larger than all
       
   399 	             * available memory and crashing xlock.
       
   400 	             */
       
   401 	            if (XPending(dsp) > 100) {	/* 100 is arbitrarily big enough */
       
   402 		        register Status status;
       
   403 		        do {
       
   404 		            status = XCheckMaskEvent(dsp,
       
   405 				              KeyPressMask | KeyReleaseMask, &event);
       
   406 		        } while (status);
       
   407 		        XBell(dsp, 100);
       
   408 	            }
       
   409 		    return 0;
       
   410 		case 21:	/* ^U */
       
   411 		    bp = 0;
       
   412 		    break;
       
   413 		default:
       
   414 		    s[bp] = c;
       
   415 		    if (bp < slen - 1)
       
   416 			bp++;
       
   417 		    else
       
   418 			XSync(dsp, True);	/* flush input buffer */
       
   419 		}
       
   420 	    }
       
   421 	    XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
       
   422 	    if (echokeys || reallyechokeys) {
       
   423 		if (reallyechokeys) {
       
   424 		    memcpy(pwbuf, s, slen);
       
   425 		} else {
       
   426 		    memset(pwbuf, '?', slen);
       
   427 		} 
       
   428 
       
   429 		XFillRectangle(dsp, win[screen], Scr[screen].gc,
       
   430 			       passx, passy - font->ascent,
       
   431 			       XTextWidth(font, pwbuf, slen),
       
   432 			       font->ascent + font->descent);
       
   433 		XDrawString(dsp, win[screen], textgc[screen],
       
   434 			    passx, passy, pwbuf, bp);
       
   435 	    }
       
   436 	    /*
       
   437 	     * eat all events if there are more than enough pending... this
       
   438 	     * keeps the Xlib event buffer from growing larger than all
       
   439 	     * available memory and crashing xlock.
       
   440 	     */
       
   441 	    if (XPending(dsp) > 100) {	/* 100 is arbitrarily big enough */
       
   442 		register Status status;
       
   443 		do {
       
   444 		    status = XCheckMaskEvent(dsp,
       
   445 				      KeyPressMask | KeyReleaseMask, &event);
       
   446 		} while (status);
       
   447 		XBell(dsp, 100);
       
   448 	    }
       
   449 	    break;
       
   450 
       
   451 	case ButtonPress:
       
   452 	    if (((XButtonEvent *) & event)->window == icon[screen]) {
       
   453 		stoptryingfornow = True;
       
   454 		return 1;
       
   455 	    }
       
   456 	    break;
       
   457 
       
   458 	case VisibilityNotify:
       
   459 	    if (event.xvisibility.state != VisibilityUnobscured) {
       
   460 #ifndef DEBUG
       
   461 		XRaiseWindow(dsp, win[screen]);
       
   462 #endif
       
   463 		s[0] = '\0';
       
   464 		return 1;
       
   465 	    }
       
   466 	    break;
       
   467 
       
   468 	case KeymapNotify:
       
   469 	case KeyRelease:
       
   470 	case ButtonRelease:
       
   471 	case MotionNotify:
       
   472 	case LeaveNotify:
       
   473 	case EnterNotify:
       
   474 	    break;
       
   475 
       
   476 	default:
       
   477 	    fprintf(stderr, "%s: unexpected event: %d\n",
       
   478 		    ProgramName, event.type);
       
   479 	    break;
       
   480 	}
       
   481     }
       
   482 }
       
   483 
       
   484 
       
   485 static int
       
   486 CheckPassword()
       
   487 {
       
   488 #ifdef SYSV
       
   489     struct spwd *rspw, *uspw;
       
   490     struct passwd *upw;
       
   491     char       *user;
       
   492 #else
       
   493     struct passwd *rpw, *upw;
       
   494 #endif /* SYSV */
       
   495 
       
   496 #ifdef SYSV
       
   497     rspw = getspnam("root");
       
   498 
       
   499     upw = (struct passwd *)getpwuid(getuid());
       
   500     if (upw == NULL) { 	/* should not pass NULL to getspnam  */
       
   501 	user = "";
       
   502     }
       
   503     else {
       
   504 	user = upw->pw_name;
       
   505     }
       
   506     uspw = getspnam(user);
       
   507     if (!uspw) {
       
   508 	if (allowroot) {
       
   509 		if (!rspw)
       
   510 			return(1);
       
   511 		else
       
   512 			return(0);
       
   513 	}
       
   514 	return(1);
       
   515     }
       
   516 #else 	/* SYSV */
       
   517     rpw = (struct passwd *)getpwuid(0);
       
   518  
       
   519     upw = (struct passwd *)getpwuid(getuid());
       
   520 
       
   521     if (!upw) {
       
   522 	if (allowroot) {
       
   523 		if (!rpw)
       
   524 			return(1);
       
   525 		else
       
   526 			return(0);
       
   527 	}
       
   528 	return(1);
       
   529     }
       
   530 #endif 	/* SYSV */
       
   531 
       
   532     return(0);
       
   533 }
       
   534 
       
   535 
       
   536 static void passwordPrompt(const char *prompt)
       
   537 {
       
   538     int         y, left;
       
   539     Screen     *scr = ScreenOfDisplay(dsp, screen);
       
   540 
       
   541     left = iconx[screen] + ICONW + font->max_bounds.width;
       
   542     y = icony[screen] + font->ascent + font->ascent + font->descent + 2;
       
   543 
       
   544     XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
       
   545 
       
   546     XFillRectangle(dsp, win[screen], Scr[screen].gc,
       
   547 		       left, y - font->ascent, WIDTH - left, 
       
   548       		       font->ascent + font->descent + 2);
       
   549 
       
   550     XDrawString(dsp, win[screen], textgc[screen],
       
   551 		left, y, prompt, strlen(prompt));
       
   552     XDrawString(dsp, win[screen], textgc[screen],
       
   553 		left + 1, y, prompt, strlen(prompt));
       
   554 
       
   555     passx = left + 1 + XTextWidth(font, prompt, strlen(prompt))
       
   556 	+ XTextWidth(font, " ", 1);
       
   557     passy = y;
       
   558 }
       
   559 
       
   560 static void displayTextInfo(const char *infoMsg)
       
   561 {
       
   562     int         y;
       
   563     Screen     *scr = ScreenOfDisplay(dsp, screen);
       
   564 
       
   565     y = icony[screen] + ICONH + font->ascent + 2;
       
   566 
       
   567     XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
       
   568 
       
   569     XFillRectangle(dsp, win[screen], Scr[screen].gc,
       
   570 		       iconx[screen], y - font->ascent,
       
   571 		       WIDTH - iconx[screen], 
       
   572       		       font->ascent + font->descent + 2);
       
   573 
       
   574     XDrawString(dsp, win[screen], textgc[screen],
       
   575 		iconx[screen], y, infoMsg, strlen(infoMsg));
       
   576 }
       
   577 
       
   578 #ifdef USE_PAM
       
   579 static int pamconv(int num_msg, struct pam_message **msg,
       
   580               struct pam_response **response, void *appdata_ptr)
       
   581 {
       
   582     int i;
       
   583     int status = PAM_SUCCESS;
       
   584     
       
   585     struct pam_message      *m;
       
   586     struct pam_response     *r;
       
   587 
       
   588     *response = calloc(num_msg, sizeof (struct pam_response));
       
   589     if (*response == NULL)
       
   590 	return (PAM_BUF_ERR);
       
   591 
       
   592     m = *msg;
       
   593     r = *response;
       
   594 
       
   595     for (i = 0; i < num_msg; i++ , m++ , r++) {
       
   596 #ifdef DEBUG
       
   597 	if (verbose) {
       
   598 	    fprintf(stderr, "pam_msg: %d: '%s'\n", m->msg_style, m->msg);
       
   599 	}
       
   600 #endif
       
   601 	switch (m->msg_style) {
       
   602 	  case PAM_ERROR_MSG:
       
   603 	  case PAM_TEXT_INFO:
       
   604 	    displayTextInfo(m->msg);
       
   605 	    break;
       
   606 
       
   607           case PAM_PROMPT_ECHO_ON:
       
   608 	    reallyechokeys = True; 
       
   609 	    /* FALLTHRU */
       
   610           case PAM_PROMPT_ECHO_OFF:
       
   611 	    passwordPrompt(m->msg);
       
   612 	    if (ReadXString(buffer, PAM_MAX_RESP_SIZE)) {
       
   613 		/* timeout or other error */
       
   614 		status = PAM_CONV_ERR;
       
   615 		i = num_msg;
       
   616 	    } else {
       
   617 		r->resp = strdup(buffer);
       
   618 		if (r->resp == NULL) {
       
   619 		    status = PAM_BUF_ERR;
       
   620 		    i = num_msg;
       
   621 		}
       
   622 #ifdef DEBUG
       
   623 		if (verbose) {
       
   624 		    fprintf(stderr, "pam_resp: '%s'\n", r->resp);
       
   625 		}
       
   626 #endif
       
   627 	    }
       
   628 	    reallyechokeys = False;
       
   629 	    break;
       
   630 
       
   631 	  default:
       
   632 	    if (verbose) {
       
   633 		fprintf(stderr, "%s: Unknown PAM msg_style: %d\n",
       
   634 		  ProgramName, m->msg_style);
       
   635 	    }
       
   636 	}
       
   637     }
       
   638     if (status != PAM_SUCCESS) {
       
   639 	/* free responses */
       
   640 	r = *response;
       
   641 	for (i = 0; i < num_msg; i++, r++) {
       
   642 	    if (r->resp)
       
   643 		free(r->resp);
       
   644 	}
       
   645 	free(*response);
       
   646 	*response = NULL;
       
   647     }
       
   648     return status;
       
   649 }
       
   650 #endif
       
   651 
       
   652 #ifdef	sun
       
   653 #include <syslog.h>
       
   654 #include <bsm/adt.h>
       
   655 #include <bsm/adt_event.h>
       
   656 
       
   657 
       
   658 /*
       
   659  * audit_lock - audit entry to screenlock
       
   660  *
       
   661  *	Entry	Process running with appropriate privilege to generate
       
   662  *			audit records and real uid of the user.
       
   663  *
       
   664  *	Exit	ADT_screenlock audit record written.
       
   665  */
       
   666 static void
       
   667 audit_lock(void)
       
   668 {
       
   669 	adt_session_data_t	*ah;	/* audit session handle */
       
   670 	adt_event_data_t	*event;	/* audit event handle */
       
   671  
       
   672 	/* Audit start of screen lock -- equivalent to logout ;-) */
       
   673 	
       
   674 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
       
   675 
       
   676 		syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m");
       
   677 		return;
       
   678 	}
       
   679 	if ((event = adt_alloc_event(ah, ADT_screenlock)) == NULL) {
       
   680 	
       
   681 		syslog(LOG_AUTH | LOG_ALERT,
       
   682 		    "adt_alloc_event(ADT_screenlock): %m");
       
   683 	} else {
       
   684 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
       
   685 
       
   686 			syslog(LOG_AUTH | LOG_ALERT,
       
   687 			    "adt_put_event(ADT_screenlock): %m");
       
   688 		}
       
   689 		adt_free_event(event);
       
   690 	}
       
   691 	(void) adt_end_session(ah);
       
   692 }
       
   693 
       
   694 
       
   695 /*
       
   696  * audit_unlock - audit screen unlock
       
   697  *
       
   698  *	Entry	Process running with appropriate privilege to generate
       
   699  *			audit records and real uid of the user.
       
   700  *		pam_status = PAM error code; reason for failure.
       
   701  *
       
   702  *	Exit	ADT_screenunlock audit record written.
       
   703  */
       
   704 static void
       
   705 audit_unlock(int pam_status)
       
   706 {
       
   707 	adt_session_data_t	*ah;	/* audit session handle */
       
   708 	adt_event_data_t	*event;	/* audit event handle */
       
   709 
       
   710 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
       
   711 
       
   712 		syslog(LOG_AUTH | LOG_ALERT,
       
   713 		    "adt_start_session(ADT_screenunlock): %m");
       
   714 		return;
       
   715 	}
       
   716 	if ((event = adt_alloc_event(ah, ADT_screenunlock)) == NULL) {
       
   717 	
       
   718 		syslog(LOG_AUTH | LOG_ALERT,
       
   719 		    "adt_alloc_event(ADT_screenunlock): %m");
       
   720 	} else {
       
   721 		if (adt_put_event(event,
       
   722 		    pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
       
   723 		    pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM +
       
   724 		    pam_status) != 0) {
       
   725 
       
   726 			syslog(LOG_AUTH | LOG_ALERT,
       
   727 			    "adt_put_event(ADT_screenunlock(%s): %m",
       
   728 			    pam_strerror(NULL, pam_status));
       
   729 		}
       
   730 		adt_free_event(event);
       
   731 	}
       
   732 	(void) adt_end_session(ah);
       
   733 }
       
   734 
       
   735 
       
   736 /*
       
   737  * audit_passwd - audit password change
       
   738  *	Entry	Process running with appropriate privilege to generate
       
   739  *			audit records and real uid of the user.
       
   740  *		pam_status = PAM error code; reason for failure.
       
   741  *
       
   742  *	Exit	ADT_passwd audit record written.
       
   743  */
       
   744 static void
       
   745 audit_passwd(int pam_status)
       
   746 {
       
   747 	adt_session_data_t	*ah;	/* audit session handle */
       
   748 	adt_event_data_t	*event;	/* audit event handle */
       
   749 
       
   750 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
       
   751 
       
   752 		syslog(LOG_AUTH | LOG_ALERT,
       
   753 		    "adt_start_session(ADT_passwd): %m");
       
   754 		return;
       
   755 	}
       
   756 	if ((event = adt_alloc_event(ah, ADT_passwd)) == NULL) {
       
   757 	
       
   758 		syslog(LOG_AUTH | LOG_ALERT,
       
   759 		    "adt_alloc_event(ADT_passwd): %m");
       
   760 	} else {
       
   761 		if (adt_put_event(event,
       
   762 		    pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
       
   763 		    pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM +
       
   764 		    pam_status) != 0) {
       
   765 
       
   766 			syslog(LOG_AUTH | LOG_ALERT,
       
   767 			    "adt_put_event(ADT_passwd(%s): %m",
       
   768 			    pam_strerror(NULL, pam_status));
       
   769 		}
       
   770 		adt_free_event(event);
       
   771 	}
       
   772 	(void) adt_end_session(ah);
       
   773 }
       
   774 #endif	/* sun */
       
   775 
       
   776 static int
       
   777 getPassword()
       
   778 {
       
   779     char       *userpass = NULL;
       
   780     char       *rootpass = NULL;
       
   781     XWindowAttributes xgwa;
       
   782     int         y, left, done;
       
   783 #ifdef SYSV
       
   784     struct spwd *rspw, *uspw;
       
   785     char       *suserpass = NULL;
       
   786     char       *srootpass = NULL;
       
   787     char       *user;
       
   788 #else
       
   789     char       *user = getenv("USER");
       
   790 #endif /* SYSV */
       
   791     struct passwd *rpw, *upw;
       
   792 #ifdef USE_PAM
       
   793     pam_handle_t *pamh = NULL;
       
   794     struct pam_conv pc;
       
   795     Bool	use_pam = True;
       
   796     int		pam_error;
       
   797     int		pam_flags = 0;
       
   798 #endif
       
   799     const char *authErrMsg = text_invalid;  
       
   800 
       
   801 #ifdef SYSV
       
   802     rpw = getpwuid(0);
       
   803     if (rpw) {
       
   804        user = rpw->pw_name;
       
   805        rootpass = strdup(rpw->pw_passwd);
       
   806 
       
   807        rspw = getspnam(user);
       
   808        if (rspw && rspw->sp_pwdp)
       
   809 	   srootpass = strdup(rspw->sp_pwdp);
       
   810     }
       
   811 
       
   812     upw = getpwuid(getuid());
       
   813     if (upw) {
       
   814        user = upw->pw_name;
       
   815        userpass = strdup(upw->pw_passwd);
       
   816 
       
   817        uspw = getspnam(user);
       
   818        if (uspw && uspw->sp_pwdp)
       
   819 	   suserpass = strdup(uspw->sp_pwdp);
       
   820     }
       
   821     else 
       
   822        user = "";
       
   823 #else
       
   824     rpw = (struct passwd *)getpwuid(0);
       
   825     if (rpw)
       
   826        rootpass = strdup(rpw->pw_passwd);
       
   827  
       
   828     upw = (struct passwd *)getpwuid(getuid());
       
   829     if (upw)
       
   830        userpass = strdup(upw->pw_passwd);
       
   831 #endif /* SYSV */
       
   832 
       
   833 #ifdef USE_PAM
       
   834     pc.conv = pamconv;
       
   835     
       
   836     pam_error = pam_start(XLOCK_PAM_SERVICE, user, &pc, &pamh);
       
   837     if (pam_error != PAM_SUCCESS) {
       
   838 	use_pam = False;
       
   839 	PAM_ERROR_PRINT("pam_start");
       
   840     } else {
       
   841 #ifdef sun
       
   842 	/* Check /etc/default/login to see if we should add
       
   843 	   PAM_DISALLOW_NULL_AUTHTOK to pam_flags */
       
   844 	if (defopen("/etc/default/login") == 0) {
       
   845 	    char *ptr;
       
   846 
       
   847 	    int flags = defcntl(DC_GETFLAGS, 0);
       
   848 	    TURNOFF(flags, DC_CASE);
       
   849 	    (void) defcntl(DC_SETFLAGS, flags);
       
   850 
       
   851 	    if ((ptr = defread("PASSREQ=")) != NULL &&
       
   852 	      strcasecmp("YES", ptr) == 0) {
       
   853 		pam_flags |= PAM_DISALLOW_NULL_AUTHTOK;
       
   854 	    }
       
   855 
       
   856 	    (void) defopen((char *)NULL); /* close current file */
       
   857 	}
       
   858 
       
   859 #endif
       
   860 #ifdef SYSV
       
   861 	/* Disable user password non-PAM authentication */
       
   862 	if (userpass) {
       
   863 	    memset(userpass, 0, strlen(userpass));
       
   864 	    free(userpass);
       
   865 	    userpass = NULL;
       
   866 	}
       
   867 	if (suserpass) {
       
   868 	    memset(suserpass, 0, strlen(suserpass));
       
   869 	    free(suserpass);
       
   870 	    suserpass = NULL;
       
   871 	}
       
   872 #endif
       
   873     }
       
   874 #endif /* USE_PAM */
       
   875 
       
   876     XGetWindowAttributes(dsp, win[screen], &xgwa);
       
   877 
       
   878     XChangeGrabbedCursor(passwdcursor);
       
   879 
       
   880     XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
       
   881     XFillRectangle(dsp, win[screen], Scr[screen].gc,
       
   882 		   0, 0, xgwa.width, xgwa.height);
       
   883 
       
   884     XMapWindow(dsp, icon[screen]);
       
   885     XRaiseWindow(dsp, icon[screen]);
       
   886 
       
   887     left = iconx[screen] + ICONW + font->max_bounds.width;
       
   888     y = icony[screen] + font->ascent;
       
   889 
       
   890     XDrawString(dsp, win[screen], textgc[screen],
       
   891 		left, y, text_name, strlen(text_name));
       
   892     XDrawString(dsp, win[screen], textgc[screen],
       
   893 		left + 1, y, text_name, strlen(text_name));
       
   894     XDrawString(dsp, win[screen], textgc[screen],
       
   895 		left + XTextWidth(font, text_name, strlen(text_name)), y,
       
   896 		user, strlen(user));
       
   897 
       
   898     y = icony[screen] - (font->descent + 2);
       
   899 
       
   900     XDrawString(dsp, win[screen], textgc[screen],
       
   901 		iconx[screen], y, text_info, strlen(text_info));
       
   902 
       
   903     passwordPrompt(text_pass);
       
   904 
       
   905     XFlush(dsp);
       
   906 
       
   907     y = icony[screen] + ICONH + font->ascent + 2
       
   908       + font->ascent + font->descent + 2;
       
   909 
       
   910     done = False;
       
   911     stoptryingfornow = False;
       
   912     while (!done) {
       
   913 #ifdef USE_PAM
       
   914 	if (use_pam) {
       
   915 
       
   916 	    pam_error = pam_authenticate(pamh, pam_flags);
       
   917 	    if (pam_error == PAM_SUCCESS) {
       
   918 		const char *pam_error_from = "pam_acct_mgmt";
       
   919 
       
   920 		pam_error = pam_acct_mgmt(pamh, pam_flags);
       
   921 
       
   922 		if (pam_error == PAM_NEW_AUTHTOK_REQD) {
       
   923 		    do {
       
   924 			pam_error = pam_chauthtok(pamh,
       
   925 						  PAM_CHANGE_EXPIRED_AUTHTOK);
       
   926 		    } while (pam_error == PAM_AUTHTOK_ERR || 
       
   927 		      pam_error == PAM_TRY_AGAIN);
       
   928 		    pam_error_from = "pam_chauthtok";
       
   929 #ifdef	sun
       
   930 		    audit_passwd(pam_error);
       
   931 #endif	/* sun */
       
   932 		}
       
   933 
       
   934 		if (pam_error == PAM_SUCCESS) {
       
   935 		    pam_error = pam_setcred(pamh,PAM_REFRESH_CRED);  
       
   936 		    if (pam_error != PAM_SUCCESS) {
       
   937 			PAM_ERROR_PRINT("pam_setcred(PAM_REFRESH_CRED)");
       
   938 		    } else {
       
   939 			done = True;
       
   940 		    }
       
   941 		} else {
       
   942 #ifdef	sun
       
   943     		    audit_unlock(pam_error);
       
   944 #endif	/* sun */
       
   945 		    PAM_ERROR_PRINT(pam_error_from);
       
   946 		}
       
   947 	    } else if (stoptryingfornow) {
       
   948 		break;
       
   949 	    } else {
       
   950 #ifdef	sun
       
   951     		audit_unlock(pam_error);
       
   952 #endif	/* sun */
       
   953 		PAM_ERROR_PRINT("pam_authenticate");
       
   954 	    }
       
   955 
       
   956 	    if (pam_error != PAM_SUCCESS) {
       
   957 		authErrMsg = pam_strerror(pamh, pam_error);
       
   958 	    }
       
   959 	} else 
       
   960 	if (ReadXString(buffer, PAM_MAX_RESP_SIZE))
       
   961 	    break;
       
   962 #endif
       
   963 
       
   964 	/*
       
   965 	 *  This section gets a little messy.  In SYSV, the number of
       
   966 	 *  cases to handle increases because of the existence of the
       
   967 	 *  shadow file.  There are also a number of cases that need
       
   968 	 *  to be dealt with where either root or user passwords are
       
   969 	 *  nil.  Hopefully the code below is easy enough to follow.
       
   970 	 */
       
   971 
       
   972 #ifdef SYSV
       
   973 	if (userpass) {
       
   974 	    if (*userpass == NULL) {
       
   975 		done = (*buffer == NULL);
       
   976 	    } else {
       
   977 		done = (!strcmp(crypt(buffer, userpass), userpass));
       
   978 	    }
       
   979 	}
       
   980 	if (!done && suserpass) {
       
   981 	    if (*suserpass == NULL) {
       
   982 		done = (*buffer == NULL);
       
   983 	    } else {
       
   984 		done = (!strcmp(crypt(buffer, suserpass), suserpass));
       
   985 	    }
       
   986 	}
       
   987 	if (!done && allowroot) {
       
   988 	    if (srootpass) {
       
   989 		if (*srootpass == NULL) {
       
   990 		    done = (*buffer == NULL);
       
   991 		} else {
       
   992 		    done = (!strcmp(crypt(buffer, srootpass), srootpass));
       
   993 		}
       
   994 	    }
       
   995 	    if (!done && rootpass) {
       
   996 		if (*rootpass == NULL) {
       
   997 		    done = (*buffer == NULL);
       
   998 		} else {
       
   999 		    done = (!strcmp(crypt(buffer, rootpass), rootpass));
       
  1000 		}
       
  1001 	    }
       
  1002         }
       
  1003 #else
       
  1004 	done = !((strcmp(crypt(buffer, userpass), userpass))
       
  1005 	       && (!allowroot || strcmp(crypt(buffer, rootpass), rootpass)));
       
  1006 
       
  1007 	if (!done && *buffer == NULL) {
       
  1008 	    /* just hit return, and it wasn't his password */
       
  1009 	    break;
       
  1010 	}
       
  1011 	if (*userpass == NULL && *buffer != NULL) {
       
  1012 	    /*
       
  1013 	     * the user has no password, but something was typed anyway.
       
  1014 	     * sounds fishy: don't let him in...
       
  1015 	     */
       
  1016 	    done = False;
       
  1017 	}
       
  1018 #endif /* SYSV */
       
  1019 
       
  1020 	/* clear plaintext password so you can't grunge around /dev/kmem */
       
  1021 	memset(buffer, 0, sizeof(buffer));
       
  1022 
       
  1023 	displayTextInfo(text_valid);
       
  1024 
       
  1025 	if (done) {
       
  1026 	    /* clear encrypted passwords just in case */
       
  1027 	    if (rootpass) {
       
  1028 		memset(rootpass, 0, strlen(rootpass));
       
  1029 		free(rootpass);  
       
  1030 	    }
       
  1031 	    if (userpass) {
       
  1032 		memset(userpass, 0, strlen(userpass));
       
  1033 		free(userpass);
       
  1034 	    }
       
  1035 #ifdef SYSV
       
  1036 	    if (srootpass) {
       
  1037 		memset(srootpass, 0, strlen(srootpass));
       
  1038 		free(srootpass);  
       
  1039 	    }
       
  1040 	    if (suserpass) {
       
  1041 		memset(suserpass, 0, strlen(suserpass));
       
  1042 		free(suserpass);
       
  1043 	    }
       
  1044 #endif
       
  1045 #ifdef USE_PAM
       
  1046 #ifdef	sun
       
  1047 	    audit_unlock(pam_error);
       
  1048 #endif	/* sun */
       
  1049 	    pam_end(pamh, pam_error);
       
  1050 #endif
       
  1051 	    return 0;
       
  1052 	} else {
       
  1053 	    XSync(dsp, True);	/* flush input buffer */
       
  1054 	    sleep(1);
       
  1055 	    
       
  1056 	    displayTextInfo(authErrMsg);
       
  1057 
       
  1058 	    if (echokeys || reallyechokeys)	/* erase old echo */
       
  1059 		XFillRectangle(dsp, win[screen], Scr[screen].gc,
       
  1060 			       passx, passy - font->ascent,
       
  1061 			       xgwa.width - passx,
       
  1062 			       font->ascent + font->descent);
       
  1063 	}
       
  1064     }
       
  1065     /* clear encrypted passwords just in case */
       
  1066     if (rootpass) {
       
  1067 	memset(rootpass, 0, strlen(rootpass));
       
  1068 	free(rootpass);  
       
  1069     }
       
  1070     if (userpass) {
       
  1071 	memset(userpass, 0, strlen(userpass));
       
  1072 	free(userpass);
       
  1073     }
       
  1074 #ifdef SYSV
       
  1075     if (srootpass) {
       
  1076 	memset(srootpass, 0, strlen(srootpass));
       
  1077 	free(srootpass);  
       
  1078     }
       
  1079     if (suserpass) {
       
  1080 	memset(suserpass, 0, strlen(suserpass));
       
  1081 	free(suserpass);
       
  1082     }
       
  1083 #endif
       
  1084 #ifdef USE_PAM
       
  1085     pam_end(pamh, pam_error);
       
  1086 #endif
       
  1087     XChangeGrabbedCursor(mycursor);
       
  1088     XUnmapWindow(dsp, icon[screen]);
       
  1089     return 1;
       
  1090 }
       
  1091 
       
  1092 
       
  1093 static void
       
  1094 justDisplay()
       
  1095 {
       
  1096     XEvent      event;
       
  1097 
       
  1098     for (screen = 0; screen < screens; screen++)
       
  1099 	init(win[screen]);
       
  1100     do {
       
  1101 	while (!XPending(dsp)) {
       
  1102 	    for (screen = 0; screen < screens; screen++)
       
  1103 		callback(win[screen]);
       
  1104 	    XFlush(dsp);
       
  1105 	    usleep(delay);
       
  1106 	}
       
  1107 	XNextEvent(dsp, &event);
       
  1108 #ifndef DEBUG
       
  1109 	if (event.type == VisibilityNotify)
       
  1110 	    XRaiseWindow(dsp, event.xany.window);
       
  1111 #endif
       
  1112     } while (event.type != ButtonPress && event.type != KeyPress);
       
  1113     for (screen = 0; screen < screens; screen++)
       
  1114 	if (event.xbutton.root == RootWindow(dsp, screen))
       
  1115 	    break;
       
  1116     if (usefirst)
       
  1117 	XPutBackEvent(dsp, &event);
       
  1118 }
       
  1119 
       
  1120 
       
  1121 static void
       
  1122 sigcatch()
       
  1123 {
       
  1124     finish();
       
  1125     error("%s: caught terminate signal.\nAccess control list restored.\n",(char*)NULL);
       
  1126 }
       
  1127 
       
  1128 
       
  1129 static void
       
  1130 lockDisplay()
       
  1131 {
       
  1132     if (!allowaccess) {
       
  1133 #ifdef SYSV
       
  1134 	sigset_t    oldsigmask;
       
  1135 	sigset_t    newsigmask;
       
  1136 
       
  1137 	sigemptyset(&newsigmask);
       
  1138 	sigaddset(&newsigmask, SIGHUP);
       
  1139 	sigaddset(&newsigmask, SIGINT);
       
  1140 	sigaddset(&newsigmask, SIGQUIT);
       
  1141 	sigaddset(&newsigmask, SIGTERM);
       
  1142 	sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);
       
  1143 #else
       
  1144 	int         oldsigmask;
       
  1145 
       
  1146 	oldsigmask = sigblock(sigmask(SIGHUP) |
       
  1147 			      sigmask(SIGINT) |
       
  1148 			      sigmask(SIGQUIT) |
       
  1149 			      sigmask(SIGTERM));
       
  1150 #endif
       
  1151 
       
  1152 	signal(SIGHUP, (void (*)()) sigcatch);
       
  1153 	signal(SIGINT, (void (*)()) sigcatch);
       
  1154 	signal(SIGQUIT, (void (*)()) sigcatch);
       
  1155 	signal(SIGTERM, (void (*)()) sigcatch);
       
  1156 
       
  1157 	XGrabHosts(dsp);
       
  1158 
       
  1159 #ifdef SYSV
       
  1160 	sigprocmask(SIG_SETMASK, &oldsigmask, &oldsigmask);
       
  1161 #else
       
  1162 	sigsetmask(oldsigmask);
       
  1163 #endif
       
  1164     }
       
  1165 #ifdef	sun
       
  1166 	audit_lock();
       
  1167 #endif	/* sun */
       
  1168     do {
       
  1169 	justDisplay();
       
  1170     } while (getPassword());
       
  1171 }
       
  1172 
       
  1173 
       
  1174 int
       
  1175 main(argc, argv)
       
  1176     int         argc;
       
  1177     char       *argv[];
       
  1178 {
       
  1179     XSetWindowAttributes xswa;
       
  1180     XGCValues   xgcv;
       
  1181 
       
  1182     ProgramName = strrchr(argv[0], '/');
       
  1183     if (ProgramName)
       
  1184 	ProgramName++;
       
  1185     else
       
  1186 	ProgramName = argv[0];
       
  1187 
       
  1188     srandom(time((long *) 0));	/* random mode needs the seed set. */
       
  1189 
       
  1190     GetResources(argc, argv);
       
  1191 
       
  1192     CheckResources();
       
  1193 
       
  1194     font = XLoadQueryFont(dsp, fontname);
       
  1195     if (font == NULL) {
       
  1196 	fprintf(stderr, "%s: can't find font: %s, using %s...\n",
       
  1197 		ProgramName, fontname, FALLBACK_FONTNAME);
       
  1198 	font = XLoadQueryFont(dsp, FALLBACK_FONTNAME);
       
  1199 	if (font == NULL)
       
  1200 	    error("%s: can't even find %s!!!\n", FALLBACK_FONTNAME);
       
  1201     }
       
  1202 
       
  1203     if (CheckPassword()) {
       
  1204 	fprintf(stderr, "%s: can't get the user password. Exiting ...\n", 
       
  1205 		ProgramName);
       
  1206 
       
  1207 	fprintf(stderr,"\tYou need to run xlock in setuid root mode on your local machine.\n");
       
  1208 	error("\tContact your system administrator.\n", (char *) NULL);
       
  1209     }
       
  1210 	
       
  1211     screens = ScreenCount(dsp);
       
  1212     if (screens > MAXSCREENS)
       
  1213 	error("%s: can only support %d screens.\n", MAXSCREENS);
       
  1214     for (screen = 0; screen < screens; screen++) {
       
  1215 	XColor      tmp;
       
  1216 	Screen     *scr = ScreenOfDisplay(dsp, screen);
       
  1217 	Visual 	    *vis = XDefaultVisual(dsp, screen);
       
  1218 	Colormap    cmap;
       
  1219 	root[screen] = RootWindowOfScreen(scr);
       
  1220 
       
  1221 	cmap = XCreateColormap(dsp, root[screen], vis, AllocNone);
       
  1222 
       
  1223 	XAllocNamedColor(dsp, cmap, "White", &sswhite[screen], &tmp);
       
  1224 	XAllocNamedColor(dsp, cmap, "Black", &ssblack[screen], &tmp);
       
  1225 
       
  1226 	if (mono || CellsOfScreen(scr) == 2) {
       
  1227  	    if (!XAllocNamedColor(dsp, cmap, background,
       
  1228  				  &bgcol[screen], &tmp)) {
       
  1229  		XAllocNamedColor(dsp, cmap, "White", &bgcol[screen], &tmp);
       
  1230  	    }
       
  1231  	    if (!XAllocNamedColor(dsp, cmap, foreground,
       
  1232  				  &fgcol[screen], &tmp)) {
       
  1233  		XAllocNamedColor(dsp, cmap, "Black", &fgcol[screen], &tmp);
       
  1234  	    }
       
  1235 	    Scr[screen].pixels[0] = fgcol[screen].pixel;
       
  1236 	    Scr[screen].pixels[1] = bgcol[screen].pixel;
       
  1237 	    Scr[screen].npixels = 2;
       
  1238 	} else {
       
  1239 	    int         colorcount = NUMCOLORS;
       
  1240 	    u_char      red[NUMCOLORS];
       
  1241 	    u_char      green[NUMCOLORS];
       
  1242 	    u_char      blue[NUMCOLORS];
       
  1243 	    int         i;
       
  1244 
       
  1245 	    if (!XAllocNamedColor(dsp, cmap, background,
       
  1246 				  &bgcol[screen], &tmp)) {
       
  1247 		fprintf(stderr, "couldn't allocate: %s\n", background);
       
  1248 		XAllocNamedColor(dsp, cmap, "White", &bgcol[screen], &tmp);
       
  1249 	    }
       
  1250 	    if (!XAllocNamedColor(dsp, cmap, foreground,
       
  1251 				  &fgcol[screen], &tmp)) {
       
  1252 		fprintf(stderr, "couldn't allocate: %s\n", foreground);
       
  1253 		XAllocNamedColor(dsp, cmap, "Black", &fgcol[screen], &tmp);
       
  1254 	    }
       
  1255 	    hsbramp(0.0, saturation, 1.0, 1.0, saturation, 1.0, colorcount,
       
  1256 		    red, green, blue);
       
  1257 	    Scr[screen].npixels = 0;
       
  1258 	    for (i = 0; i < colorcount; i++) {
       
  1259 		XColor      xcolor;
       
  1260 
       
  1261 		xcolor.red = red[i] << 8;
       
  1262 		xcolor.green = green[i] << 8;
       
  1263 		xcolor.blue = blue[i] << 8;
       
  1264 		xcolor.flags = DoRed | DoGreen | DoBlue;
       
  1265 
       
  1266 		if (!XAllocColor(dsp, cmap, &xcolor))
       
  1267 		    break;
       
  1268 
       
  1269 		Scr[screen].pixels[i] = xcolor.pixel;
       
  1270 		Scr[screen].npixels++;
       
  1271 	    }
       
  1272 	    if (verbose)
       
  1273 		fprintf(stderr, "%d pixels allocated\n", Scr[screen].npixels);
       
  1274 	}
       
  1275 
       
  1276 	xswa.override_redirect = True;
       
  1277 	xswa.background_pixel = ssblack[screen].pixel;
       
  1278 	xswa.event_mask = KeyPressMask | ButtonPressMask | VisibilityChangeMask;
       
  1279 	xswa.colormap = cmap;		/* In DEBUG mode, we do not see this */
       
  1280 
       
  1281 	win[screen] = XCreateWindow(dsp, root[screen], 0, 0, WIDTH, HEIGHT, 0,
       
  1282 				 CopyFromParent, InputOutput, CopyFromParent,
       
  1283 				    CWMASK, &xswa);
       
  1284 
       
  1285 #ifdef DEBUG
       
  1286 	{
       
  1287 	    XWMHints    xwmh;
       
  1288 
       
  1289 	    xwmh.flags = InputHint;
       
  1290 	    xwmh.input = True;
       
  1291 	    XChangeProperty(dsp, win[screen],
       
  1292 			    XA_WM_HINTS, XA_WM_HINTS, 32, PropModeReplace,
       
  1293 			(unsigned char *) &xwmh, sizeof(xwmh) / sizeof(int));
       
  1294 	}
       
  1295 #endif
       
  1296 	
       
  1297   	iconx[screen] = (DisplayWidth(dsp, screen) -
       
  1298   			 XTextWidth(font, text_info, strlen(text_info))) / 2;
       
  1299 	
       
  1300   	icony[screen] = DisplayHeight(dsp, screen) / 6;
       
  1301 	
       
  1302  	xswa.border_pixel = fgcol[screen].pixel;
       
  1303  	xswa.background_pixel = bgcol[screen].pixel;
       
  1304  	xswa.event_mask = ButtonPressMask;
       
  1305 	xswa.colormap = cmap;		/* In DEBUG mode, we do not see this */
       
  1306 
       
  1307 #define CIMASK CWBorderPixel | CWBackPixel | CWEventMask | CWColormap
       
  1308   	icon[screen] = XCreateWindow(dsp, win[screen],
       
  1309   				     iconx[screen], icony[screen],
       
  1310  				     ICONW, ICONH, 1, CopyFromParent,
       
  1311   				     InputOutput, CopyFromParent,
       
  1312  				     CIMASK, &xswa);
       
  1313   
       
  1314 	XMapWindow(dsp, win[screen]);
       
  1315 	XRaiseWindow(dsp, win[screen]);
       
  1316 	XInstallColormap(dsp, cmap);
       
  1317 
       
  1318 	xgcv.foreground = sswhite[screen].pixel;
       
  1319 	xgcv.background = ssblack[screen].pixel;
       
  1320 	Scr[screen].gc = XCreateGC(dsp, win[screen],
       
  1321 				   GCForeground | GCBackground, &xgcv);
       
  1322 
       
  1323 	xgcv.foreground = fgcol[screen].pixel;
       
  1324 	xgcv.background = bgcol[screen].pixel;
       
  1325 	xgcv.font = font->fid;
       
  1326 	textgc[screen] = XCreateGC(dsp, win[screen],
       
  1327 				GCFont | GCForeground | GCBackground, &xgcv);
       
  1328     }
       
  1329     lockc = XCreateBitmapFromData(dsp, root[0], no_bits, 1, 1);
       
  1330     lockm = XCreateBitmapFromData(dsp, root[0], no_bits, 1, 1);
       
  1331     mycursor = XCreatePixmapCursor(dsp, lockc, lockm,
       
  1332 				   &fgcol[screen], &bgcol[screen], 0, 0);
       
  1333     passwdcursor = XCreateFontCursor(dsp, XC_left_ptr);
       
  1334     XFreePixmap(dsp, lockc);
       
  1335     XFreePixmap(dsp, lockm);
       
  1336 
       
  1337 
       
  1338     if (!enablesaver) {
       
  1339 	XGetScreenSaver(dsp, &sstimeout, &ssinterval,
       
  1340 			&ssblanking, &ssexposures);
       
  1341 	XSetScreenSaver(dsp, 0, 0, 0, 0);	/* disable screen saver */
       
  1342     }
       
  1343 #ifndef DEBUG
       
  1344     GrabKeyboardAndMouse();
       
  1345 #endif
       
  1346 
       
  1347     nice(nicelevel);
       
  1348 
       
  1349     if (nolock)
       
  1350 	justDisplay();
       
  1351     else
       
  1352 	lockDisplay();
       
  1353 
       
  1354     finish();
       
  1355 
       
  1356     return 0;
       
  1357 }