1 /* See LICENSE file for license details. */
2 #define _XOPEN_SOURCE 500
15 #include <sys/types.h>
16 #include <X11/extensions/Xrandr.h>
17 #include <X11/keysym.h>
19 #include <X11/Xutil.h>
22 #include <login_cap.h>
44 unsigned long colors
[NUMCOLS
];
49 static Bool running
= True
;
50 static Bool failure
= False
;
56 die(const char *errstr
, ...)
61 vfprintf(stderr
, errstr
, ap
);
74 fd
= open("/proc/self/oom_score_adj", O_WRONLY
);
75 if (fd
< 0 && errno
== ENOENT
) {
78 if (fd
< 0 || write(fd
, "-1000\n", (sizeof("-1000\n") - 1)) !=
79 (sizeof("-1000\n") - 1) || close(fd
) != 0) {
80 die("can't tame the oom-killer. is suid or sgid set?\n");
86 /* only run as root */
94 if (!(pw
= getpwuid(getuid()))) {
96 die("getpwuid: %s\n", strerror(errno
));
98 die("cannot retrieve password entry\n");
100 rval
= pw
->pw_passwd
;
103 if (rval
[0] == 'x' && rval
[1] == '\0') {
105 if (!(sp
= getspnam(getenv("USER"))))
106 die("cannot retrieve shadow entry (make sure to suid or sgid slock)\n");
111 /* drop privileges */
112 if (geteuid() == 0 &&
113 ((getegid() != pw
->pw_gid
&& setgid(pw
->pw_gid
) < 0) || setuid(pw
->pw_uid
) < 0))
114 die("cannot drop privileges\n");
123 readpw(Display
*dpy
, const char *pws
)
126 char buf
[32], passwd
[256];
128 unsigned int len
, color
;
131 static int oldc
= INIT
;
136 /* As "slock" stands for "Simple X display locker", the DPMS settings
137 * had been removed and you can set it with "xset" or some other
138 * utility. This way the user can easily set a customized DPMS
140 while (running
&& !XNextEvent(dpy
, &ev
)) {
141 if (ev
.type
== KeyPress
) {
142 explicit_bzero(&buf
, sizeof(buf
));
143 num
= XLookupString(&ev
.xkey
, buf
, sizeof(buf
), &ksym
, 0);
144 if (IsKeypadKey(ksym
)) {
145 if (ksym
== XK_KP_Enter
)
147 else if (ksym
>= XK_KP_0
&& ksym
<= XK_KP_9
)
148 ksym
= (ksym
- XK_KP_0
) + XK_0
;
150 if (IsFunctionKey(ksym
) ||
152 IsMiscFunctionKey(ksym
) ||
154 IsPrivateKeypadKey(ksym
))
160 running
= !auth_userokay(getlogin(), NULL
, "auth-xlock", passwd
);
162 running
= !!strcmp(crypt(passwd
, pws
), pws
);
168 explicit_bzero(&passwd
, sizeof(passwd
));
172 explicit_bzero(&passwd
, sizeof(passwd
));
180 if (num
&& !iscntrl((int)buf
[0]) && (len
+ num
< sizeof(passwd
))) {
181 memcpy(passwd
+ len
, buf
, num
);
186 color
= len
? INPUT
: (failure
|| failonclear
? FAILED
: INIT
);
187 if (running
&& oldc
!= color
) {
188 for (screen
= 0; screen
< nscreens
; screen
++) {
189 XSetWindowBackground(dpy
, locks
[screen
]->win
, locks
[screen
]->colors
[color
]);
190 XClearWindow(dpy
, locks
[screen
]->win
);
194 } else if (rr
&& ev
.type
== rrevbase
+ RRScreenChangeNotify
) {
195 XRRScreenChangeNotifyEvent
*rre
= (XRRScreenChangeNotifyEvent
*)&ev
;
196 for (screen
= 0; screen
< nscreens
; screen
++) {
197 if (locks
[screen
]->win
== rre
->window
) {
198 XResizeWindow(dpy
, locks
[screen
]->win
, rre
->width
, rre
->height
);
199 XClearWindow(dpy
, locks
[screen
]->win
);
202 } else for (screen
= 0; screen
< nscreens
; screen
++)
203 XRaiseWindow(dpy
, locks
[screen
]->win
);
208 unlockscreen(Display
*dpy
, Lock
*lock
)
210 if(dpy
== NULL
|| lock
== NULL
)
213 XUngrabPointer(dpy
, CurrentTime
);
214 XFreeColors(dpy
, DefaultColormap(dpy
, lock
->screen
), lock
->colors
, NUMCOLS
, 0);
215 XFreePixmap(dpy
, lock
->pmap
);
216 XDestroyWindow(dpy
, lock
->win
);
222 lockscreen(Display
*dpy
, int screen
)
224 char curs
[] = {0, 0, 0, 0, 0, 0, 0, 0};
228 XSetWindowAttributes wa
;
231 if (!running
|| dpy
== NULL
|| screen
< 0 || !(lock
= malloc(sizeof(Lock
))))
234 lock
->screen
= screen
;
235 lock
->root
= RootWindow(dpy
, lock
->screen
);
237 for (i
= 0; i
< NUMCOLS
; i
++) {
238 XAllocNamedColor(dpy
, DefaultColormap(dpy
, lock
->screen
), colorname
[i
], &color
, &dummy
);
239 lock
->colors
[i
] = color
.pixel
;
243 wa
.override_redirect
= 1;
244 wa
.background_pixel
= lock
->colors
[INIT
];
245 lock
->win
= XCreateWindow(dpy
, lock
->root
, 0, 0, DisplayWidth(dpy
, lock
->screen
), DisplayHeight(dpy
, lock
->screen
),
246 0, DefaultDepth(dpy
, lock
->screen
), CopyFromParent
,
247 DefaultVisual(dpy
, lock
->screen
), CWOverrideRedirect
| CWBackPixel
, &wa
);
248 lock
->pmap
= XCreateBitmapFromData(dpy
, lock
->win
, curs
, 8, 8);
249 invisible
= XCreatePixmapCursor(dpy
, lock
->pmap
, lock
->pmap
, &color
, &color
, 0, 0);
250 XDefineCursor(dpy
, lock
->win
, invisible
);
252 /* Try to grab mouse pointer *and* keyboard, else fail the lock */
253 if (XGrabPointer(dpy
, lock
->root
, False
, ButtonPressMask
|
254 ButtonReleaseMask
| PointerMotionMask
, GrabModeAsync
, GrabModeAsync
,
255 None
, invisible
, CurrentTime
) != GrabSuccess
) {
256 fprintf(stderr
, "slock: unable to grab mouse pointer for screen %d\n", screen
);
258 unlockscreen(dpy
, lock
);
262 if (XGrabKeyboard(dpy
, lock
->root
, True
, GrabModeAsync
, GrabModeAsync
,
263 CurrentTime
) != GrabSuccess
) {
264 fprintf(stderr
, "slock: unable to grab keyboard for screen %d\n", screen
);
266 unlockscreen(dpy
, lock
);
270 XMapRaised(dpy
, lock
->win
);
272 XRRSelectInput(dpy
, lock
->win
, RRScreenChangeNotifyMask
);
274 XSelectInput(dpy
, lock
->root
, SubstructureNotifyMask
);
281 die("usage: slock [-v | cmd [arg ...]]\n");
285 main(int argc
, char **argv
) {
286 #ifndef HAVE_BSD_AUTH
294 fprintf(stderr
, "slock-"VERSION
"\n");
304 /* Check if the current user has a password entry */
306 if (!getpwuid(getuid())) {
308 die("slock: no password entry for current user\n");
310 die("slock: getpwuid: %s\n", strerror(errno
));
313 #ifndef HAVE_BSD_AUTH
317 if (!(dpy
= XOpenDisplay(NULL
)))
318 die("slock: cannot open display\n");
320 /* check for Xrandr support */
321 rr
= XRRQueryExtension(dpy
, &rrevbase
, &rrerrbase
);
323 /* get number of screens in display "dpy" and blank them */
324 nscreens
= ScreenCount(dpy
);
325 if (!(locks
= malloc(sizeof(Lock
*) * nscreens
))) {
327 die("slock: out of memory\n");
329 for (nlocks
= 0, s
= 0; s
< nscreens
; s
++) {
330 if ((locks
[s
] = lockscreen(dpy
, s
)) != NULL
)
335 /* did we actually manage to lock anything? */
337 /* nothing to protect */
343 /* run post-lock command */
349 die("slock: fork failed: %s\n", strerror(errno
));
351 if (close(ConnectionNumber(dpy
)) < 0)
352 die("slock: close: %s\n", strerror(errno
));
353 execvp(argv
[0], argv
);
354 fprintf(stderr
, "slock: execvp %s: %s\n", argv
[0],
360 /* everything is now blank. Wait for the correct password */
367 /* password ok, unlock everything and quit */
368 for (s
= 0; s
< nscreens
; s
++)
369 unlockscreen(dpy
, locks
[s
]);