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>
39 unsigned long colors
[NUMCOLS
];
44 static Bool running
= True
;
45 static Bool failure
= False
;
51 die(const char *errstr
, ...)
56 vfprintf(stderr
, errstr
, ap
);
63 #include <linux/oom.h>
72 fd
= open("/proc/self/oom_score_adj", O_WRONLY
);
73 if (fd
< 0 && errno
== ENOENT
)
76 /* convert OOM_SCORE_ADJ_MIN to string for writing */
77 length
= snprintf(value
, sizeof(value
), "%d\n", OOM_SCORE_ADJ_MIN
);
79 /* bail on truncation */
80 if (length
>= sizeof(value
))
81 die("buffer too small\n");
83 if (fd
< 0 || write(fd
, value
, length
) != length
|| close(fd
) != 0)
84 die("cannot disable the out-of-memory killer for this process (make sure to suid or sgid slock)\n");
89 /* only run as root */
97 if (!(pw
= getpwuid(getuid()))) {
99 die("slock: getpwuid: %s\n", strerror(errno
));
101 die("slock: cannot retrieve password entry\n");
103 rval
= pw
->pw_passwd
;
106 if (rval
[0] == 'x' && rval
[1] == '\0') {
108 if (!(sp
= getspnam(getenv("USER"))))
109 die("slock: cannot retrieve shadow entry (make sure to suid or sgid slock)\n");
114 /* drop privileges */
115 if (geteuid() == 0 &&
116 ((getegid() != pw
->pw_gid
&& setgid(pw
->pw_gid
) < 0) || setuid(pw
->pw_uid
) < 0))
117 die("slock: cannot drop privileges\n");
126 readpw(Display
*dpy
, const char *pws
)
129 char buf
[32], passwd
[256];
131 unsigned int len
, color
;
134 static int oldc
= INIT
;
139 /* As "slock" stands for "Simple X display locker", the DPMS settings
140 * had been removed and you can set it with "xset" or some other
141 * utility. This way the user can easily set a customized DPMS
143 while (running
&& !XNextEvent(dpy
, &ev
)) {
144 if (ev
.type
== KeyPress
) {
146 num
= XLookupString(&ev
.xkey
, buf
, sizeof(buf
), &ksym
, 0);
147 if (IsKeypadKey(ksym
)) {
148 if (ksym
== XK_KP_Enter
)
150 else if (ksym
>= XK_KP_0
&& ksym
<= XK_KP_9
)
151 ksym
= (ksym
- XK_KP_0
) + XK_0
;
153 if (IsFunctionKey(ksym
) ||
155 IsMiscFunctionKey(ksym
) ||
157 IsPrivateKeypadKey(ksym
))
163 running
= !auth_userokay(getlogin(), NULL
, "auth-xlock", passwd
);
165 running
= !!strcmp(crypt(passwd
, pws
), pws
);
181 if (num
&& !iscntrl((int)buf
[0]) && (len
+ num
< sizeof(passwd
))) {
182 memcpy(passwd
+ len
, buf
, num
);
187 color
= len
? INPUT
: (failure
|| failonclear
? FAILED
: INIT
);
188 if (running
&& oldc
!= color
) {
189 for (screen
= 0; screen
< nscreens
; screen
++) {
190 XSetWindowBackground(dpy
, locks
[screen
]->win
, locks
[screen
]->colors
[color
]);
191 XClearWindow(dpy
, locks
[screen
]->win
);
195 } else if (rr
&& ev
.type
== rrevbase
+ RRScreenChangeNotify
) {
196 XRRScreenChangeNotifyEvent
*rre
= (XRRScreenChangeNotifyEvent
*)&ev
;
197 for (screen
= 0; screen
< nscreens
; screen
++) {
198 if (locks
[screen
]->win
== rre
->window
) {
199 XResizeWindow(dpy
, locks
[screen
]->win
, rre
->width
, rre
->height
);
200 XClearWindow(dpy
, locks
[screen
]->win
);
203 } else for (screen
= 0; screen
< nscreens
; screen
++)
204 XRaiseWindow(dpy
, locks
[screen
]->win
);
209 unlockscreen(Display
*dpy
, Lock
*lock
)
211 if(dpy
== NULL
|| lock
== NULL
)
214 XUngrabPointer(dpy
, CurrentTime
);
215 XFreeColors(dpy
, DefaultColormap(dpy
, lock
->screen
), lock
->colors
, NUMCOLS
, 0);
216 XFreePixmap(dpy
, lock
->pmap
);
217 XDestroyWindow(dpy
, lock
->win
);
223 lockscreen(Display
*dpy
, int screen
)
225 char curs
[] = {0, 0, 0, 0, 0, 0, 0, 0};
230 XSetWindowAttributes wa
;
233 if (!running
|| dpy
== NULL
|| screen
< 0 || !(lock
= malloc(sizeof(Lock
))))
236 lock
->screen
= screen
;
237 lock
->root
= RootWindow(dpy
, lock
->screen
);
239 for (i
= 0; i
< NUMCOLS
; i
++) {
240 XAllocNamedColor(dpy
, DefaultColormap(dpy
, lock
->screen
), colorname
[i
], &color
, &dummy
);
241 lock
->colors
[i
] = color
.pixel
;
245 wa
.override_redirect
= 1;
246 wa
.background_pixel
= lock
->colors
[INIT
];
247 lock
->win
= XCreateWindow(dpy
, lock
->root
, 0, 0, DisplayWidth(dpy
, lock
->screen
), DisplayHeight(dpy
, lock
->screen
),
248 0, DefaultDepth(dpy
, lock
->screen
), CopyFromParent
,
249 DefaultVisual(dpy
, lock
->screen
), CWOverrideRedirect
| CWBackPixel
, &wa
);
250 lock
->pmap
= XCreateBitmapFromData(dpy
, lock
->win
, curs
, 8, 8);
251 invisible
= XCreatePixmapCursor(dpy
, lock
->pmap
, lock
->pmap
, &color
, &color
, 0, 0);
252 XDefineCursor(dpy
, lock
->win
, invisible
);
253 XMapRaised(dpy
, lock
->win
);
255 XRRSelectInput(dpy
, lock
->win
, RRScreenChangeNotifyMask
);
257 /* Try to grab mouse pointer *and* keyboard, else fail the lock */
258 for (len
= 1000; len
; len
--) {
259 if (XGrabPointer(dpy
, lock
->root
, False
, ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
,
260 GrabModeAsync
, GrabModeAsync
, None
, invisible
, CurrentTime
) == GrabSuccess
)
265 fprintf(stderr
, "slock: unable to grab mouse pointer for screen %d\n", screen
);
267 for (len
= 1000; len
; len
--) {
268 if (XGrabKeyboard(dpy
, lock
->root
, True
, GrabModeAsync
, GrabModeAsync
, CurrentTime
) == GrabSuccess
) {
269 /* everything fine, we grabbed both inputs */
270 XSelectInput(dpy
, lock
->root
, SubstructureNotifyMask
);
275 fprintf(stderr
, "slock: unable to grab keyboard for screen %d\n", screen
);
277 /* grabbing one of the inputs failed */
279 unlockscreen(dpy
, lock
);
286 fprintf(stderr
, "usage: slock [-v|POST_LOCK_CMD]\n");
291 main(int argc
, char **argv
) {
292 #ifndef HAVE_BSD_AUTH
298 if ((argc
== 2) && !strcmp("-v", argv
[1]))
299 die("slock-%s, © 2006-2016 slock engineers\n", VERSION
);
301 if ((argc
== 2) && !strcmp("-h", argv
[1]))
308 if (!getpwuid(getuid()))
309 die("slock: no passwd entry for you\n");
311 #ifndef HAVE_BSD_AUTH
315 if (!(dpy
= XOpenDisplay(0)))
316 die("slock: cannot open display\n");
317 rr
= XRRQueryExtension(dpy
, &rrevbase
, &rrerrbase
);
318 /* Get the number of screens in display "dpy" and blank them all. */
319 nscreens
= ScreenCount(dpy
);
320 if (!(locks
= malloc(sizeof(Lock
*) * nscreens
)))
321 die("slock: malloc: %s\n", strerror(errno
));
323 for (screen
= 0; screen
< nscreens
; screen
++) {
324 if ((locks
[screen
] = lockscreen(dpy
, screen
)) != NULL
)
329 /* Did we actually manage to lock something? */
330 if (nlocks
== 0) { /* nothing to protect */
336 if (argc
>= 2 && fork() == 0) {
338 close(ConnectionNumber(dpy
));
339 execvp(argv
[1], argv
+1);
340 die("slock: execvp %s failed: %s\n", argv
[1], strerror(errno
));
343 /* Everything is now blank. Now wait for the correct password. */
350 /* Password ok, unlock everything and quit. */
351 for (screen
= 0; screen
< nscreens
; screen
++)
352 unlockscreen(dpy
, locks
[screen
]);