6 * Copyright (C)1993,1994 Ian Jackson
8 * This is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * This is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
21 #include <X11/Xutil.h>
22 #include <X11/keysym.h>
27 #include <sys/types.h>
44 #include "lock.bitmap"
45 #include "mask.bitmap"
46 #include "patchlevel.h"
51 #define TIMEOUTPERATTEMPT 30000
52 #define MAXGOODWILL (TIMEOUTPERATTEMPT*5)
53 #define INITIALGOODWILL MAXGOODWILL
54 #define GOODWILLPORTION 0.3
57 int passwordok(const char *s) {
62 key[0] = *(pw->pw_passwd);
63 key[1] = (pw->pw_passwd)[1];
66 return !strcmp(encr, pw->pw_passwd);
68 /* simpler, and should work with crypt() algorithms using longer
69 salt strings (like the md5-based one on freebsd). --marekm */
70 return !strcmp(crypt(s, pw->pw_passwd), pw->pw_passwd);
74 int main(int argc, char **argv){
77 char cbuf[10], rbuf[128]; /* shadow appears to suggest 127 a good value here */
79 long goodwill= INITIALGOODWILL, timeout= 0;
80 XSetWindowAttributes attrib;
82 Pixmap csr_source,csr_mask;
83 XColor csr_fg, csr_bg, dummy, black;
84 int ret, screen, blank = 0, fork_after = 0;
92 if ((strcmp(argv[1], "-b") == 0)) {
96 } else if ((strcmp(argv[1], "-f") == 0)) {
101 fprintf(stderr,"xtrlock (version %s); usage: xtrlock [-b] [-f]\n",
107 errno=0; pw= getpwuid(getuid());
108 if (!pw) { perror("password entry for uid not found"); exit(1); }
110 sp = getspnam(pw->pw_name);
112 pw->pw_passwd = sp->sp_pwdp;
116 /* logically, if we need to do the following then the same
117 applies to being installed setgid shadow.
118 we do this first, because of a bug in linux. --jdamery */
119 if (setgid(getgid())) { perror("setgid"); exit(1); }
120 /* we can be installed setuid root to support shadow passwords,
121 and we don't need root privileges any longer. --marekm */
122 if (setuid(getuid())) { perror("setuid"); exit(1); }
124 if (strlen(pw->pw_passwd) < 13) {
125 fputs("password entry has no pwd\n",stderr); exit(1);
128 display= XOpenDisplay(0);
131 fprintf(stderr,"xtrlock (version %s): cannot open display\n",
136 attrib.override_redirect= True;
139 screen = DefaultScreen(display);
140 attrib.background_pixel = BlackPixel(display, screen);
141 window= XCreateWindow(display,DefaultRootWindow(display),
142 0,0,DisplayWidth(display, screen),DisplayHeight(display, screen),
143 0,DefaultDepth(display, screen), CopyFromParent, DefaultVisual(display, screen),
144 CWOverrideRedirect|CWBackPixel,&attrib);
145 XAllocNamedColor(display, DefaultColormap(display, screen), "black", &black, &dummy);
147 window= XCreateWindow(display,DefaultRootWindow(display),
148 0,0,1,1,0,CopyFromParent,InputOnly,CopyFromParent,
149 CWOverrideRedirect,&attrib);
152 XSelectInput(display,window,KeyPressMask|KeyReleaseMask);
154 csr_source= XCreateBitmapFromData(display,window,lock_bits,lock_width,lock_height);
155 csr_mask= XCreateBitmapFromData(display,window,mask_bits,mask_width,mask_height);
157 ret = XAllocNamedColor(display,
158 DefaultColormap(display, DefaultScreen(display)),
162 XAllocNamedColor(display,
163 DefaultColormap(display, DefaultScreen(display)),
167 ret = XAllocNamedColor(display,
168 DefaultColormap(display,DefaultScreen(display)),
172 XAllocNamedColor(display,
173 DefaultColormap(display, DefaultScreen(display)),
179 cursor= XCreatePixmapCursor(display,csr_source,csr_mask,&csr_fg,&csr_bg,
180 lock_x_hot,lock_y_hot);
182 XMapWindow(display,window);
184 /*Sometimes the WM doesn't ungrab the keyboard quickly enough if
185 *launching xtrlock from a keystroke shortcut, meaning xtrlock fails
186 *to start We deal with this by waiting (up to 100 times) for 10,000
187 *microsecs and trying to grab each time. If we still fail
188 *(i.e. after 1s in total), then give up, and emit an error
191 gs=0; /*gs==grab successful*/
192 for (tvt=0 ; tvt<100; tvt++) {
193 ret = XGrabKeyboard(display,window,False,GrabModeAsync,GrabModeAsync,
195 if (ret == GrabSuccess) {
199 /*grab failed; wait .01s*/
202 select(1,NULL,NULL,NULL,&tv);
205 fprintf(stderr,"xtrlock (version %s): cannot grab keyboard\n",
210 if (XGrabPointer(display,window,False,(KeyPressMask|KeyReleaseMask)&0,
211 GrabModeAsync,GrabModeAsync,None,
212 cursor,CurrentTime)!=GrabSuccess) {
213 XUngrabKeyboard(display,CurrentTime);
214 fprintf(stderr,"xtrlock (version %s): cannot grab pointer\n",
222 fprintf(stderr,"xtrlock (version %s): cannot fork: %s\n",
223 program_version, strerror(errno));
225 } else if (pid > 0) {
231 XNextEvent(display,&ev);
234 if (ev.xkey.time < timeout) { XBell(display,0); break; }
235 clen= XLookupString(&ev.xkey,cbuf,9,&ks,0);
237 case XK_Escape: case XK_Clear:
239 case XK_Delete: case XK_BackSpace:
242 case XK_Linefeed: case XK_Return:
245 if (passwordok(rbuf)) goto loop_x;
249 goodwill+= ev.xkey.time - timeout;
250 if (goodwill > MAXGOODWILL) {
251 goodwill= MAXGOODWILL;
254 timeout= -goodwill*GOODWILLPORTION;
256 timeout+= ev.xkey.time + TIMEOUTPERATTEMPT;
259 if (clen != 1) break;
260 /* allow space for the trailing \0 */
261 if (rlen < (sizeof(rbuf) - 1)){