546N/A/*
1233N/A * Copyright (c) 1988, 2011, Oracle and/or its affiliates. All rights reserved.
546N/A *
546N/A * Permission is hereby granted, free of charge, to any person obtaining a
919N/A * copy of this software and associated documentation files (the "Software"),
919N/A * to deal in the Software without restriction, including without limitation
919N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
919N/A * and/or sell copies of the Software, and to permit persons to whom the
919N/A * Software is furnished to do so, subject to the following conditions:
546N/A *
919N/A * The above copyright notice and this permission notice (including the next
919N/A * paragraph) shall be included in all copies or substantial portions of the
919N/A * Software.
546N/A *
919N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
919N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
919N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
919N/A * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
919N/A * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
919N/A * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
919N/A * DEALINGS IN THE SOFTWARE.
546N/A */
546N/A/*
546N/A * xlock.c - X11 client to lock a display and show a screen saver.
546N/A *
546N/A * Copyright (c) 1988-91 by Patrick J. Naughton.
546N/A *
546N/A * Permission to use, copy, modify, and distribute this software and its
546N/A * documentation for any purpose and without fee is hereby granted,
546N/A * provided that the above copyright notice appear in all copies and that
546N/A * both that copyright notice and this permission notice appear in
546N/A * supporting documentation.
546N/A *
546N/A * This file is provided AS IS with no warranties of any kind. The author
546N/A * shall have no liability with respect to the infringement of copyrights,
546N/A * trade secrets or any patents by this file or any part thereof. In no
546N/A * event will the author be liable for any lost revenue or profits or
546N/A * other special, indirect and consequential damages.
546N/A *
546N/A * Comments and additions should be sent to the author:
546N/A *
546N/A * naughton@eng.sun.com
546N/A *
546N/A * Patrick J. Naughton
546N/A * MS 10-20
546N/A * Sun Laboritories, Inc.
546N/A * 2550 Garcia Ave
546N/A * Mountain View, CA 94043
546N/A *
546N/A * Revision History:
546N/A *
546N/A * 24-Jun-91: make foreground and background color get used on mono.
546N/A * 24-May-91: added -usefirst.
546N/A * 16-May-91: added pyro and random modes.
546N/A * ripped big comment block out of all other files.
546N/A * 08-Jan-91: fix some problems with password entry.
546N/A * removed renicing code.
546N/A * 29-Oct-90: added cast to XFree() arg.
546N/A * added volume arg to call to XBell().
546N/A * 28-Oct-90: center prompt screen.
546N/A * make sure Xlib input buffer does not use up all of swap.
546N/A * make displayed text come from resource file for better I18N.
546N/A * add backward compatible signal handlers for pre 4.1 machines.
546N/A * 31-Aug-90: added blank mode.
546N/A * added swarm mode.
546N/A * moved usleep() and seconds() out to usleep.c.
546N/A * added SVR4 defines to xlock.h
546N/A * 29-Jul-90: added support for multiple screens to be locked by one xlock.
546N/A * moved global defines to xlock.h
546N/A * removed use of allowsig().
546N/A * 07-Jul-90: reworked commandline args and resources to use Xrm.
546N/A * moved resource processing out to resource.c
546N/A * 02-Jul-90: reworked colors to not use dynamic colormap.
546N/A * 23-May-90: added autoraise when obscured.
546N/A * 15-Apr-90: added hostent alias searching for host authentication.
546N/A * 18-Feb-90: added SunOS3.5 fix.
546N/A * changed -mono -> -color, and -saver -> -lock.
546N/A * allow non-locking screensavers to display on remote machine.
546N/A * added -echokeys to disable echoing of '?'s on input.
546N/A * cleaned up all of the parameters and defaults.
546N/A * 20-Dec-89: added -xhost to allow access control list to be left alone.
546N/A * added -screensaver (don't disable screen saver) for the paranoid.
546N/A * Moved seconds() here from all of the display mode source files.
546N/A * Fixed bug with calling XUngrabHosts() in finish().
546N/A * 19-Dec-89: Fixed bug in GrabPointer.
546N/A * Changed fontname to XLFD style.
546N/A * 23-Sep-89: Added fix to allow local hostname:0 as a display.
546N/A * Put empty case for Enter/Leave events.
546N/A * Moved colormap installation later in startup.
546N/A * 20-Sep-89: Linted and made -saver mode grab the keyboard and mouse.
546N/A * Replaced SunView code for life mode with Jim Graham's version,
546N/A * so I could contrib it without legal problems.
546N/A * Sent to expo for X11R4 contrib.
546N/A * 19-Sep-89: Added '?'s on input.
546N/A * 27-Mar-89: Added -qix mode.
546N/A * Fixed GContext->GC.
546N/A * 20-Mar-89: Added backup font (fixed) if XQueryLoadFont() fails.
546N/A * Changed default font to lucida-sans-24.
546N/A * 08-Mar-89: Added -nice, -mode and -display, built vector for life and hop.
546N/A * 24-Feb-89: Replaced hopalong display with life display from SunView1.
546N/A * 22-Feb-89: Added fix for color servers with n < 8 planes.
546N/A * 16-Feb-89: Updated calling conventions for XCreateHsbColormap();
546N/A * Added -count for number of iterations per color.
546N/A * Fixed defaulting mechanism.
546N/A * Ripped out VMS hacks.
546N/A * Sent to expo for X11R3 contrib.
546N/A * 15-Feb-89: Changed default font to pellucida-sans-18.
546N/A * 20-Jan-89: Added -verbose and fixed usage message.
546N/A * 19-Jan-89: Fixed monochrome gc bug.
546N/A * 16-Dec-88: Added SunView style password prompting.
546N/A * 19-Sep-88: Changed -color to -mono. (default is color on color displays).
546N/A * Added -saver option. (just do display... don't lock.)
546N/A * 31-Aug-88: Added -time option.
546N/A * Removed code for fractals to separate file for modularity.
546N/A * Added signal handler to restore host access.
546N/A * Installs dynamic colormap with a Hue Ramp.
546N/A * If grabs fail then exit.
546N/A * Added VMS Hacks. (password 'iwiwuu').
546N/A * Sent to expo for X11R2 contrib.
546N/A * 08-Jun-88: Fixed root password pointer problem and changed PASSLENGTH to 20.
546N/A * 20-May-88: Added -root to allow root to unlock.
546N/A * 12-Apr-88: Added root password override.
546N/A * Added screen saver override.
546N/A * Removed XGrabServer/XUngrabServer.
546N/A * Added access control handling instead.
546N/A * 01-Apr-88: Added XGrabServer/XUngrabServer for more security.
546N/A * 30-Mar-88: Removed startup password requirement.
546N/A * Removed cursor to avoid phosphor burn.
546N/A * 27-Mar-88: Rotate fractal by 45 degrees clockwise.
546N/A * 24-Mar-88: Added color support. [-color]
546N/A * wrote the man page.
546N/A * 23-Mar-88: Added HOPALONG routines from Scientific American Sept. 86 p. 14.
546N/A * added password requirement for invokation
546N/A * removed option for command line password
546N/A * added requirement for display to be "unix:0".
546N/A * 22-Mar-88: Recieved Walter Milliken's comp.windows.x posting.
546N/A *
546N/A */
546N/A
546N/A#include <stdio.h>
546N/A#include <signal.h>
546N/A#include <string.h>
1233N/A#include <stdarg.h>
1233N/A#include <crypt.h>
546N/A#ifdef SYSV
546N/A#include <shadow.h>
546N/A#endif
546N/A#include <pwd.h>
546N/A
546N/A#include "xlock.h"
546N/A#include <X11/cursorfont.h>
546N/A#include <X11/Xatom.h>
546N/A
546N/A#ifdef USE_PAM
546N/A# include <security/pam_appl.h>
546N/A# ifndef XLOCK_PAM_SERVICE
546N/A# define XLOCK_PAM_SERVICE "xlock"
546N/A# endif
546N/A# define PAM_ERROR_PRINT(pamfunc) \
546N/A if (verbose) { \
546N/A fprintf(stderr, "%s: %s failure: %s\n", ProgramName, pamfunc, \
546N/A pam_strerror(pamh, pam_error)); \
546N/A }
546N/A# ifdef sun
546N/A# include <deflt.h>
546N/A# endif
546N/A#endif
546N/A
546N/Achar *ProgramName; /* argv[0] */
546N/Aperscreen Scr[MAXSCREENS];
546N/ADisplay *dsp = NULL; /* server display connection */
546N/Aint screen; /* current screen */
546N/Avoid (*callback) () = NULL;
546N/Avoid (*init) () = NULL;
546N/A
546N/Astatic int screens; /* number of screens */
546N/Astatic Window win[MAXSCREENS]; /* window used to cover screen */
546N/Astatic Window icon[MAXSCREENS]; /* window used during password typein */
546N/Astatic Window root[MAXSCREENS]; /* convenience pointer to the root window */
546N/Astatic GC textgc[MAXSCREENS]; /* graphics context used for text rendering */
546N/Astatic XColor fgcol[MAXSCREENS];/* used for text rendering */
546N/Astatic XColor bgcol[MAXSCREENS];/* background of text screen */
546N/AXColor ssblack[MAXSCREENS];/* black color for screen saver screen */
546N/AXColor sswhite[MAXSCREENS];/* white color for screen saver screen */
546N/Astatic int iconx[MAXSCREENS]; /* location of left edge of icon */
546N/Astatic int icony[MAXSCREENS]; /* location of top edge of icon */
546N/Astatic Cursor mycursor; /* blank cursor */
546N/Astatic Cursor passwdcursor; /* cursor used in getPassword */
546N/Astatic Pixmap lockc;
546N/Astatic Pixmap lockm; /* pixmaps for cursor and mask */
546N/Astatic char no_bits[] = {0}; /* dummy array for the blank cursor */
546N/Astatic int passx; /* position of the ?'s */
546N/Astatic int passy;
546N/Astatic XFontStruct *font;
546N/Astatic int sstimeout; /* screen saver parameters */
546N/Astatic int ssinterval;
546N/Astatic int ssblanking;
546N/Astatic int ssexposures;
546N/A
546N/Astatic char buffer[PAM_MAX_RESP_SIZE];
546N/Astatic Bool reallyechokeys = False; /* Echo real keys instead of ?'s */
546N/Astatic Bool stoptryingfornow = False;
546N/A
546N/A#define FALLBACK_FONTNAME "fixed"
546N/A#define ICONW 64
546N/A#define ICONH 64
546N/A
546N/A#ifdef DEBUG
546N/A#define WIDTH WidthOfScreen(scr) - 100
546N/A#define HEIGHT HeightOfScreen(scr) - 100
546N/A#define CWMASK CWBackPixel | CWEventMask | CWColormap
546N/A#else
546N/A#define WIDTH WidthOfScreen(scr)
546N/A#define HEIGHT HeightOfScreen(scr)
546N/A#define CWMASK CWOverrideRedirect | CWBackPixel | CWEventMask | CWColormap
546N/A#endif
546N/A
546N/A#define AllPointerEventMask \
546N/A (ButtonPressMask | ButtonReleaseMask | \
546N/A EnterWindowMask | LeaveWindowMask | \
546N/A PointerMotionMask | PointerMotionHintMask | \
546N/A Button1MotionMask | Button2MotionMask | \
546N/A Button3MotionMask | Button4MotionMask | \
546N/A Button5MotionMask | ButtonMotionMask | \
546N/A KeymapStateMask)
546N/A
546N/Avoid
1233N/Aerror(const char *format, ...)
546N/A{
1233N/A va_list args;
1233N/A
1233N/A fprintf(stderr, "%s: ", ProgramName);
1233N/A va_start(args, format);
1233N/A vfprintf(stderr, format, args);
1233N/A va_end(args);
546N/A exit(1);
546N/A}
546N/A
546N/A/*
546N/A * Server access control support.
546N/A */
546N/A
546N/Astatic XHostAddress *XHosts; /* the list of "friendly" client machines */
546N/Astatic int HostAccessCount; /* the number of machines in XHosts */
546N/Astatic Bool HostAccessState; /* whether or not we even look at the list */
546N/A
546N/Astatic void
546N/AXGrabHosts(dsp)
546N/A Display *dsp;
546N/A{
546N/A XHosts = XListHosts(dsp, &HostAccessCount, &HostAccessState);
546N/A if (XHosts)
546N/A XRemoveHosts(dsp, XHosts, HostAccessCount);
546N/A XEnableAccessControl(dsp);
546N/A}
546N/A
546N/Astatic void
546N/AXUngrabHosts(dsp)
546N/A Display *dsp;
546N/A{
546N/A if (XHosts) {
546N/A XAddHosts(dsp, XHosts, HostAccessCount);
546N/A XFree((char *) XHosts);
546N/A }
546N/A if (HostAccessState == False)
546N/A XDisableAccessControl(dsp);
546N/A}
546N/A
546N/A
546N/A/*
546N/A * Simple wrapper to get an asynchronous grab on the keyboard and mouse.
546N/A * If either grab fails, we sleep for one second and try again since some
546N/A * window manager might have had the mouse grabbed to drive the menu choice
546N/A * that picked "Lock Screen..". If either one fails the second time we print
546N/A * an error message and exit.
546N/A */
546N/Astatic void
546N/AGrabKeyboardAndMouse()
546N/A{
546N/A Status status;
546N/A
546N/A status = XGrabKeyboard(dsp, win[0], True,
546N/A GrabModeAsync, GrabModeAsync, CurrentTime);
546N/A if (status != GrabSuccess) {
546N/A sleep(1);
546N/A status = XGrabKeyboard(dsp, win[0], True,
546N/A GrabModeAsync, GrabModeAsync, CurrentTime);
546N/A
546N/A if (status != GrabSuccess)
1233N/A error("couldn't grab keyboard! (%d)\n", status);
546N/A }
546N/A status = XGrabPointer(dsp, win[0], True, AllPointerEventMask,
546N/A GrabModeAsync, GrabModeAsync, None, mycursor,
546N/A CurrentTime);
546N/A if (status != GrabSuccess) {
546N/A sleep(1);
546N/A status = XGrabPointer(dsp, win[0], True, AllPointerEventMask,
546N/A GrabModeAsync, GrabModeAsync, None, mycursor,
546N/A CurrentTime);
546N/A
546N/A if (status != GrabSuccess)
1233N/A error("couldn't grab pointer! (%d)\n", status);
546N/A }
546N/A}
546N/A
546N/A
546N/A/*
546N/A * Assuming that we already have an asynch grab on the pointer,
546N/A * just grab it again with a new cursor shape and ignore the return code.
546N/A */
546N/Astatic void
546N/AXChangeGrabbedCursor(cursor)
546N/A Cursor cursor;
546N/A{
546N/A#ifndef DEBUG
546N/A (void) XGrabPointer(dsp, win[0], True, AllPointerEventMask,
546N/A GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
546N/A#endif
546N/A}
546N/A
546N/A
546N/A/*
546N/A * Restore all grabs, reset screensaver, restore colormap, close connection.
546N/A */
546N/Astatic void
546N/Afinish()
546N/A{
546N/A XSync(dsp, False);
546N/A if (!nolock && !allowaccess)
546N/A XUngrabHosts(dsp);
546N/A XUngrabPointer(dsp, CurrentTime);
546N/A XUngrabKeyboard(dsp, CurrentTime);
546N/A if (!enablesaver)
546N/A XSetScreenSaver(dsp, sstimeout, ssinterval, ssblanking, ssexposures);
546N/A XFlush(dsp);
546N/A XCloseDisplay(dsp);
546N/A}
546N/A
546N/A
546N/Astatic int
546N/AReadXString(s, slen)
546N/A char *s;
546N/A int slen;
546N/A{
546N/A XEvent event;
546N/A char keystr[20];
546N/A char c;
546N/A int i;
546N/A int bp;
546N/A int len;
546N/A int thisscreen = screen;
546N/A char pwbuf[PAM_MAX_RESP_SIZE];
546N/A
546N/A for (screen = 0; screen < screens; screen++)
546N/A if (thisscreen == screen)
546N/A init(icon[screen]);
546N/A else
546N/A init(win[screen]);
546N/A bp = 0;
546N/A *s = 0;
546N/A while (True) {
546N/A unsigned long lasteventtime = seconds();
546N/A while (!XPending(dsp)) {
546N/A for (screen = 0; screen < screens; screen++)
546N/A if (thisscreen == screen)
546N/A callback(icon[screen]);
546N/A else
546N/A callback(win[screen]);
546N/A XFlush(dsp);
546N/A usleep(delay);
546N/A if (seconds() - lasteventtime > timeout) {
546N/A screen = thisscreen;
546N/A stoptryingfornow = True;
546N/A return 1;
546N/A }
546N/A }
546N/A screen = thisscreen;
546N/A XNextEvent(dsp, &event);
546N/A switch (event.type) {
546N/A case KeyPress:
546N/A len = XLookupString((XKeyEvent *) & event, keystr, 20, NULL, NULL);
546N/A for (i = 0; i < len; i++) {
546N/A c = keystr[i];
546N/A switch (c) {
546N/A case 8: /* ^H */
546N/A case 127: /* DEL */
546N/A if (bp > 0)
546N/A bp--;
546N/A break;
546N/A case 10: /* ^J */
546N/A case 13: /* ^M */
546N/A s[bp] = '\0';
546N/A /*
546N/A * eat all events if there are more than enough pending... this
546N/A * keeps the Xlib event buffer from growing larger than all
546N/A * available memory and crashing xlock.
546N/A */
546N/A if (XPending(dsp) > 100) { /* 100 is arbitrarily big enough */
546N/A register Status status;
546N/A do {
546N/A status = XCheckMaskEvent(dsp,
546N/A KeyPressMask | KeyReleaseMask, &event);
546N/A } while (status);
546N/A XBell(dsp, 100);
546N/A }
546N/A return 0;
546N/A case 21: /* ^U */
546N/A bp = 0;
546N/A break;
546N/A default:
546N/A s[bp] = c;
546N/A if (bp < slen - 1)
546N/A bp++;
546N/A else
546N/A XSync(dsp, True); /* flush input buffer */
546N/A }
546N/A }
546N/A XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
546N/A if (echokeys || reallyechokeys) {
546N/A if (reallyechokeys) {
546N/A memcpy(pwbuf, s, slen);
546N/A } else {
546N/A memset(pwbuf, '?', slen);
546N/A }
546N/A
546N/A XFillRectangle(dsp, win[screen], Scr[screen].gc,
546N/A passx, passy - font->ascent,
546N/A XTextWidth(font, pwbuf, slen),
546N/A font->ascent + font->descent);
546N/A XDrawString(dsp, win[screen], textgc[screen],
546N/A passx, passy, pwbuf, bp);
546N/A }
546N/A /*
546N/A * eat all events if there are more than enough pending... this
546N/A * keeps the Xlib event buffer from growing larger than all
546N/A * available memory and crashing xlock.
546N/A */
546N/A if (XPending(dsp) > 100) { /* 100 is arbitrarily big enough */
546N/A register Status status;
546N/A do {
546N/A status = XCheckMaskEvent(dsp,
546N/A KeyPressMask | KeyReleaseMask, &event);
546N/A } while (status);
546N/A XBell(dsp, 100);
546N/A }
546N/A break;
546N/A
546N/A case ButtonPress:
546N/A if (((XButtonEvent *) & event)->window == icon[screen]) {
546N/A stoptryingfornow = True;
546N/A return 1;
546N/A }
546N/A break;
546N/A
546N/A case VisibilityNotify:
546N/A if (event.xvisibility.state != VisibilityUnobscured) {
546N/A#ifndef DEBUG
546N/A XRaiseWindow(dsp, win[screen]);
546N/A#endif
546N/A s[0] = '\0';
546N/A return 1;
546N/A }
546N/A break;
546N/A
546N/A case KeymapNotify:
546N/A case KeyRelease:
546N/A case ButtonRelease:
546N/A case MotionNotify:
546N/A case LeaveNotify:
546N/A case EnterNotify:
546N/A break;
546N/A
546N/A default:
546N/A fprintf(stderr, "%s: unexpected event: %d\n",
546N/A ProgramName, event.type);
546N/A break;
546N/A }
546N/A }
546N/A}
546N/A
546N/A
546N/Astatic int
546N/ACheckPassword()
546N/A{
546N/A#ifdef SYSV
546N/A struct spwd *rspw, *uspw;
546N/A struct passwd *upw;
1233N/A const char *user;
546N/A#else
546N/A struct passwd *rpw, *upw;
546N/A#endif /* SYSV */
546N/A
546N/A#ifdef SYSV
546N/A rspw = getspnam("root");
546N/A
546N/A upw = (struct passwd *)getpwuid(getuid());
546N/A if (upw == NULL) { /* should not pass NULL to getspnam */
546N/A user = "";
546N/A }
546N/A else {
546N/A user = upw->pw_name;
546N/A }
546N/A uspw = getspnam(user);
546N/A if (!uspw) {
546N/A if (allowroot) {
546N/A if (!rspw)
546N/A return(1);
546N/A else
546N/A return(0);
546N/A }
546N/A return(1);
546N/A }
546N/A#else /* SYSV */
546N/A rpw = (struct passwd *)getpwuid(0);
546N/A
546N/A upw = (struct passwd *)getpwuid(getuid());
546N/A
546N/A if (!upw) {
546N/A if (allowroot) {
546N/A if (!rpw)
546N/A return(1);
546N/A else
546N/A return(0);
546N/A }
546N/A return(1);
546N/A }
546N/A#endif /* SYSV */
546N/A
546N/A return(0);
546N/A}
546N/A
546N/A
546N/Astatic void passwordPrompt(const char *prompt)
546N/A{
546N/A int y, left;
546N/A Screen *scr = ScreenOfDisplay(dsp, screen);
546N/A
546N/A left = iconx[screen] + ICONW + font->max_bounds.width;
546N/A y = icony[screen] + font->ascent + font->ascent + font->descent + 2;
546N/A
546N/A XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
546N/A
546N/A XFillRectangle(dsp, win[screen], Scr[screen].gc,
546N/A left, y - font->ascent, WIDTH - left,
546N/A font->ascent + font->descent + 2);
546N/A
546N/A XDrawString(dsp, win[screen], textgc[screen],
546N/A left, y, prompt, strlen(prompt));
546N/A XDrawString(dsp, win[screen], textgc[screen],
546N/A left + 1, y, prompt, strlen(prompt));
546N/A
546N/A passx = left + 1 + XTextWidth(font, prompt, strlen(prompt))
546N/A + XTextWidth(font, " ", 1);
546N/A passy = y;
546N/A}
546N/A
546N/Astatic void displayTextInfo(const char *infoMsg)
546N/A{
546N/A int y;
546N/A Screen *scr = ScreenOfDisplay(dsp, screen);
546N/A
546N/A y = icony[screen] + ICONH + font->ascent + 2;
546N/A
546N/A XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
546N/A
546N/A XFillRectangle(dsp, win[screen], Scr[screen].gc,
546N/A iconx[screen], y - font->ascent,
546N/A WIDTH - iconx[screen],
546N/A font->ascent + font->descent + 2);
546N/A
546N/A XDrawString(dsp, win[screen], textgc[screen],
546N/A iconx[screen], y, infoMsg, strlen(infoMsg));
546N/A}
546N/A
546N/A#ifdef USE_PAM
546N/Astatic int pamconv(int num_msg, struct pam_message **msg,
546N/A struct pam_response **response, void *appdata_ptr)
546N/A{
546N/A int i;
546N/A int status = PAM_SUCCESS;
546N/A
546N/A struct pam_message *m;
546N/A struct pam_response *r;
546N/A
546N/A *response = calloc(num_msg, sizeof (struct pam_response));
546N/A if (*response == NULL)
546N/A return (PAM_BUF_ERR);
546N/A
546N/A m = *msg;
546N/A r = *response;
546N/A
546N/A for (i = 0; i < num_msg; i++ , m++ , r++) {
546N/A#ifdef DEBUG
546N/A if (verbose) {
546N/A fprintf(stderr, "pam_msg: %d: '%s'\n", m->msg_style, m->msg);
546N/A }
546N/A#endif
546N/A switch (m->msg_style) {
546N/A case PAM_ERROR_MSG:
546N/A case PAM_TEXT_INFO:
546N/A displayTextInfo(m->msg);
546N/A break;
546N/A
546N/A case PAM_PROMPT_ECHO_ON:
546N/A reallyechokeys = True;
546N/A /* FALLTHRU */
546N/A case PAM_PROMPT_ECHO_OFF:
546N/A passwordPrompt(m->msg);
546N/A if (ReadXString(buffer, PAM_MAX_RESP_SIZE)) {
546N/A /* timeout or other error */
546N/A status = PAM_CONV_ERR;
546N/A i = num_msg;
546N/A } else {
546N/A r->resp = strdup(buffer);
546N/A if (r->resp == NULL) {
546N/A status = PAM_BUF_ERR;
546N/A i = num_msg;
546N/A }
546N/A#ifdef DEBUG
546N/A if (verbose) {
546N/A fprintf(stderr, "pam_resp: '%s'\n", r->resp);
546N/A }
546N/A#endif
546N/A }
546N/A reallyechokeys = False;
546N/A break;
546N/A
546N/A default:
546N/A if (verbose) {
546N/A fprintf(stderr, "%s: Unknown PAM msg_style: %d\n",
546N/A ProgramName, m->msg_style);
546N/A }
546N/A }
546N/A }
546N/A if (status != PAM_SUCCESS) {
546N/A /* free responses */
546N/A r = *response;
546N/A for (i = 0; i < num_msg; i++, r++) {
546N/A if (r->resp)
546N/A free(r->resp);
546N/A }
546N/A free(*response);
546N/A *response = NULL;
546N/A }
546N/A return status;
546N/A}
546N/A#endif
546N/A
546N/A#ifdef sun
546N/A#include <syslog.h>
546N/A#include <bsm/adt.h>
546N/A#include <bsm/adt_event.h>
546N/A
546N/A
546N/A/*
546N/A * audit_lock - audit entry to screenlock
546N/A *
546N/A * Entry Process running with appropriate privilege to generate
546N/A * audit records and real uid of the user.
546N/A *
546N/A * Exit ADT_screenlock audit record written.
546N/A */
546N/Astatic void
546N/Aaudit_lock(void)
546N/A{
546N/A adt_session_data_t *ah; /* audit session handle */
546N/A adt_event_data_t *event; /* audit event handle */
546N/A
546N/A /* Audit start of screen lock -- equivalent to logout ;-) */
546N/A
546N/A if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
546N/A
546N/A syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m");
546N/A return;
546N/A }
546N/A if ((event = adt_alloc_event(ah, ADT_screenlock)) == NULL) {
546N/A
546N/A syslog(LOG_AUTH | LOG_ALERT,
546N/A "adt_alloc_event(ADT_screenlock): %m");
546N/A } else {
546N/A if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
546N/A
546N/A syslog(LOG_AUTH | LOG_ALERT,
546N/A "adt_put_event(ADT_screenlock): %m");
546N/A }
546N/A adt_free_event(event);
546N/A }
546N/A (void) adt_end_session(ah);
546N/A}
546N/A
546N/A
546N/A/*
546N/A * audit_unlock - audit screen unlock
546N/A *
546N/A * Entry Process running with appropriate privilege to generate
546N/A * audit records and real uid of the user.
546N/A * pam_status = PAM error code; reason for failure.
546N/A *
546N/A * Exit ADT_screenunlock audit record written.
546N/A */
546N/Astatic void
546N/Aaudit_unlock(int pam_status)
546N/A{
546N/A adt_session_data_t *ah; /* audit session handle */
546N/A adt_event_data_t *event; /* audit event handle */
546N/A
546N/A if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
546N/A
546N/A syslog(LOG_AUTH | LOG_ALERT,
546N/A "adt_start_session(ADT_screenunlock): %m");
546N/A return;
546N/A }
546N/A if ((event = adt_alloc_event(ah, ADT_screenunlock)) == NULL) {
546N/A
546N/A syslog(LOG_AUTH | LOG_ALERT,
546N/A "adt_alloc_event(ADT_screenunlock): %m");
546N/A } else {
546N/A if (adt_put_event(event,
546N/A pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
546N/A pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM +
546N/A pam_status) != 0) {
546N/A
546N/A syslog(LOG_AUTH | LOG_ALERT,
546N/A "adt_put_event(ADT_screenunlock(%s): %m",
546N/A pam_strerror(NULL, pam_status));
546N/A }
546N/A adt_free_event(event);
546N/A }
546N/A (void) adt_end_session(ah);
546N/A}
546N/A
546N/A
546N/A/*
546N/A * audit_passwd - audit password change
546N/A * Entry Process running with appropriate privilege to generate
546N/A * audit records and real uid of the user.
546N/A * pam_status = PAM error code; reason for failure.
546N/A *
546N/A * Exit ADT_passwd audit record written.
546N/A */
546N/Astatic void
546N/Aaudit_passwd(int pam_status)
546N/A{
546N/A adt_session_data_t *ah; /* audit session handle */
546N/A adt_event_data_t *event; /* audit event handle */
546N/A
546N/A if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
546N/A
546N/A syslog(LOG_AUTH | LOG_ALERT,
546N/A "adt_start_session(ADT_passwd): %m");
546N/A return;
546N/A }
546N/A if ((event = adt_alloc_event(ah, ADT_passwd)) == NULL) {
546N/A
546N/A syslog(LOG_AUTH | LOG_ALERT,
546N/A "adt_alloc_event(ADT_passwd): %m");
546N/A } else {
546N/A if (adt_put_event(event,
546N/A pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
546N/A pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM +
546N/A pam_status) != 0) {
546N/A
546N/A syslog(LOG_AUTH | LOG_ALERT,
546N/A "adt_put_event(ADT_passwd(%s): %m",
546N/A pam_strerror(NULL, pam_status));
546N/A }
546N/A adt_free_event(event);
546N/A }
546N/A (void) adt_end_session(ah);
546N/A}
546N/A#endif /* sun */
546N/A
546N/Astatic int
546N/AgetPassword()
546N/A{
546N/A char *userpass = NULL;
546N/A char *rootpass = NULL;
546N/A XWindowAttributes xgwa;
546N/A int y, left, done;
546N/A#ifdef SYSV
546N/A struct spwd *rspw, *uspw;
546N/A char *suserpass = NULL;
546N/A char *srootpass = NULL;
1233N/A const char *user;
546N/A#else
1233N/A const char *user = getenv("USER");
546N/A#endif /* SYSV */
546N/A struct passwd *rpw, *upw;
546N/A#ifdef USE_PAM
546N/A pam_handle_t *pamh = NULL;
546N/A struct pam_conv pc;
546N/A Bool use_pam = True;
546N/A int pam_error;
546N/A int pam_flags = 0;
546N/A#endif
546N/A const char *authErrMsg = text_invalid;
546N/A
546N/A#ifdef SYSV
546N/A rpw = getpwuid(0);
546N/A if (rpw) {
546N/A user = rpw->pw_name;
546N/A rootpass = strdup(rpw->pw_passwd);
546N/A
546N/A rspw = getspnam(user);
546N/A if (rspw && rspw->sp_pwdp)
546N/A srootpass = strdup(rspw->sp_pwdp);
546N/A }
546N/A
546N/A upw = getpwuid(getuid());
546N/A if (upw) {
546N/A user = upw->pw_name;
546N/A userpass = strdup(upw->pw_passwd);
546N/A
546N/A uspw = getspnam(user);
546N/A if (uspw && uspw->sp_pwdp)
546N/A suserpass = strdup(uspw->sp_pwdp);
546N/A }
546N/A else
546N/A user = "";
546N/A#else
546N/A rpw = (struct passwd *)getpwuid(0);
546N/A if (rpw)
546N/A rootpass = strdup(rpw->pw_passwd);
546N/A
546N/A upw = (struct passwd *)getpwuid(getuid());
546N/A if (upw)
546N/A userpass = strdup(upw->pw_passwd);
546N/A#endif /* SYSV */
546N/A
546N/A#ifdef USE_PAM
546N/A pc.conv = pamconv;
546N/A
546N/A pam_error = pam_start(XLOCK_PAM_SERVICE, user, &pc, &pamh);
546N/A if (pam_error != PAM_SUCCESS) {
546N/A use_pam = False;
546N/A PAM_ERROR_PRINT("pam_start");
546N/A } else {
546N/A#ifdef sun
546N/A /* Check /etc/default/login to see if we should add
546N/A PAM_DISALLOW_NULL_AUTHTOK to pam_flags */
546N/A if (defopen("/etc/default/login") == 0) {
546N/A char *ptr;
546N/A
546N/A int flags = defcntl(DC_GETFLAGS, 0);
546N/A TURNOFF(flags, DC_CASE);
546N/A (void) defcntl(DC_SETFLAGS, flags);
546N/A
546N/A if ((ptr = defread("PASSREQ=")) != NULL &&
546N/A strcasecmp("YES", ptr) == 0) {
546N/A pam_flags |= PAM_DISALLOW_NULL_AUTHTOK;
546N/A }
546N/A
546N/A (void) defopen((char *)NULL); /* close current file */
546N/A }
546N/A
546N/A#endif
546N/A#ifdef SYSV
546N/A /* Disable user password non-PAM authentication */
546N/A if (userpass) {
546N/A memset(userpass, 0, strlen(userpass));
546N/A free(userpass);
546N/A userpass = NULL;
546N/A }
546N/A if (suserpass) {
546N/A memset(suserpass, 0, strlen(suserpass));
546N/A free(suserpass);
546N/A suserpass = NULL;
546N/A }
546N/A#endif
546N/A }
546N/A#endif /* USE_PAM */
546N/A
546N/A XGetWindowAttributes(dsp, win[screen], &xgwa);
546N/A
546N/A XChangeGrabbedCursor(passwdcursor);
546N/A
546N/A XSetForeground(dsp, Scr[screen].gc, bgcol[screen].pixel);
546N/A XFillRectangle(dsp, win[screen], Scr[screen].gc,
546N/A 0, 0, xgwa.width, xgwa.height);
546N/A
546N/A XMapWindow(dsp, icon[screen]);
546N/A XRaiseWindow(dsp, icon[screen]);
546N/A
546N/A left = iconx[screen] + ICONW + font->max_bounds.width;
546N/A y = icony[screen] + font->ascent;
546N/A
546N/A XDrawString(dsp, win[screen], textgc[screen],
546N/A left, y, text_name, strlen(text_name));
546N/A XDrawString(dsp, win[screen], textgc[screen],
546N/A left + 1, y, text_name, strlen(text_name));
546N/A XDrawString(dsp, win[screen], textgc[screen],
546N/A left + XTextWidth(font, text_name, strlen(text_name)), y,
546N/A user, strlen(user));
546N/A
546N/A y = icony[screen] - (font->descent + 2);
546N/A
546N/A XDrawString(dsp, win[screen], textgc[screen],
546N/A iconx[screen], y, text_info, strlen(text_info));
546N/A
546N/A passwordPrompt(text_pass);
546N/A
546N/A XFlush(dsp);
546N/A
546N/A y = icony[screen] + ICONH + font->ascent + 2
546N/A + font->ascent + font->descent + 2;
546N/A
546N/A done = False;
546N/A stoptryingfornow = False;
546N/A while (!done) {
546N/A#ifdef USE_PAM
546N/A if (use_pam) {
546N/A
546N/A pam_error = pam_authenticate(pamh, pam_flags);
546N/A if (pam_error == PAM_SUCCESS) {
546N/A const char *pam_error_from = "pam_acct_mgmt";
546N/A
546N/A pam_error = pam_acct_mgmt(pamh, pam_flags);
546N/A
546N/A if (pam_error == PAM_NEW_AUTHTOK_REQD) {
546N/A do {
546N/A pam_error = pam_chauthtok(pamh,
546N/A PAM_CHANGE_EXPIRED_AUTHTOK);
546N/A } while (pam_error == PAM_AUTHTOK_ERR ||
546N/A pam_error == PAM_TRY_AGAIN);
546N/A pam_error_from = "pam_chauthtok";
546N/A#ifdef sun
546N/A audit_passwd(pam_error);
546N/A#endif /* sun */
546N/A }
546N/A
546N/A if (pam_error == PAM_SUCCESS) {
546N/A pam_error = pam_setcred(pamh,PAM_REFRESH_CRED);
546N/A if (pam_error != PAM_SUCCESS) {
546N/A PAM_ERROR_PRINT("pam_setcred(PAM_REFRESH_CRED)");
546N/A } else {
546N/A done = True;
546N/A }
546N/A } else {
546N/A#ifdef sun
546N/A audit_unlock(pam_error);
546N/A#endif /* sun */
546N/A PAM_ERROR_PRINT(pam_error_from);
546N/A }
546N/A } else if (stoptryingfornow) {
546N/A break;
546N/A } else {
546N/A#ifdef sun
546N/A audit_unlock(pam_error);
546N/A#endif /* sun */
546N/A PAM_ERROR_PRINT("pam_authenticate");
546N/A }
546N/A
546N/A if (pam_error != PAM_SUCCESS) {
546N/A authErrMsg = pam_strerror(pamh, pam_error);
546N/A }
546N/A } else
546N/A if (ReadXString(buffer, PAM_MAX_RESP_SIZE))
546N/A break;
546N/A#endif
546N/A
546N/A /*
546N/A * This section gets a little messy. In SYSV, the number of
546N/A * cases to handle increases because of the existence of the
546N/A * shadow file. There are also a number of cases that need
546N/A * to be dealt with where either root or user passwords are
546N/A * nil. Hopefully the code below is easy enough to follow.
546N/A */
546N/A
546N/A#ifdef SYSV
546N/A if (userpass) {
546N/A if (*userpass == NULL) {
546N/A done = (*buffer == NULL);
546N/A } else {
546N/A done = (!strcmp(crypt(buffer, userpass), userpass));
546N/A }
546N/A }
546N/A if (!done && suserpass) {
546N/A if (*suserpass == NULL) {
546N/A done = (*buffer == NULL);
546N/A } else {
546N/A done = (!strcmp(crypt(buffer, suserpass), suserpass));
546N/A }
546N/A }
546N/A if (!done && allowroot) {
546N/A if (srootpass) {
546N/A if (*srootpass == NULL) {
546N/A done = (*buffer == NULL);
546N/A } else {
546N/A done = (!strcmp(crypt(buffer, srootpass), srootpass));
546N/A }
546N/A }
546N/A if (!done && rootpass) {
546N/A if (*rootpass == NULL) {
546N/A done = (*buffer == NULL);
546N/A } else {
546N/A done = (!strcmp(crypt(buffer, rootpass), rootpass));
546N/A }
546N/A }
546N/A }
546N/A#else
546N/A done = !((strcmp(crypt(buffer, userpass), userpass))
546N/A && (!allowroot || strcmp(crypt(buffer, rootpass), rootpass)));
546N/A
546N/A if (!done && *buffer == NULL) {
546N/A /* just hit return, and it wasn't his password */
546N/A break;
546N/A }
546N/A if (*userpass == NULL && *buffer != NULL) {
546N/A /*
546N/A * the user has no password, but something was typed anyway.
546N/A * sounds fishy: don't let him in...
546N/A */
546N/A done = False;
546N/A }
546N/A#endif /* SYSV */
546N/A
546N/A /* clear plaintext password so you can't grunge around /dev/kmem */
546N/A memset(buffer, 0, sizeof(buffer));
546N/A
546N/A displayTextInfo(text_valid);
546N/A
546N/A if (done) {
546N/A /* clear encrypted passwords just in case */
546N/A if (rootpass) {
546N/A memset(rootpass, 0, strlen(rootpass));
546N/A free(rootpass);
546N/A }
546N/A if (userpass) {
546N/A memset(userpass, 0, strlen(userpass));
546N/A free(userpass);
546N/A }
546N/A#ifdef SYSV
546N/A if (srootpass) {
546N/A memset(srootpass, 0, strlen(srootpass));
546N/A free(srootpass);
546N/A }
546N/A if (suserpass) {
546N/A memset(suserpass, 0, strlen(suserpass));
546N/A free(suserpass);
546N/A }
546N/A#endif
546N/A#ifdef USE_PAM
546N/A#ifdef sun
546N/A audit_unlock(pam_error);
546N/A#endif /* sun */
546N/A pam_end(pamh, pam_error);
546N/A#endif
546N/A return 0;
546N/A } else {
546N/A XSync(dsp, True); /* flush input buffer */
546N/A sleep(1);
546N/A
546N/A displayTextInfo(authErrMsg);
546N/A
546N/A if (echokeys || reallyechokeys) /* erase old echo */
546N/A XFillRectangle(dsp, win[screen], Scr[screen].gc,
546N/A passx, passy - font->ascent,
546N/A xgwa.width - passx,
546N/A font->ascent + font->descent);
546N/A }
546N/A }
546N/A /* clear encrypted passwords just in case */
546N/A if (rootpass) {
546N/A memset(rootpass, 0, strlen(rootpass));
546N/A free(rootpass);
546N/A }
546N/A if (userpass) {
546N/A memset(userpass, 0, strlen(userpass));
546N/A free(userpass);
546N/A }
546N/A#ifdef SYSV
546N/A if (srootpass) {
546N/A memset(srootpass, 0, strlen(srootpass));
546N/A free(srootpass);
546N/A }
546N/A if (suserpass) {
546N/A memset(suserpass, 0, strlen(suserpass));
546N/A free(suserpass);
546N/A }
546N/A#endif
546N/A#ifdef USE_PAM
546N/A pam_end(pamh, pam_error);
546N/A#endif
546N/A XChangeGrabbedCursor(mycursor);
546N/A XUnmapWindow(dsp, icon[screen]);
546N/A return 1;
546N/A}
546N/A
546N/A
546N/Astatic void
546N/AjustDisplay()
546N/A{
546N/A XEvent event;
546N/A
546N/A for (screen = 0; screen < screens; screen++)
546N/A init(win[screen]);
546N/A do {
546N/A while (!XPending(dsp)) {
546N/A for (screen = 0; screen < screens; screen++)
546N/A callback(win[screen]);
546N/A XFlush(dsp);
546N/A usleep(delay);
546N/A }
546N/A XNextEvent(dsp, &event);
546N/A#ifndef DEBUG
546N/A if (event.type == VisibilityNotify)
546N/A XRaiseWindow(dsp, event.xany.window);
546N/A#endif
546N/A } while (event.type != ButtonPress && event.type != KeyPress);
546N/A for (screen = 0; screen < screens; screen++)
546N/A if (event.xbutton.root == RootWindow(dsp, screen))
546N/A break;
546N/A if (usefirst)
546N/A XPutBackEvent(dsp, &event);
546N/A}
546N/A
546N/A
546N/Astatic void
546N/Asigcatch()
546N/A{
546N/A finish();
1233N/A error("caught terminate signal.\nAccess control list restored.\n");
546N/A}
546N/A
546N/A
546N/Astatic void
546N/AlockDisplay()
546N/A{
546N/A if (!allowaccess) {
546N/A#ifdef SYSV
546N/A sigset_t oldsigmask;
546N/A sigset_t newsigmask;
546N/A
546N/A sigemptyset(&newsigmask);
546N/A sigaddset(&newsigmask, SIGHUP);
546N/A sigaddset(&newsigmask, SIGINT);
546N/A sigaddset(&newsigmask, SIGQUIT);
546N/A sigaddset(&newsigmask, SIGTERM);
546N/A sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);
546N/A#else
546N/A int oldsigmask;
546N/A
546N/A oldsigmask = sigblock(sigmask(SIGHUP) |
546N/A sigmask(SIGINT) |
546N/A sigmask(SIGQUIT) |
546N/A sigmask(SIGTERM));
546N/A#endif
546N/A
546N/A signal(SIGHUP, (void (*)()) sigcatch);
546N/A signal(SIGINT, (void (*)()) sigcatch);
546N/A signal(SIGQUIT, (void (*)()) sigcatch);
546N/A signal(SIGTERM, (void (*)()) sigcatch);
546N/A
546N/A XGrabHosts(dsp);
546N/A
546N/A#ifdef SYSV
546N/A sigprocmask(SIG_SETMASK, &oldsigmask, &oldsigmask);
546N/A#else
546N/A sigsetmask(oldsigmask);
546N/A#endif
546N/A }
546N/A#ifdef sun
546N/A audit_lock();
546N/A#endif /* sun */
546N/A do {
546N/A justDisplay();
546N/A } while (getPassword());
546N/A}
546N/A
546N/A
546N/Aint
546N/Amain(argc, argv)
546N/A int argc;
546N/A char *argv[];
546N/A{
546N/A XSetWindowAttributes xswa;
546N/A XGCValues xgcv;
546N/A
546N/A ProgramName = strrchr(argv[0], '/');
546N/A if (ProgramName)
546N/A ProgramName++;
546N/A else
546N/A ProgramName = argv[0];
546N/A
546N/A srandom(time((long *) 0)); /* random mode needs the seed set. */
546N/A
546N/A GetResources(argc, argv);
546N/A
546N/A CheckResources();
546N/A
546N/A font = XLoadQueryFont(dsp, fontname);
546N/A if (font == NULL) {
546N/A fprintf(stderr, "%s: can't find font: %s, using %s...\n",
546N/A ProgramName, fontname, FALLBACK_FONTNAME);
546N/A font = XLoadQueryFont(dsp, FALLBACK_FONTNAME);
546N/A if (font == NULL)
1233N/A error("can't even find %s!!!\n", FALLBACK_FONTNAME);
546N/A }
546N/A
546N/A if (CheckPassword()) {
1233N/A error("can't get the user password. Exiting ...\n"
1233N/A "\tYou need to run xlock in setuid root mode on your local machine.\n"
1233N/A "\tContact your system administrator.\n");
546N/A }
546N/A
546N/A screens = ScreenCount(dsp);
546N/A if (screens > MAXSCREENS)
1233N/A error("can only support %d screens.\n", MAXSCREENS);
546N/A for (screen = 0; screen < screens; screen++) {
546N/A XColor tmp;
546N/A Screen *scr = ScreenOfDisplay(dsp, screen);
546N/A Visual *vis = XDefaultVisual(dsp, screen);
546N/A Colormap cmap;
546N/A root[screen] = RootWindowOfScreen(scr);
546N/A
546N/A cmap = XCreateColormap(dsp, root[screen], vis, AllocNone);
546N/A
546N/A XAllocNamedColor(dsp, cmap, "White", &sswhite[screen], &tmp);
546N/A XAllocNamedColor(dsp, cmap, "Black", &ssblack[screen], &tmp);
546N/A
546N/A if (mono || CellsOfScreen(scr) == 2) {
546N/A if (!XAllocNamedColor(dsp, cmap, background,
546N/A &bgcol[screen], &tmp)) {
546N/A XAllocNamedColor(dsp, cmap, "White", &bgcol[screen], &tmp);
546N/A }
546N/A if (!XAllocNamedColor(dsp, cmap, foreground,
546N/A &fgcol[screen], &tmp)) {
546N/A XAllocNamedColor(dsp, cmap, "Black", &fgcol[screen], &tmp);
546N/A }
546N/A Scr[screen].pixels[0] = fgcol[screen].pixel;
546N/A Scr[screen].pixels[1] = bgcol[screen].pixel;
546N/A Scr[screen].npixels = 2;
546N/A } else {
546N/A int colorcount = NUMCOLORS;
546N/A u_char red[NUMCOLORS];
546N/A u_char green[NUMCOLORS];
546N/A u_char blue[NUMCOLORS];
546N/A int i;
546N/A
546N/A if (!XAllocNamedColor(dsp, cmap, background,
546N/A &bgcol[screen], &tmp)) {
546N/A fprintf(stderr, "couldn't allocate: %s\n", background);
546N/A XAllocNamedColor(dsp, cmap, "White", &bgcol[screen], &tmp);
546N/A }
546N/A if (!XAllocNamedColor(dsp, cmap, foreground,
546N/A &fgcol[screen], &tmp)) {
546N/A fprintf(stderr, "couldn't allocate: %s\n", foreground);
546N/A XAllocNamedColor(dsp, cmap, "Black", &fgcol[screen], &tmp);
546N/A }
546N/A hsbramp(0.0, saturation, 1.0, 1.0, saturation, 1.0, colorcount,
546N/A red, green, blue);
546N/A Scr[screen].npixels = 0;
546N/A for (i = 0; i < colorcount; i++) {
546N/A XColor xcolor;
546N/A
546N/A xcolor.red = red[i] << 8;
546N/A xcolor.green = green[i] << 8;
546N/A xcolor.blue = blue[i] << 8;
546N/A xcolor.flags = DoRed | DoGreen | DoBlue;
546N/A
546N/A if (!XAllocColor(dsp, cmap, &xcolor))
546N/A break;
546N/A
546N/A Scr[screen].pixels[i] = xcolor.pixel;
546N/A Scr[screen].npixels++;
546N/A }
546N/A if (verbose)
546N/A fprintf(stderr, "%d pixels allocated\n", Scr[screen].npixels);
546N/A }
546N/A
546N/A xswa.override_redirect = True;
546N/A xswa.background_pixel = ssblack[screen].pixel;
546N/A xswa.event_mask = KeyPressMask | ButtonPressMask | VisibilityChangeMask;
546N/A xswa.colormap = cmap; /* In DEBUG mode, we do not see this */
546N/A
546N/A win[screen] = XCreateWindow(dsp, root[screen], 0, 0, WIDTH, HEIGHT, 0,
546N/A CopyFromParent, InputOutput, CopyFromParent,
546N/A CWMASK, &xswa);
546N/A
546N/A#ifdef DEBUG
546N/A {
546N/A XWMHints xwmh;
546N/A
546N/A xwmh.flags = InputHint;
546N/A xwmh.input = True;
546N/A XChangeProperty(dsp, win[screen],
546N/A XA_WM_HINTS, XA_WM_HINTS, 32, PropModeReplace,
546N/A (unsigned char *) &xwmh, sizeof(xwmh) / sizeof(int));
546N/A }
546N/A#endif
546N/A
546N/A iconx[screen] = (DisplayWidth(dsp, screen) -
546N/A XTextWidth(font, text_info, strlen(text_info))) / 2;
546N/A
546N/A icony[screen] = DisplayHeight(dsp, screen) / 6;
546N/A
546N/A xswa.border_pixel = fgcol[screen].pixel;
546N/A xswa.background_pixel = bgcol[screen].pixel;
546N/A xswa.event_mask = ButtonPressMask;
546N/A xswa.colormap = cmap; /* In DEBUG mode, we do not see this */
546N/A
546N/A#define CIMASK CWBorderPixel | CWBackPixel | CWEventMask | CWColormap
546N/A icon[screen] = XCreateWindow(dsp, win[screen],
546N/A iconx[screen], icony[screen],
546N/A ICONW, ICONH, 1, CopyFromParent,
546N/A InputOutput, CopyFromParent,
546N/A CIMASK, &xswa);
546N/A
546N/A XMapWindow(dsp, win[screen]);
546N/A XRaiseWindow(dsp, win[screen]);
546N/A XInstallColormap(dsp, cmap);
546N/A
546N/A xgcv.foreground = sswhite[screen].pixel;
546N/A xgcv.background = ssblack[screen].pixel;
546N/A Scr[screen].gc = XCreateGC(dsp, win[screen],
546N/A GCForeground | GCBackground, &xgcv);
546N/A
546N/A xgcv.foreground = fgcol[screen].pixel;
546N/A xgcv.background = bgcol[screen].pixel;
546N/A xgcv.font = font->fid;
546N/A textgc[screen] = XCreateGC(dsp, win[screen],
546N/A GCFont | GCForeground | GCBackground, &xgcv);
546N/A }
546N/A lockc = XCreateBitmapFromData(dsp, root[0], no_bits, 1, 1);
546N/A lockm = XCreateBitmapFromData(dsp, root[0], no_bits, 1, 1);
546N/A mycursor = XCreatePixmapCursor(dsp, lockc, lockm,
546N/A &fgcol[screen], &bgcol[screen], 0, 0);
546N/A passwdcursor = XCreateFontCursor(dsp, XC_left_ptr);
546N/A XFreePixmap(dsp, lockc);
546N/A XFreePixmap(dsp, lockm);
546N/A
546N/A
546N/A if (!enablesaver) {
546N/A XGetScreenSaver(dsp, &sstimeout, &ssinterval,
546N/A &ssblanking, &ssexposures);
546N/A XSetScreenSaver(dsp, 0, 0, 0, 0); /* disable screen saver */
546N/A }
546N/A#ifndef DEBUG
546N/A GrabKeyboardAndMouse();
546N/A#endif
546N/A
546N/A nice(nicelevel);
546N/A
546N/A if (nolock)
546N/A justDisplay();
546N/A else
546N/A lockDisplay();
546N/A
546N/A finish();
546N/A
546N/A return 0;
546N/A}