2 * Copyright (c) 1988, 2019, Oracle and/or its affiliates. All rights reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * xlock.c - X11 client to lock a display and show a screen saver.
26 * Copyright (c) 1988-91 by Patrick J. Naughton.
28 * Permission to use, copy, modify, and distribute this software and its
29 * documentation for any purpose and without fee is hereby granted,
30 * provided that the above copyright notice appear in all copies and that
31 * both that copyright notice and this permission notice appear in
32 * supporting documentation.
34 * This file is provided AS IS with no warranties of any kind. The author
35 * shall have no liability with respect to the infringement of copyrights,
36 * trade secrets or any patents by this file or any part thereof. In no
37 * event will the author be liable for any lost revenue or profits or
38 * other special, indirect and consequential damages.
40 * Comments and additions should be sent to the author:
42 * naughton@eng.sun.com
46 * Sun Laboritories, Inc.
48 * Mountain View, CA 94043
52 * 24-Jun-91: make foreground and background color get used on mono.
53 * 24-May-91: added -usefirst.
54 * 16-May-91: added pyro and random modes.
55 * ripped big comment block out of all other files.
56 * 08-Jan-91: fix some problems with password entry.
57 * removed renicing code.
58 * 29-Oct-90: added cast to XFree() arg.
59 * added volume arg to call to XBell().
60 * 28-Oct-90: center prompt screen.
61 * make sure Xlib input buffer does not use up all of swap.
62 * make displayed text come from resource file for better I18N.
63 * add backward compatible signal handlers for pre 4.1 machines.
64 * 31-Aug-90: added blank mode.
66 * moved usleep() and seconds() out to usleep.c.
67 * added SVR4 defines to xlock.h
68 * 29-Jul-90: added support for multiple screens to be locked by one xlock.
69 * moved global defines to xlock.h
70 * removed use of allowsig().
71 * 07-Jul-90: reworked commandline args and resources to use Xrm.
72 * moved resource processing out to resource.c
73 * 02-Jul-90: reworked colors to not use dynamic colormap.
74 * 23-May-90: added autoraise when obscured.
75 * 15-Apr-90: added hostent alias searching for host authentication.
76 * 18-Feb-90: added SunOS3.5 fix.
77 * changed -mono -> -color, and -saver -> -lock.
78 * allow non-locking screensavers to display on remote machine.
79 * added -echokeys to disable echoing of '?'s on input.
80 * cleaned up all of the parameters and defaults.
81 * 20-Dec-89: added -xhost to allow access control list to be left alone.
82 * added -screensaver (don't disable screen saver) for the paranoid.
83 * Moved seconds() here from all of the display mode source files.
84 * Fixed bug with calling XUngrabHosts() in finish().
85 * 19-Dec-89: Fixed bug in GrabPointer.
86 * Changed fontname to XLFD style.
87 * 23-Sep-89: Added fix to allow local hostname:0 as a display.
88 * Put empty case for Enter/Leave events.
89 * Moved colormap installation later in startup.
90 * 20-Sep-89: Linted and made -saver mode grab the keyboard and mouse.
91 * Replaced SunView code for life mode with Jim Graham's version,
92 * so I could contrib it without legal problems.
93 * Sent to expo for X11R4 contrib.
94 * 19-Sep-89: Added '?'s on input.
95 * 27-Mar-89: Added -qix mode.
97 * 20-Mar-89: Added backup font (fixed) if XQueryLoadFont() fails.
98 * Changed default font to lucida-sans-24.
99 * 08-Mar-89: Added -nice, -mode and -display, built vector for life and hop.
100 * 24-Feb-89: Replaced hopalong display with life display from SunView1.
101 * 22-Feb-89: Added fix for color servers with n < 8 planes.
102 * 16-Feb-89: Updated calling conventions for XCreateHsbColormap();
103 * Added -count for number of iterations per color.
104 * Fixed defaulting mechanism.
105 * Ripped out VMS hacks.
106 * Sent to expo for X11R3 contrib.
107 * 15-Feb-89: Changed default font to pellucida-sans-18.
108 * 20-Jan-89: Added -verbose and fixed usage message.
109 * 19-Jan-89: Fixed monochrome gc bug.
110 * 16-Dec-88: Added SunView style password prompting.
111 * 19-Sep-88: Changed -color to -mono. (default is color on color displays).
112 * Added -saver option. (just do display... don't lock.)
113 * 31-Aug-88: Added -time option.
114 * Removed code for fractals to separate file for modularity.
115 * Added signal handler to restore host access.
116 * Installs dynamic colormap with a Hue Ramp.
117 * If grabs fail then exit.
118 * Added VMS Hacks. (password 'iwiwuu').
119 * Sent to expo for X11R2 contrib.
120 * 08-Jun-88: Fixed root password pointer problem and changed PASSLENGTH to 20.
121 * 20-May-88: Added -root to allow root to unlock.
122 * 12-Apr-88: Added root password override.
123 * Added screen saver override.
124 * Removed XGrabServer/XUngrabServer.
125 * Added access control handling instead.
126 * 01-Apr-88: Added XGrabServer/XUngrabServer for more security.
127 * 30-Mar-88: Removed startup password requirement.
128 * Removed cursor to avoid phosphor burn.
129 * 27-Mar-88: Rotate fractal by 45 degrees clockwise.
130 * 24-Mar-88: Added color support. [-color]
131 * wrote the man page.
132 * 23-Mar-88: Added HOPALONG routines from Scientific American Sept. 86 p. 14.
133 * added password requirement for invokation
134 * removed option for command line password
135 * added requirement for display to be "unix:0".
136 * 22-Mar-88: Recieved Walter Milliken's comp.windows.x posting.
152 # define NOTE(s) /* ignored */
156 #include <X11/cursorfont.h>
157 #include <X11/Xatom.h>
160 # include <security/pam_appl.h>
161 # ifndef XLOCK_PAM_SERVICE
162 # define XLOCK_PAM_SERVICE "xlock"
164 # define PAM_ERROR_PRINT(pamfunc) \
166 fprintf(stderr, "%s: %s failure: %s\n", ProgramName, pamfunc, \
167 pam_strerror(pamh, pam_error)); \
174 char *ProgramName
; /* argv[0] */
175 perscreen Scr
[MAXSCREENS
];
176 Display
*dsp
= NULL
; /* server display connection */
177 int screen
; /* current screen */
178 void (*callback
) (Window win
) = NULL
;
179 void (*init
) (Window win
) = NULL
;
180 static void (*exp_bzero
) (void *s
, size_t n
);
181 #define EXPLICIT_BZERO(s, n) (*exp_bzero)(s, n)
183 static int screens
; /* number of screens */
184 static Window win
[MAXSCREENS
]; /* window used to cover screen */
185 static Window icon
[MAXSCREENS
]; /* window used during password typein */
186 static Window root
[MAXSCREENS
]; /* convenience pointer to the root window */
187 static GC textgc
[MAXSCREENS
]; /* graphics context used for text rendering */
188 static XColor fgcol
[MAXSCREENS
];/* used for text rendering */
189 static XColor bgcol
[MAXSCREENS
];/* background of text screen */
190 XColor ssblack
[MAXSCREENS
];/* black color for screen saver screen */
191 XColor sswhite
[MAXSCREENS
];/* white color for screen saver screen */
192 static int iconx
[MAXSCREENS
]; /* location of left edge of icon */
193 static int icony
[MAXSCREENS
]; /* location of top edge of icon */
194 static Cursor mycursor
; /* blank cursor */
195 static Cursor passwdcursor
; /* cursor used in getPassword */
197 static Pixmap lockm
; /* pixmaps for cursor and mask */
198 static char no_bits
[] = {0}; /* dummy array for the blank cursor */
199 static int passx
; /* position of the ?'s */
201 static XFontStruct
*font
;
202 static int sstimeout
; /* screen saver parameters */
203 static int ssinterval
;
204 static int ssblanking
;
205 static int ssexposures
;
207 static char buffer
[PAM_MAX_RESP_SIZE
];
208 static Bool reallyechokeys
= False
; /* Echo real keys instead of ?'s */
209 static Bool stoptryingfornow
= False
;
211 #define FALLBACK_FONTNAME "fixed"
216 #define WIDTH WidthOfScreen(scr) - 100
217 #define HEIGHT HeightOfScreen(scr) - 100
218 #define CWMASK CWBackPixel | CWEventMask | CWColormap
220 #define WIDTH WidthOfScreen(scr)
221 #define HEIGHT HeightOfScreen(scr)
222 #define CWMASK CWOverrideRedirect | CWBackPixel | CWEventMask | CWColormap
225 #define AllPointerEventMask \
226 (ButtonPressMask | ButtonReleaseMask | \
227 EnterWindowMask | LeaveWindowMask | \
228 PointerMotionMask | PointerMotionHintMask | \
229 Button1MotionMask | Button2MotionMask | \
230 Button3MotionMask | Button4MotionMask | \
231 Button5MotionMask | ButtonMotionMask | \
235 error(const char *format
, ...)
239 fprintf(stderr
, "%s: ", ProgramName
);
240 va_start(args
, format
);
241 vfprintf(stderr
, format
, args
);
247 * Server access control support.
250 static XHostAddress
*XHosts
; /* the list of "friendly" client machines */
251 static int HostAccessCount
; /* the number of machines in XHosts */
252 static Bool HostAccessState
; /* whether or not we even look at the list */
255 XGrabHosts(Display
*dsp
)
257 XHosts
= XListHosts(dsp
, &HostAccessCount
, &HostAccessState
);
259 XRemoveHosts(dsp
, XHosts
, HostAccessCount
);
260 XEnableAccessControl(dsp
);
264 XUngrabHosts(Display
*dsp
)
267 XAddHosts(dsp
, XHosts
, HostAccessCount
);
270 if (HostAccessState
== False
)
271 XDisableAccessControl(dsp
);
276 * Simple wrapper to get an asynchronous grab on the keyboard and mouse.
277 * If either grab fails, we sleep for one second and try again since some
278 * window manager might have had the mouse grabbed to drive the menu choice
279 * that picked "Lock Screen..". If either one fails the second time we print
280 * an error message and exit.
283 GrabKeyboardAndMouse(void)
287 status
= XGrabKeyboard(dsp
, win
[0], True
,
288 GrabModeAsync
, GrabModeAsync
, CurrentTime
);
289 if (status
!= GrabSuccess
) {
291 status
= XGrabKeyboard(dsp
, win
[0], True
,
292 GrabModeAsync
, GrabModeAsync
, CurrentTime
);
294 if (status
!= GrabSuccess
)
295 error("couldn't grab keyboard! (%d)\n", status
);
297 status
= XGrabPointer(dsp
, win
[0], True
, AllPointerEventMask
,
298 GrabModeAsync
, GrabModeAsync
, None
, mycursor
,
300 if (status
!= GrabSuccess
) {
302 status
= XGrabPointer(dsp
, win
[0], True
, AllPointerEventMask
,
303 GrabModeAsync
, GrabModeAsync
, None
, mycursor
,
306 if (status
!= GrabSuccess
)
307 error("couldn't grab pointer! (%d)\n", status
);
313 * Assuming that we already have an asynch grab on the pointer,
314 * just grab it again with a new cursor shape and ignore the return code.
317 XChangeGrabbedCursor(Cursor cursor
)
320 (void) XGrabPointer(dsp
, win
[0], True
, AllPointerEventMask
,
321 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
327 * Restore all grabs, reset screensaver, restore colormap, close connection.
333 if (!nolock
&& !allowaccess
)
335 XUngrabPointer(dsp
, CurrentTime
);
336 XUngrabKeyboard(dsp
, CurrentTime
);
338 XSetScreenSaver(dsp
, sstimeout
, ssinterval
, ssblanking
, ssexposures
);
344 static volatile int sigcaught
= 0;
347 sigcatch(int sig
, siginfo_t
*info
, void *context
)
349 NOTE(ARGUNUSED(context
))
350 /* note that we were caught, but don't try to re-enter Xlib from here */
352 psiginfo(info
, ProgramName
);
355 static void _X_NORETURN
359 error("caught terminate signal %d.\nAccess control list restored.\n",
376 int thisscreen
= screen
;
377 char pwbuf
[PAM_MAX_RESP_SIZE
];
379 for (screen
= 0; screen
< screens
; screen
++)
380 if (thisscreen
== screen
)
388 long lasteventtime
= seconds();
389 while (!XPending(dsp
)) {
392 for (screen
= 0; screen
< screens
; screen
++)
393 if (thisscreen
== screen
)
394 callback(icon
[screen
]);
396 callback(win
[screen
]);
398 usleep((useconds_t
) delay
);
399 if (seconds() - lasteventtime
> (long) timeout
) {
401 stoptryingfornow
= True
;
406 XNextEvent(dsp
, &event
);
409 switch (event
.type
) {
411 len
= XLookupString((XKeyEvent
*) & event
, keystr
, 20, NULL
, NULL
);
412 for (i
= 0; i
< len
; i
++) {
424 * eat all events if there are more than enough pending... this
425 * keeps the Xlib event buffer from growing larger than all
426 * available memory and crashing xlock.
428 if (XPending(dsp
) > 100) { /* 100 is arbitrarily big enough */
429 register Status status
;
431 status
= XCheckMaskEvent(dsp
,
432 KeyPressMask
| KeyReleaseMask
, &event
);
445 XSync(dsp
, True
); /* flush input buffer */
448 XSetForeground(dsp
, Scr
[screen
].gc
, bgcol
[screen
].pixel
);
449 if (echokeys
|| reallyechokeys
) {
450 if (reallyechokeys
) {
451 memcpy(pwbuf
, s
, slen
);
453 memset(pwbuf
, '?', slen
);
456 XFillRectangle(dsp
, win
[screen
], Scr
[screen
].gc
,
457 passx
, passy
- font
->ascent
,
458 XTextWidth(font
, pwbuf
, (int) slen
),
459 font
->ascent
+ font
->descent
);
460 XDrawString(dsp
, win
[screen
], textgc
[screen
],
461 passx
, passy
, pwbuf
, bp
);
464 * eat all events if there are more than enough pending... this
465 * keeps the Xlib event buffer from growing larger than all
466 * available memory and crashing xlock.
468 if (XPending(dsp
) > 100) { /* 100 is arbitrarily big enough */
469 register Status status
;
471 status
= XCheckMaskEvent(dsp
,
472 KeyPressMask
| KeyReleaseMask
, &event
);
479 if (((XButtonEvent
*) & event
)->window
== icon
[screen
]) {
480 stoptryingfornow
= True
;
485 case VisibilityNotify
:
486 if (event
.xvisibility
.state
!= VisibilityUnobscured
) {
488 XRaiseWindow(dsp
, win
[screen
]);
504 fprintf(stderr
, "%s: unexpected event: %d\n",
505 ProgramName
, event
.type
);
513 static void passwordPrompt(const char *prompt
)
516 Screen
*scr
= ScreenOfDisplay(dsp
, screen
);
518 left
= iconx
[screen
] + ICONW
+ font
->max_bounds
.width
;
519 y
= icony
[screen
] + font
->ascent
+ font
->ascent
+ font
->descent
+ 2;
521 XSetForeground(dsp
, Scr
[screen
].gc
, bgcol
[screen
].pixel
);
523 XFillRectangle(dsp
, win
[screen
], Scr
[screen
].gc
,
524 left
, y
- font
->ascent
, WIDTH
- left
,
525 font
->ascent
+ font
->descent
+ 2);
527 XDrawString(dsp
, win
[screen
], textgc
[screen
],
528 left
, y
, prompt
, (int) strlen(prompt
));
529 XDrawString(dsp
, win
[screen
], textgc
[screen
],
530 left
+ 1, y
, prompt
, (int) strlen(prompt
));
532 passx
= left
+ 1 + XTextWidth(font
, prompt
, (int) strlen(prompt
))
533 + XTextWidth(font
, " ", 1);
537 static void displayTextInfo(const char *infoMsg
)
540 Screen
*scr
= ScreenOfDisplay(dsp
, screen
);
542 y
= icony
[screen
] + ICONH
+ font
->ascent
+ 2;
544 XSetForeground(dsp
, Scr
[screen
].gc
, bgcol
[screen
].pixel
);
546 XFillRectangle(dsp
, win
[screen
], Scr
[screen
].gc
,
547 iconx
[screen
], y
- font
->ascent
,
548 WIDTH
- iconx
[screen
],
549 font
->ascent
+ font
->descent
+ 2);
551 XDrawString(dsp
, win
[screen
], textgc
[screen
],
552 iconx
[screen
], y
, infoMsg
, (int) strlen(infoMsg
));
556 static int pamconv(int num_msg
, struct pam_message
**msg
,
557 struct pam_response
**response
, void *appdata_ptr
)
559 NOTE(ARGUNUSED(appdata_ptr
))
561 int status
= PAM_SUCCESS
;
563 struct pam_message
*m
;
564 struct pam_response
*r
;
566 *response
= calloc(num_msg
, sizeof (struct pam_response
));
567 if (*response
== NULL
)
568 return (PAM_BUF_ERR
);
573 for (i
= 0; i
< num_msg
; i
++ , m
++ , r
++) {
576 fprintf(stderr
, "pam_msg: %d: '%s'\n", m
->msg_style
, m
->msg
);
579 switch (m
->msg_style
) {
582 displayTextInfo(m
->msg
);
585 case PAM_PROMPT_ECHO_ON
:
586 reallyechokeys
= True
;
588 case PAM_PROMPT_ECHO_OFF
:
589 passwordPrompt(m
->msg
);
590 if (ReadXString(buffer
, PAM_MAX_RESP_SIZE
)) {
591 /* timeout or other error */
592 status
= PAM_CONV_ERR
;
595 r
->resp
= strdup(buffer
);
596 if (r
->resp
== NULL
) {
597 status
= PAM_BUF_ERR
;
602 fprintf(stderr
, "pam_resp: '%s'\n", r
->resp
);
606 reallyechokeys
= False
;
611 fprintf(stderr
, "%s: Unknown PAM msg_style: %d\n",
612 ProgramName
, m
->msg_style
);
616 if (status
!= PAM_SUCCESS
) {
619 for (i
= 0; i
< num_msg
; i
++, r
++) {
633 #include <bsm/adt_event.h>
637 * audit_lock - audit entry to screenlock
639 * Entry Process running with appropriate privilege to generate
640 * audit records and real uid of the user.
642 * Exit ADT_screenlock audit record written.
647 adt_session_data_t
*ah
; /* audit session handle */
648 adt_event_data_t
*event
; /* audit event handle */
650 /* Audit start of screen lock -- equivalent to logout ;-) */
652 if (adt_start_session(&ah
, NULL
, ADT_USE_PROC_DATA
) != 0) {
654 syslog(LOG_AUTH
| LOG_ALERT
, "adt_start_session: %m");
657 if ((event
= adt_alloc_event(ah
, ADT_screenlock
)) == NULL
) {
659 syslog(LOG_AUTH
| LOG_ALERT
,
660 "adt_alloc_event(ADT_screenlock): %m");
662 if (adt_put_event(event
, ADT_SUCCESS
, ADT_SUCCESS
) != 0) {
664 syslog(LOG_AUTH
| LOG_ALERT
,
665 "adt_put_event(ADT_screenlock): %m");
667 adt_free_event(event
);
669 (void) adt_end_session(ah
);
674 * audit_unlock - audit screen unlock
676 * Entry Process running with appropriate privilege to generate
677 * audit records and real uid of the user.
678 * pam_status = PAM error code; reason for failure.
680 * Exit ADT_screenunlock audit record written.
683 audit_unlock(int pam_status
)
685 adt_session_data_t
*ah
; /* audit session handle */
686 adt_event_data_t
*event
; /* audit event handle */
688 if (adt_start_session(&ah
, NULL
, ADT_USE_PROC_DATA
) != 0) {
690 syslog(LOG_AUTH
| LOG_ALERT
,
691 "adt_start_session(ADT_screenunlock): %m");
694 if ((event
= adt_alloc_event(ah
, ADT_screenunlock
)) == NULL
) {
696 syslog(LOG_AUTH
| LOG_ALERT
,
697 "adt_alloc_event(ADT_screenunlock): %m");
699 if (adt_put_event(event
,
700 pam_status
== PAM_SUCCESS
? ADT_SUCCESS
: ADT_FAILURE
,
701 pam_status
== PAM_SUCCESS
? ADT_SUCCESS
: ADT_FAIL_PAM
+
704 syslog(LOG_AUTH
| LOG_ALERT
,
705 "adt_put_event(ADT_screenunlock(%s): %m",
706 pam_strerror(NULL
, pam_status
));
708 adt_free_event(event
);
710 (void) adt_end_session(ah
);
715 * audit_passwd - audit password change
716 * Entry Process running with appropriate privilege to generate
717 * audit records and real uid of the user.
718 * pam_status = PAM error code; reason for failure.
720 * Exit ADT_passwd audit record written.
723 audit_passwd(int pam_status
)
725 adt_session_data_t
*ah
; /* audit session handle */
726 adt_event_data_t
*event
; /* audit event handle */
728 if (adt_start_session(&ah
, NULL
, ADT_USE_PROC_DATA
) != 0) {
730 syslog(LOG_AUTH
| LOG_ALERT
,
731 "adt_start_session(ADT_passwd): %m");
734 if ((event
= adt_alloc_event(ah
, ADT_passwd
)) == NULL
) {
736 syslog(LOG_AUTH
| LOG_ALERT
,
737 "adt_alloc_event(ADT_passwd): %m");
739 if (adt_put_event(event
,
740 pam_status
== PAM_SUCCESS
? ADT_SUCCESS
: ADT_FAILURE
,
741 pam_status
== PAM_SUCCESS
? ADT_SUCCESS
: ADT_FAIL_PAM
+
744 syslog(LOG_AUTH
| LOG_ALERT
,
745 "adt_put_event(ADT_passwd(%s): %m",
746 pam_strerror(NULL
, pam_status
));
748 adt_free_event(event
);
750 (void) adt_end_session(ah
);
757 char *userpass
= NULL
;
758 char *rootpass
= NULL
;
759 XWindowAttributes xgwa
;
761 struct spwd
*rspw
, *uspw
;
762 char *suserpass
= NULL
;
763 char *srootpass
= NULL
;
765 struct passwd
*rpw
, *upw
;
767 pam_handle_t
*pamh
= NULL
;
773 const char *authErrMsg
= text_invalid
;
780 rootpass
= strdup(rpw
->pw_passwd
);
782 rspw
= getspnam(user
);
783 if (rspw
&& rspw
->sp_pwdp
)
784 srootpass
= strdup(rspw
->sp_pwdp
);
787 upw
= getpwuid(getuid());
797 pam_error
= pam_start(XLOCK_PAM_SERVICE
, user
, &pc
, &pamh
);
798 if (pam_error
!= PAM_SUCCESS
) {
800 PAM_ERROR_PRINT("pam_start");
803 /* Check /etc/default/login to see if we should add
804 PAM_DISALLOW_NULL_AUTHTOK to pam_flags */
805 if (defopen("/etc/default/login") == 0) {
808 int flags
= defcntl(DC_GETFLAGS
, 0);
809 TURNOFF(flags
, DC_CASE
);
810 (void) defcntl(DC_SETFLAGS
, flags
);
812 if ((ptr
= defread("PASSREQ=")) != NULL
&&
813 strcasecmp("YES", ptr
) == 0) {
814 pam_flags
|= PAM_DISALLOW_NULL_AUTHTOK
;
817 (void) defopen(NULL
); /* close current file */
826 /* Get user password for non-PAM authentication */
827 userpass
= strdup(upw
->pw_passwd
);
829 uspw
= getspnam(user
);
830 if (uspw
&& uspw
->sp_pwdp
)
831 suserpass
= strdup(uspw
->sp_pwdp
);
836 XGetWindowAttributes(dsp
, win
[screen
], &xgwa
);
838 XChangeGrabbedCursor(passwdcursor
);
840 XSetForeground(dsp
, Scr
[screen
].gc
, bgcol
[screen
].pixel
);
841 XFillRectangle(dsp
, win
[screen
], Scr
[screen
].gc
,
842 0, 0, xgwa
.width
, xgwa
.height
);
844 XMapWindow(dsp
, icon
[screen
]);
845 XRaiseWindow(dsp
, icon
[screen
]);
847 left
= iconx
[screen
] + ICONW
+ font
->max_bounds
.width
;
848 y
= icony
[screen
] + font
->ascent
;
850 XDrawString(dsp
, win
[screen
], textgc
[screen
],
851 left
, y
, text_name
, (int) strlen(text_name
));
852 XDrawString(dsp
, win
[screen
], textgc
[screen
],
853 left
+ 1, y
, text_name
, (int) strlen(text_name
));
854 XDrawString(dsp
, win
[screen
], textgc
[screen
],
855 left
+ XTextWidth(font
, text_name
, (int) strlen(text_name
)), y
,
856 user
, (int) strlen(user
));
858 y
= icony
[screen
] - (font
->descent
+ 2);
860 XDrawString(dsp
, win
[screen
], textgc
[screen
],
861 iconx
[screen
], y
, text_info
, (int) strlen(text_info
));
863 passwordPrompt(text_pass
);
867 y
= icony
[screen
] + ICONH
+ font
->ascent
+ 2
868 + font
->ascent
+ font
->descent
+ 2;
871 stoptryingfornow
= False
;
879 pam_error
= pam_authenticate(pamh
, pam_flags
);
880 if (pam_error
== PAM_SUCCESS
) {
881 const char *pam_error_from
= "pam_acct_mgmt";
883 pam_error
= pam_acct_mgmt(pamh
, pam_flags
);
885 if (pam_error
== PAM_NEW_AUTHTOK_REQD
) {
887 pam_error
= pam_chauthtok(pamh
,
888 PAM_CHANGE_EXPIRED_AUTHTOK
);
889 } while (pam_error
== PAM_AUTHTOK_ERR
||
890 pam_error
== PAM_TRY_AGAIN
);
891 pam_error_from
= "pam_chauthtok";
893 audit_passwd(pam_error
);
897 if (pam_error
== PAM_SUCCESS
) {
898 pam_error
= pam_setcred(pamh
,PAM_REFRESH_CRED
);
899 if (pam_error
!= PAM_SUCCESS
) {
900 PAM_ERROR_PRINT("pam_setcred(PAM_REFRESH_CRED)");
906 audit_unlock(pam_error
);
908 PAM_ERROR_PRINT(pam_error_from
);
910 } else if (stoptryingfornow
) {
915 audit_unlock(pam_error
);
917 PAM_ERROR_PRINT("pam_authenticate");
920 if (pam_error
!= PAM_SUCCESS
) {
921 authErrMsg
= pam_strerror(pamh
, pam_error
);
925 } else if (ReadXString(buffer
, PAM_MAX_RESP_SIZE
))
930 * This section gets a little messy. In SYSV, the number of
931 * cases to handle increases because of the existence of the
932 * shadow file. There are also a number of cases that need
933 * to be dealt with where either root or user passwords are
934 * nil. Hopefully the code below is easy enough to follow.
938 if (*userpass
== '\0') {
939 done
= (*buffer
== '\0');
941 done
= (!strcmp(crypt(buffer
, userpass
), userpass
));
944 if (!done
&& suserpass
) {
945 if (*suserpass
== '\0') {
946 done
= (*buffer
== '\0');
948 done
= (!strcmp(crypt(buffer
, suserpass
), suserpass
));
951 if (!done
&& allowroot
) {
953 if (*srootpass
== '\0') {
954 done
= (*buffer
== '\0');
956 done
= (!strcmp(crypt(buffer
, srootpass
), srootpass
));
959 if (!done
&& rootpass
) {
960 if (*rootpass
== '\0') {
961 done
= (*buffer
== '\0');
963 done
= (!strcmp(crypt(buffer
, rootpass
), rootpass
));
968 /* clear plaintext password so you can't grunge around /dev/kmem */
969 EXPLICIT_BZERO(buffer
, sizeof(buffer
));
971 displayTextInfo(text_valid
);
974 /* clear encrypted passwords just in case */
976 EXPLICIT_BZERO(rootpass
, strlen(rootpass
));
981 EXPLICIT_BZERO(userpass
, strlen(userpass
));
986 EXPLICIT_BZERO(srootpass
, strlen(srootpass
));
991 EXPLICIT_BZERO(suserpass
, strlen(suserpass
));
998 audit_unlock(pam_error
);
1000 pam_end(pamh
, pam_error
);
1005 XSync(dsp
, True
); /* flush input buffer */
1008 displayTextInfo(authErrMsg
);
1010 if (echokeys
|| reallyechokeys
) /* erase old echo */
1011 XFillRectangle(dsp
, win
[screen
], Scr
[screen
].gc
,
1012 passx
, passy
- font
->ascent
,
1014 font
->ascent
+ font
->descent
);
1017 /* clear encrypted passwords just in case */
1019 EXPLICIT_BZERO(rootpass
, strlen(rootpass
));
1024 EXPLICIT_BZERO(userpass
, strlen(userpass
));
1029 EXPLICIT_BZERO(srootpass
, strlen(srootpass
));
1034 EXPLICIT_BZERO(suserpass
, strlen(suserpass
));
1040 pam_end(pamh
, pam_error
);
1043 XChangeGrabbedCursor(mycursor
);
1044 XUnmapWindow(dsp
, icon
[screen
]);
1053 for (screen
= 0; screen
< screens
; screen
++)
1056 while (!XPending(dsp
)) {
1059 for (screen
= 0; screen
< screens
; screen
++)
1060 callback(win
[screen
]);
1062 usleep((useconds_t
) delay
);
1064 XNextEvent(dsp
, &event
);
1068 if (event
.type
== VisibilityNotify
)
1069 XRaiseWindow(dsp
, event
.xany
.window
);
1071 } while (event
.type
!= ButtonPress
&& event
.type
!= KeyPress
);
1072 for (screen
= 0; screen
< screens
; screen
++)
1073 if (event
.xbutton
.root
== RootWindow(dsp
, screen
))
1076 XPutBackEvent(dsp
, &event
);
1084 sigset_t oldsigmask
;
1085 sigset_t newsigmask
;
1086 struct sigaction sigact
;
1088 sigemptyset(&newsigmask
);
1089 sigaddset(&newsigmask
, SIGHUP
);
1090 sigaddset(&newsigmask
, SIGINT
);
1091 sigaddset(&newsigmask
, SIGQUIT
);
1092 sigaddset(&newsigmask
, SIGTERM
);
1093 sigprocmask(SIG_BLOCK
, &newsigmask
, &oldsigmask
);
1095 sigact
.sa_sigaction
= sigcatch
;
1096 sigact
.sa_mask
= newsigmask
;
1097 sigact
.sa_flags
= SA_SIGINFO
;
1099 sigaction(SIGHUP
, &sigact
, NULL
);
1100 sigaction(SIGINT
, &sigact
, NULL
);
1101 sigaction(SIGQUIT
, &sigact
, NULL
);
1102 sigaction(SIGTERM
, &sigact
, NULL
);
1106 sigprocmask(SIG_SETMASK
, &oldsigmask
, &oldsigmask
);
1115 } while (getPassword());
1125 XSetWindowAttributes xswa
;
1128 if ((geteuid() != 0) || (seteuid(getuid()) != 0)) {
1129 error("Not running with root privileges. Exiting ...\n"
1130 "\tYou need to run xlock in setuid root mode on your local machine.\n"
1131 "\tContact your system administrator.\n");
1134 ProgramName
= strrchr(argv
[0], '/');
1138 ProgramName
= argv
[0];
1140 srandom((uint_t
) time((long *) 0)); /* random mode needs the seed set. */
1143 (void (*)(void *, size_t)) dlsym(RTLD_DEFAULT
, "explicit_bzero");
1144 if (exp_bzero
== NULL
) {
1145 /* If the explicit version isn't found, at least the compilers we
1146 use won't optimize out a call to a function found via dlsym(). */
1147 exp_bzero
= (void (*)(void *, size_t)) dlsym(RTLD_DEFAULT
, "bzero");
1148 if (exp_bzero
== NULL
) {
1149 const char *dle
= dlerror();
1150 char errmsg
[BUFSIZ
];
1152 snprintf(errmsg
, sizeof(errmsg
), "%s\n Exiting ...\n", dle
);
1157 GetResources(argc
, argv
);
1161 font
= XLoadQueryFont(dsp
, fontname
);
1163 fprintf(stderr
, "%s: can't find font: %s, using %s...\n",
1164 ProgramName
, fontname
, FALLBACK_FONTNAME
);
1165 font
= XLoadQueryFont(dsp
, FALLBACK_FONTNAME
);
1167 error("can't even find %s!!!\n", FALLBACK_FONTNAME
);
1170 screens
= ScreenCount(dsp
);
1171 if (screens
> MAXSCREENS
)
1172 error("can only support %d screens.\n", MAXSCREENS
);
1173 for (screen
= 0; screen
< screens
; screen
++) {
1175 Screen
*scr
= ScreenOfDisplay(dsp
, screen
);
1176 Visual
*vis
= XDefaultVisual(dsp
, screen
);
1178 root
[screen
] = RootWindowOfScreen(scr
);
1180 cmap
= XCreateColormap(dsp
, root
[screen
], vis
, AllocNone
);
1182 XAllocNamedColor(dsp
, cmap
, "White", &sswhite
[screen
], &tmp
);
1183 XAllocNamedColor(dsp
, cmap
, "Black", &ssblack
[screen
], &tmp
);
1185 if (mono
|| CellsOfScreen(scr
) == 2) {
1186 if (!XAllocNamedColor(dsp
, cmap
, background
,
1187 &bgcol
[screen
], &tmp
)) {
1188 XAllocNamedColor(dsp
, cmap
, "White", &bgcol
[screen
], &tmp
);
1190 if (!XAllocNamedColor(dsp
, cmap
, foreground
,
1191 &fgcol
[screen
], &tmp
)) {
1192 XAllocNamedColor(dsp
, cmap
, "Black", &fgcol
[screen
], &tmp
);
1194 Scr
[screen
].pixels
[0] = fgcol
[screen
].pixel
;
1195 Scr
[screen
].pixels
[1] = bgcol
[screen
].pixel
;
1196 Scr
[screen
].npixels
= 2;
1198 int colorcount
= NUMCOLORS
;
1199 u_char red
[NUMCOLORS
];
1200 u_char green
[NUMCOLORS
];
1201 u_char blue
[NUMCOLORS
];
1204 if (!XAllocNamedColor(dsp
, cmap
, background
,
1205 &bgcol
[screen
], &tmp
)) {
1206 fprintf(stderr
, "couldn't allocate: %s\n", background
);
1207 XAllocNamedColor(dsp
, cmap
, "White", &bgcol
[screen
], &tmp
);
1209 if (!XAllocNamedColor(dsp
, cmap
, foreground
,
1210 &fgcol
[screen
], &tmp
)) {
1211 fprintf(stderr
, "couldn't allocate: %s\n", foreground
);
1212 XAllocNamedColor(dsp
, cmap
, "Black", &fgcol
[screen
], &tmp
);
1214 hsbramp(0.0, saturation
, 1.0, 1.0, saturation
, 1.0, colorcount
,
1216 Scr
[screen
].npixels
= 0;
1217 for (i
= 0; i
< colorcount
; i
++) {
1219 .red
= (unsigned short) (red
[i
] << 8),
1220 .green
= (unsigned short) (green
[i
] << 8),
1221 .blue
= (unsigned short) (blue
[i
] << 8),
1222 .flags
= DoRed
| DoGreen
| DoBlue
1225 if (!XAllocColor(dsp
, cmap
, &xcolor
))
1228 Scr
[screen
].pixels
[i
] = xcolor
.pixel
;
1229 Scr
[screen
].npixels
++;
1232 fprintf(stderr
, "%d pixels allocated\n", Scr
[screen
].npixels
);
1235 xswa
.override_redirect
= True
;
1236 xswa
.background_pixel
= ssblack
[screen
].pixel
;
1237 xswa
.event_mask
= KeyPressMask
| ButtonPressMask
| VisibilityChangeMask
;
1238 xswa
.colormap
= cmap
; /* In DEBUG mode, we do not see this */
1240 win
[screen
] = XCreateWindow(dsp
, root
[screen
], 0, 0, WIDTH
, HEIGHT
, 0,
1241 CopyFromParent
, InputOutput
, CopyFromParent
,
1248 xwmh
.flags
= InputHint
;
1250 XChangeProperty(dsp
, win
[screen
],
1251 XA_WM_HINTS
, XA_WM_HINTS
, 32, PropModeReplace
,
1252 (unsigned char *) &xwmh
, sizeof(xwmh
) / sizeof(int));
1256 iconx
[screen
] = (DisplayWidth(dsp
, screen
) -
1257 XTextWidth(font
, text_info
, (int) strlen(text_info
))) / 2;
1259 icony
[screen
] = DisplayHeight(dsp
, screen
) / 6;
1261 xswa
.border_pixel
= fgcol
[screen
].pixel
;
1262 xswa
.background_pixel
= bgcol
[screen
].pixel
;
1263 xswa
.event_mask
= ButtonPressMask
;
1264 xswa
.colormap
= cmap
; /* In DEBUG mode, we do not see this */
1266 #define CIMASK CWBorderPixel | CWBackPixel | CWEventMask | CWColormap
1267 icon
[screen
] = XCreateWindow(dsp
, win
[screen
],
1268 iconx
[screen
], icony
[screen
],
1269 ICONW
, ICONH
, 1, CopyFromParent
,
1270 InputOutput
, CopyFromParent
,
1273 XMapWindow(dsp
, win
[screen
]);
1274 XRaiseWindow(dsp
, win
[screen
]);
1275 XInstallColormap(dsp
, cmap
);
1277 xgcv
.foreground
= sswhite
[screen
].pixel
;
1278 xgcv
.background
= ssblack
[screen
].pixel
;
1279 Scr
[screen
].gc
= XCreateGC(dsp
, win
[screen
],
1280 GCForeground
| GCBackground
, &xgcv
);
1282 xgcv
.foreground
= fgcol
[screen
].pixel
;
1283 xgcv
.background
= bgcol
[screen
].pixel
;
1284 xgcv
.font
= font
->fid
;
1285 textgc
[screen
] = XCreateGC(dsp
, win
[screen
],
1286 GCFont
| GCForeground
| GCBackground
, &xgcv
);
1288 lockc
= XCreateBitmapFromData(dsp
, root
[0], no_bits
, 1, 1);
1289 lockm
= XCreateBitmapFromData(dsp
, root
[0], no_bits
, 1, 1);
1290 mycursor
= XCreatePixmapCursor(dsp
, lockc
, lockm
,
1291 &fgcol
[screen
], &bgcol
[screen
], 0, 0);
1292 passwdcursor
= XCreateFontCursor(dsp
, XC_left_ptr
);
1293 XFreePixmap(dsp
, lockc
);
1294 XFreePixmap(dsp
, lockm
);
1298 XGetScreenSaver(dsp
, &sstimeout
, &ssinterval
,
1299 &ssblanking
, &ssexposures
);
1300 XSetScreenSaver(dsp
, 0, 0, 0, 0); /* disable screen saver */
1303 GrabKeyboardAndMouse();