xlock.c revision 919
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/*
* xlock.c - X11 client to lock a display and show a screen saver.
*
* Copyright (c) 1988-91 by Patrick J. Naughton.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* This file is provided AS IS with no warranties of any kind. The author
* shall have no liability with respect to the infringement of copyrights,
* trade secrets or any patents by this file or any part thereof. In no
* event will the author be liable for any lost revenue or profits or
* other special, indirect and consequential damages.
*
* Comments and additions should be sent to the author:
*
* naughton@eng.sun.com
*
* Patrick J. Naughton
* MS 10-20
* Sun Laboritories, Inc.
* 2550 Garcia Ave
* Mountain View, CA 94043
*
* Revision History:
*
* 24-Jun-91: make foreground and background color get used on mono.
* 24-May-91: added -usefirst.
* 16-May-91: added pyro and random modes.
* ripped big comment block out of all other files.
* 08-Jan-91: fix some problems with password entry.
* removed renicing code.
* 29-Oct-90: added cast to XFree() arg.
* added volume arg to call to XBell().
* 28-Oct-90: center prompt screen.
* make sure Xlib input buffer does not use up all of swap.
* make displayed text come from resource file for better I18N.
* add backward compatible signal handlers for pre 4.1 machines.
* 31-Aug-90: added blank mode.
* added swarm mode.
* moved usleep() and seconds() out to usleep.c.
* added SVR4 defines to xlock.h
* 29-Jul-90: added support for multiple screens to be locked by one xlock.
* moved global defines to xlock.h
* removed use of allowsig().
* 07-Jul-90: reworked commandline args and resources to use Xrm.
* moved resource processing out to resource.c
* 02-Jul-90: reworked colors to not use dynamic colormap.
* 23-May-90: added autoraise when obscured.
* 15-Apr-90: added hostent alias searching for host authentication.
* 18-Feb-90: added SunOS3.5 fix.
* changed -mono -> -color, and -saver -> -lock.
* allow non-locking screensavers to display on remote machine.
* added -echokeys to disable echoing of '?'s on input.
* cleaned up all of the parameters and defaults.
* 20-Dec-89: added -xhost to allow access control list to be left alone.
* added -screensaver (don't disable screen saver) for the paranoid.
* Moved seconds() here from all of the display mode source files.
* Fixed bug with calling XUngrabHosts() in finish().
* 19-Dec-89: Fixed bug in GrabPointer.
* Changed fontname to XLFD style.
* 23-Sep-89: Added fix to allow local hostname:0 as a display.
* Moved colormap installation later in startup.
* 20-Sep-89: Linted and made -saver mode grab the keyboard and mouse.
* Replaced SunView code for life mode with Jim Graham's version,
* so I could contrib it without legal problems.
* Sent to expo for X11R4 contrib.
* 19-Sep-89: Added '?'s on input.
* 27-Mar-89: Added -qix mode.
* Fixed GContext->GC.
* 20-Mar-89: Added backup font (fixed) if XQueryLoadFont() fails.
* Changed default font to lucida-sans-24.
* 08-Mar-89: Added -nice, -mode and -display, built vector for life and hop.
* 24-Feb-89: Replaced hopalong display with life display from SunView1.
* 22-Feb-89: Added fix for color servers with n < 8 planes.
* 16-Feb-89: Updated calling conventions for XCreateHsbColormap();
* Added -count for number of iterations per color.
* Fixed defaulting mechanism.
* Ripped out VMS hacks.
* Sent to expo for X11R3 contrib.
* 15-Feb-89: Changed default font to pellucida-sans-18.
* 20-Jan-89: Added -verbose and fixed usage message.
* 19-Jan-89: Fixed monochrome gc bug.
* 16-Dec-88: Added SunView style password prompting.
* 19-Sep-88: Changed -color to -mono. (default is color on color displays).
* Added -saver option. (just do display... don't lock.)
* 31-Aug-88: Added -time option.
* Removed code for fractals to separate file for modularity.
* Added signal handler to restore host access.
* Installs dynamic colormap with a Hue Ramp.
* If grabs fail then exit.
* Added VMS Hacks. (password 'iwiwuu').
* Sent to expo for X11R2 contrib.
* 08-Jun-88: Fixed root password pointer problem and changed PASSLENGTH to 20.
* 20-May-88: Added -root to allow root to unlock.
* 12-Apr-88: Added root password override.
* Added screen saver override.
* Removed XGrabServer/XUngrabServer.
* Added access control handling instead.
* 01-Apr-88: Added XGrabServer/XUngrabServer for more security.
* 30-Mar-88: Removed startup password requirement.
* Removed cursor to avoid phosphor burn.
* 27-Mar-88: Rotate fractal by 45 degrees clockwise.
* 24-Mar-88: Added color support. [-color]
* wrote the man page.
* 23-Mar-88: Added HOPALONG routines from Scientific American Sept. 86 p. 14.
* added password requirement for invokation
* removed option for command line password
* added requirement for display to be "unix:0".
* 22-Mar-88: Recieved Walter Milliken's comp.windows.x posting.
*
*/
#include <stdio.h>
#include <signal.h>
#include <string.h>
#ifdef SYSV
#include <shadow.h>
#endif
#include <pwd.h>
#include "xlock.h"
#include <X11/cursorfont.h>
#ifdef USE_PAM
# include <security/pam_appl.h>
# ifndef XLOCK_PAM_SERVICE
# define XLOCK_PAM_SERVICE "xlock"
# endif
# define PAM_ERROR_PRINT(pamfunc) \
if (verbose) { \
}
# ifdef sun
# include <deflt.h>
# endif
#endif
char *ProgramName; /* argv[0] */
int screen; /* current screen */
static int screens; /* number of screens */
static char no_bits[] = {0}; /* dummy array for the blank cursor */
static int passx; /* position of the ?'s */
static int passy;
static XFontStruct *font;
static int sstimeout; /* screen saver parameters */
static int ssinterval;
static int ssblanking;
static int ssexposures;
static char buffer[PAM_MAX_RESP_SIZE];
#define FALLBACK_FONTNAME "fixed"
#define ICONW 64
#define ICONH 64
#ifdef DEBUG
#else
#endif
#define AllPointerEventMask \
(ButtonPressMask | ButtonReleaseMask | \
/* VARARGS1 */
void
{
exit(1);
}
/*
* Server access control support.
*/
static int HostAccessCount; /* the number of machines in XHosts */
static void
{
if (XHosts)
}
static void
{
if (XHosts) {
}
if (HostAccessState == False)
}
/*
* Simple wrapper to get an asynchronous grab on the keyboard and mouse.
* If either grab fails, we sleep for one second and try again since some
* window manager might have had the mouse grabbed to drive the menu choice
* that picked "Lock Screen..". If either one fails the second time we print
* an error message and exit.
*/
static void
{
if (status != GrabSuccess) {
sleep(1);
if (status != GrabSuccess)
}
if (status != GrabSuccess) {
sleep(1);
if (status != GrabSuccess)
}
}
/*
* Assuming that we already have an asynch grab on the pointer,
* just grab it again with a new cursor shape and ignore the return code.
*/
static void
{
#ifndef DEBUG
#endif
}
/*
* Restore all grabs, reset screensaver, restore colormap, close connection.
*/
static void
finish()
{
if (!nolock && !allowaccess)
if (!enablesaver)
}
static int
ReadXString(s, slen)
char *s;
int slen;
{
char keystr[20];
char c;
int i;
int bp;
int len;
int thisscreen = screen;
char pwbuf[PAM_MAX_RESP_SIZE];
if (thisscreen == screen)
else
bp = 0;
*s = 0;
while (True) {
unsigned long lasteventtime = seconds();
if (thisscreen == screen)
else
screen = thisscreen;
return 1;
}
}
screen = thisscreen;
case KeyPress:
for (i = 0; i < len; i++) {
c = keystr[i];
switch (c) {
case 8: /* ^H */
case 127: /* DEL */
if (bp > 0)
bp--;
break;
case 10: /* ^J */
case 13: /* ^M */
s[bp] = '\0';
/*
* eat all events if there are more than enough pending... this
* keeps the Xlib event buffer from growing larger than all
* available memory and crashing xlock.
*/
do {
} while (status);
}
return 0;
case 21: /* ^U */
bp = 0;
break;
default:
s[bp] = c;
bp++;
else
}
}
if (echokeys || reallyechokeys) {
if (reallyechokeys) {
} else {
}
}
/*
* eat all events if there are more than enough pending... this
* keeps the Xlib event buffer from growing larger than all
* available memory and crashing xlock.
*/
do {
} while (status);
}
break;
case ButtonPress:
return 1;
}
break;
case VisibilityNotify:
#ifndef DEBUG
#endif
s[0] = '\0';
return 1;
}
break;
case KeymapNotify:
case KeyRelease:
case ButtonRelease:
case MotionNotify:
case LeaveNotify:
case EnterNotify:
break;
default:
break;
}
}
}
static int
{
#ifdef SYSV
char *user;
#else
#endif /* SYSV */
#ifdef SYSV
user = "";
}
else {
}
if (!uspw) {
if (allowroot) {
if (!rspw)
return(1);
else
return(0);
}
return(1);
}
#else /* SYSV */
if (!upw) {
if (allowroot) {
if (!rpw)
return(1);
else
return(0);
}
return(1);
}
#endif /* SYSV */
return(0);
}
static void passwordPrompt(const char *prompt)
{
int y, left;
passy = y;
}
static void displayTextInfo(const char *infoMsg)
{
int y;
}
#ifdef USE_PAM
{
int i;
int status = PAM_SUCCESS;
struct pam_message *m;
struct pam_response *r;
return (PAM_BUF_ERR);
m = *msg;
r = *response;
for (i = 0; i < num_msg; i++ , m++ , r++) {
#ifdef DEBUG
if (verbose) {
}
#endif
switch (m->msg_style) {
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
displayTextInfo(m->msg);
break;
case PAM_PROMPT_ECHO_ON:
/* FALLTHRU */
case PAM_PROMPT_ECHO_OFF:
passwordPrompt(m->msg);
/* timeout or other error */
i = num_msg;
} else {
i = num_msg;
}
#ifdef DEBUG
if (verbose) {
}
#endif
}
break;
default:
if (verbose) {
ProgramName, m->msg_style);
}
}
}
if (status != PAM_SUCCESS) {
/* free responses */
r = *response;
for (i = 0; i < num_msg; i++, r++) {
if (r->resp)
}
}
return status;
}
#endif
#ifdef sun
#include <syslog.h>
#include <bsm/adt_event.h>
/*
* audit_lock - audit entry to screenlock
*
* Entry Process running with appropriate privilege to generate
* audit records and real uid of the user.
*
* Exit ADT_screenlock audit record written.
*/
static void
audit_lock(void)
{
/* Audit start of screen lock -- equivalent to logout ;-) */
return;
}
"adt_alloc_event(ADT_screenlock): %m");
} else {
"adt_put_event(ADT_screenlock): %m");
}
}
(void) adt_end_session(ah);
}
/*
* audit_unlock - audit screen unlock
*
* Entry Process running with appropriate privilege to generate
* audit records and real uid of the user.
* pam_status = PAM error code; reason for failure.
*
* Exit ADT_screenunlock audit record written.
*/
static void
audit_unlock(int pam_status)
{
"adt_start_session(ADT_screenunlock): %m");
return;
}
"adt_alloc_event(ADT_screenunlock): %m");
} else {
if (adt_put_event(event,
pam_status) != 0) {
"adt_put_event(ADT_screenunlock(%s): %m",
}
}
(void) adt_end_session(ah);
}
/*
* audit_passwd - audit password change
* Entry Process running with appropriate privilege to generate
* audit records and real uid of the user.
* pam_status = PAM error code; reason for failure.
*
* Exit ADT_passwd audit record written.
*/
static void
audit_passwd(int pam_status)
{
"adt_start_session(ADT_passwd): %m");
return;
}
"adt_alloc_event(ADT_passwd): %m");
} else {
if (adt_put_event(event,
pam_status) != 0) {
"adt_put_event(ADT_passwd(%s): %m",
}
}
(void) adt_end_session(ah);
}
#endif /* sun */
static int
{
#ifdef SYSV
char *user;
#else
#endif /* SYSV */
#ifdef USE_PAM
int pam_error;
int pam_flags = 0;
#endif
const char *authErrMsg = text_invalid;
#ifdef SYSV
if (rpw) {
}
if (upw) {
}
else
user = "";
#else
if (rpw)
if (upw)
#endif /* SYSV */
#ifdef USE_PAM
if (pam_error != PAM_SUCCESS) {
PAM_ERROR_PRINT("pam_start");
} else {
#ifdef sun
PAM_DISALLOW_NULL_AUTHTOK to pam_flags */
char *ptr;
}
}
#endif
#ifdef SYSV
/* Disable user password non-PAM authentication */
if (userpass) {
}
if (suserpass) {
}
#endif
}
#endif /* USE_PAM */
while (!done) {
#ifdef USE_PAM
if (use_pam) {
if (pam_error == PAM_SUCCESS) {
const char *pam_error_from = "pam_acct_mgmt";
if (pam_error == PAM_NEW_AUTHTOK_REQD) {
do {
} while (pam_error == PAM_AUTHTOK_ERR ||
pam_error == PAM_TRY_AGAIN);
pam_error_from = "pam_chauthtok";
#ifdef sun
#endif /* sun */
}
if (pam_error == PAM_SUCCESS) {
if (pam_error != PAM_SUCCESS) {
PAM_ERROR_PRINT("pam_setcred(PAM_REFRESH_CRED)");
} else {
}
} else {
#ifdef sun
#endif /* sun */
}
} else if (stoptryingfornow) {
break;
} else {
#ifdef sun
#endif /* sun */
PAM_ERROR_PRINT("pam_authenticate");
}
if (pam_error != PAM_SUCCESS) {
}
} else
break;
#endif
/*
* This section gets a little messy. In SYSV, the number of
* cases to handle increases because of the existence of the
* shadow file. There are also a number of cases that need
* to be dealt with where either root or user passwords are
* nil. Hopefully the code below is easy enough to follow.
*/
#ifdef SYSV
if (userpass) {
} else {
}
}
} else {
}
}
if (srootpass) {
} else {
}
}
} else {
}
}
}
#else
/* just hit return, and it wasn't his password */
break;
}
/*
* the user has no password, but something was typed anyway.
* sounds fishy: don't let him in...
*/
}
#endif /* SYSV */
if (done) {
/* clear encrypted passwords just in case */
if (rootpass) {
}
if (userpass) {
}
#ifdef SYSV
if (srootpass) {
}
if (suserpass) {
}
#endif
#ifdef USE_PAM
#ifdef sun
#endif /* sun */
#endif
return 0;
} else {
sleep(1);
}
}
/* clear encrypted passwords just in case */
if (rootpass) {
}
if (userpass) {
}
#ifdef SYSV
if (srootpass) {
}
if (suserpass) {
}
#endif
#ifdef USE_PAM
#endif
return 1;
}
static void
{
do {
}
#ifndef DEBUG
#endif
break;
if (usefirst)
}
static void
sigcatch()
{
finish();
}
static void
{
if (!allowaccess) {
#ifdef SYSV
#else
int oldsigmask;
#endif
#ifdef SYSV
#else
#endif
}
#ifdef sun
audit_lock();
#endif /* sun */
do {
justDisplay();
} while (getPassword());
}
int
int argc;
char *argv[];
{
if (ProgramName)
ProgramName++;
else
ProgramName = argv[0];
}
if (CheckPassword()) {
}
if (screens > MAXSCREENS)
}
}
} else {
int colorcount = NUMCOLORS;
int i;
}
}
for (i = 0; i < colorcount; i++) {
break;
}
if (verbose)
}
#ifdef DEBUG
{
}
#endif
}
if (!enablesaver) {
&ssblanking, &ssexposures);
}
#ifndef DEBUG
#endif
if (nolock)
justDisplay();
else
lockDisplay();
finish();
return 0;
}