slock.c.orig (14706B)
1 /* See LICENSE file for license details. */ 2 #define _XOPEN_SOURCE 500 3 #define LENGTH(X) (sizeof X / sizeof X[0]) 4 #if HAVE_SHADOW_H 5 #include <shadow.h> 6 #endif 7 8 #include <ctype.h> 9 #include <errno.h> 10 #include <grp.h> 11 #include <pwd.h> 12 #include <stdarg.h> 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <string.h> 16 #include <unistd.h> 17 #include <spawn.h> 18 #include <sys/types.h> 19 #include <X11/extensions/Xrandr.h> 20 #ifdef XINERAMA 21 #include <X11/extensions/Xinerama.h> 22 #endif 23 #include <X11/keysym.h> 24 #include <X11/Xlib.h> 25 #include <X11/Xutil.h> 26 #include <X11/XKBlib.h> 27 #include <X11/Xmd.h> 28 #include <X11/extensions/dpms.h> 29 30 #include <Imlib2.h> 31 32 #include "arg.h" 33 #include "util.h" 34 35 char *argv0; 36 37 enum { 38 BACKGROUND, 39 INIT, 40 INPUT, 41 FAILED, 42 CAPS, 43 NUMCOLS 44 }; 45 46 #include "config.h" 47 48 struct lock { 49 int screen; 50 Window root, win; 51 Pixmap pmap; 52 Pixmap bgmap; 53 unsigned long colors[NUMCOLS]; 54 unsigned int x, y; 55 unsigned int xoff, yoff, mw, mh; 56 Drawable drawable; 57 GC gc; 58 XRectangle rectangles[LENGTH(rectangles)]; 59 }; 60 61 struct xrandr { 62 int active; 63 int evbase; 64 int errbase; 65 }; 66 67 Imlib_Image image; 68 69 static void 70 die(const char *errstr, ...) 71 { 72 va_list ap; 73 74 va_start(ap, errstr); 75 vfprintf(stderr, errstr, ap); 76 va_end(ap); 77 exit(1); 78 } 79 80 #ifdef __linux__ 81 #include <fcntl.h> 82 #include <linux/oom.h> 83 84 static void 85 dontkillme(void) 86 { 87 FILE *f; 88 const char oomfile[] = "/proc/self/oom_score_adj"; 89 90 if (!(f = fopen(oomfile, "w"))) { 91 if (errno == ENOENT) 92 return; 93 die("slock: fopen %s: %s\n", oomfile, strerror(errno)); 94 } 95 fprintf(f, "%d", OOM_SCORE_ADJ_MIN); 96 if (fclose(f)) { 97 if (errno == EACCES) 98 die("slock: unable to disable OOM killer. " 99 "Make sure to suid or sgid slock.\n"); 100 else 101 die("slock: fclose %s: %s\n", oomfile, strerror(errno)); 102 } 103 } 104 #endif 105 106 static const char * 107 gethash(void) 108 { 109 const char *hash; 110 struct passwd *pw; 111 112 /* Check if the current user has a password entry */ 113 errno = 0; 114 if (!(pw = getpwuid(getuid()))) { 115 if (errno) 116 die("slock: getpwuid: %s\n", strerror(errno)); 117 else 118 die("slock: cannot retrieve password entry\n"); 119 } 120 hash = pw->pw_passwd; 121 122 #if HAVE_SHADOW_H 123 if (!strcmp(hash, "x")) { 124 struct spwd *sp; 125 if (!(sp = getspnam(pw->pw_name))) 126 die("slock: getspnam: cannot retrieve shadow entry. " 127 "Make sure to suid or sgid slock.\n"); 128 hash = sp->sp_pwdp; 129 } 130 #else 131 if (!strcmp(hash, "*")) { 132 #ifdef __OpenBSD__ 133 if (!(pw = getpwuid_shadow(getuid()))) 134 die("slock: getpwnam_shadow: cannot retrieve shadow entry. " 135 "Make sure to suid or sgid slock.\n"); 136 hash = pw->pw_passwd; 137 #else 138 die("slock: getpwuid: cannot retrieve shadow entry. " 139 "Make sure to suid or sgid slock.\n"); 140 #endif /* __OpenBSD__ */ 141 } 142 #endif /* HAVE_SHADOW_H */ 143 144 return hash; 145 } 146 147 static void 148 resizerectangles(struct lock *lock) 149 { 150 int i; 151 152 for (i = 0; i < LENGTH(rectangles); i++){ 153 lock->rectangles[i].x = (rectangles[i].x * logosize) 154 + lock->xoff + ((lock->mw) / 2) - (logow / 2 * logosize); 155 lock->rectangles[i].y = (rectangles[i].y * logosize) 156 + lock->yoff + ((lock->mh) / 2) - (logoh / 2 * logosize); 157 lock->rectangles[i].width = rectangles[i].width * logosize; 158 lock->rectangles[i].height = rectangles[i].height * logosize; 159 } 160 } 161 162 static void 163 drawlogo(Display *dpy, struct lock *lock, int color) 164 { 165 XSetForeground(dpy, lock->gc, lock->colors[color]); 166 XFillRectangles(dpy, lock->win, lock->gc, lock->rectangles, LENGTH(rectangles)); 167 XSync(dpy, False); 168 } 169 170 static void 171 readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, 172 const char *hash) 173 { 174 XRRScreenChangeNotifyEvent *rre; 175 char buf[32], passwd[256], *inputhash; 176 int caps, num, screen, running, failure, oldc; 177 unsigned int len, color, indicators; 178 KeySym ksym; 179 XEvent ev; 180 181 len = 0; 182 caps = 0; 183 running = 1; 184 failure = 0; 185 oldc = INIT; 186 187 if (!XkbGetIndicatorState(dpy, XkbUseCoreKbd, &indicators)) 188 caps = indicators & 1; 189 190 while (running && !XNextEvent(dpy, &ev)) { 191 if (ev.type == KeyPress) { 192 explicit_bzero(&buf, sizeof(buf)); 193 num = XLookupString(&ev.xkey, buf, sizeof(buf), &ksym, 0); 194 if (IsKeypadKey(ksym)) { 195 if (ksym == XK_KP_Enter) 196 ksym = XK_Return; 197 else if (ksym >= XK_KP_0 && ksym <= XK_KP_9) 198 ksym = (ksym - XK_KP_0) + XK_0; 199 } 200 if (IsFunctionKey(ksym) || 201 IsKeypadKey(ksym) || 202 IsMiscFunctionKey(ksym) || 203 IsPFKey(ksym) || 204 IsPrivateKeypadKey(ksym)) 205 continue; 206 switch (ksym) { 207 case XK_Return: 208 passwd[len] = '\0'; 209 errno = 0; 210 if (!(inputhash = crypt(passwd, hash))) 211 fprintf(stderr, "slock: crypt: %s\n", strerror(errno)); 212 else 213 running = !!strcmp(inputhash, hash); 214 if (running) { 215 XBell(dpy, 100); 216 failure = 1; 217 } 218 explicit_bzero(&passwd, sizeof(passwd)); 219 len = 0; 220 break; 221 case XK_Escape: 222 explicit_bzero(&passwd, sizeof(passwd)); 223 len = 0; 224 break; 225 case XK_BackSpace: 226 if (len) 227 passwd[--len] = '\0'; 228 break; 229 case XK_Caps_Lock: 230 caps = !caps; 231 break; 232 default: 233 if (num && !iscntrl((int)buf[0]) && 234 (len + num < sizeof(passwd))) { 235 memcpy(passwd + len, buf, num); 236 len += num; 237 } else if (buf[0] == '\025') { /* ctrl-u clears input */ 238 explicit_bzero(&passwd, sizeof(passwd)); 239 len = 0; 240 } 241 break; 242 } 243 color = len ? (caps ? CAPS : INPUT) : (failure || failonclear ? FAILED : INIT); 244 if (running && oldc != color) { 245 for (screen = 0; screen < nscreens; screen++) { 246 if(locks[screen]->bgmap) 247 XSetWindowBackgroundPixmap(dpy, locks[screen]->win, locks[screen]->bgmap); 248 else 249 XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[0]); 250 //XClearWindow(dpy, locks[screen]->win); 251 drawlogo(dpy, locks[screen], color); 252 } 253 oldc = color; 254 } 255 } else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) { 256 rre = (XRRScreenChangeNotifyEvent*)&ev; 257 for (screen = 0; screen < nscreens; screen++) { 258 if (locks[screen]->win == rre->window) { 259 if (rre->rotation == RR_Rotate_90 || 260 rre->rotation == RR_Rotate_270) 261 XResizeWindow(dpy, locks[screen]->win, 262 rre->height, rre->width); 263 else 264 XResizeWindow(dpy, locks[screen]->win, 265 rre->width, rre->height); 266 XClearWindow(dpy, locks[screen]->win); 267 break; 268 } 269 } 270 } else { 271 for (screen = 0; screen < nscreens; screen++) 272 XRaiseWindow(dpy, locks[screen]->win); 273 } 274 } 275 } 276 277 static struct lock * 278 lockscreen(Display *dpy, struct xrandr *rr, int screen) 279 { 280 char curs[] = {0, 0, 0, 0, 0, 0, 0, 0}; 281 int i, ptgrab, kbgrab; 282 struct lock *lock; 283 XColor color, dummy; 284 XSetWindowAttributes wa; 285 Cursor invisible; 286 #ifdef XINERAMA 287 XineramaScreenInfo *info; 288 int n; 289 #endif 290 291 if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(struct lock)))) 292 return NULL; 293 294 lock->screen = screen; 295 lock->root = RootWindow(dpy, lock->screen); 296 297 if(image) 298 { 299 lock->bgmap = XCreatePixmap(dpy, lock->root, DisplayWidth(dpy, lock->screen), DisplayHeight(dpy, lock->screen), DefaultDepth(dpy, lock->screen)); 300 imlib_context_set_image(image); 301 imlib_context_set_display(dpy); 302 imlib_context_set_visual(DefaultVisual(dpy, lock->screen)); 303 imlib_context_set_colormap(DefaultColormap(dpy, lock->screen)); 304 imlib_context_set_drawable(lock->bgmap); 305 imlib_render_image_on_drawable(0, 0); 306 imlib_free_image(); 307 } 308 for (i = 0; i < NUMCOLS; i++) { 309 XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen), 310 colorname[i], &color, &dummy); 311 lock->colors[i] = color.pixel; 312 } 313 314 lock->x = DisplayWidth(dpy, lock->screen); 315 lock->y = DisplayHeight(dpy, lock->screen); 316 #ifdef XINERAMA 317 if ((info = XineramaQueryScreens(dpy, &n))) { 318 lock->xoff = info[0].x_org; 319 lock->yoff = info[0].y_org; 320 lock->mw = info[0].width; 321 lock->mh = info[0].height; 322 } else 323 #endif 324 { 325 lock->xoff = lock->yoff = 0; 326 lock->mw = lock->x; 327 lock->mh = lock->y; 328 } 329 lock->drawable = XCreatePixmap(dpy, lock->root, 330 lock->x, lock->y, DefaultDepth(dpy, screen)); 331 lock->gc = XCreateGC(dpy, lock->root, 0, NULL); 332 XSetLineAttributes(dpy, lock->gc, 1, LineSolid, CapButt, JoinMiter); 333 334 /* init */ 335 wa.override_redirect = 1; 336 wa.background_pixel = lock->colors[BACKGROUND]; 337 lock->win = XCreateWindow(dpy, lock->root, 0, 0, 338 lock->x, lock->y, 339 0, DefaultDepth(dpy, lock->screen), 340 CopyFromParent, 341 DefaultVisual(dpy, lock->screen), 342 CWOverrideRedirect | CWBackPixel, &wa); 343 if(lock->bgmap) 344 XSetWindowBackgroundPixmap(dpy, lock->win, lock->bgmap); 345 lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8); 346 invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, 347 &color, &color, 0, 0); 348 XDefineCursor(dpy, lock->win, invisible); 349 350 resizerectangles(lock); 351 352 /* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */ 353 for (i = 0, ptgrab = kbgrab = -1; i < 6; i++) { 354 if (ptgrab != GrabSuccess) { 355 ptgrab = XGrabPointer(dpy, lock->root, False, 356 ButtonPressMask | ButtonReleaseMask | 357 PointerMotionMask, GrabModeAsync, 358 GrabModeAsync, None, invisible, CurrentTime); 359 } 360 if (kbgrab != GrabSuccess) { 361 kbgrab = XGrabKeyboard(dpy, lock->root, True, 362 GrabModeAsync, GrabModeAsync, CurrentTime); 363 } 364 365 /* input is grabbed: we can lock the screen */ 366 if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) { 367 XMapRaised(dpy, lock->win); 368 if (rr->active) 369 XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask); 370 371 XSelectInput(dpy, lock->root, SubstructureNotifyMask); 372 drawlogo(dpy, lock, INIT); 373 return lock; 374 } 375 376 /* retry on AlreadyGrabbed but fail on other errors */ 377 if ((ptgrab != AlreadyGrabbed && ptgrab != GrabSuccess) || 378 (kbgrab != AlreadyGrabbed && kbgrab != GrabSuccess)) 379 break; 380 381 usleep(100000); 382 } 383 384 /* we couldn't grab all input: fail out */ 385 if (ptgrab != GrabSuccess) 386 fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n", 387 screen); 388 if (kbgrab != GrabSuccess) 389 fprintf(stderr, "slock: unable to grab keyboard for screen %d\n", 390 screen); 391 return NULL; 392 } 393 394 static void 395 usage(void) 396 { 397 die("usage: slock [-v] [cmd [arg ...]]\n"); 398 } 399 400 int 401 main(int argc, char **argv) { 402 struct xrandr rr; 403 struct lock **locks; 404 struct passwd *pwd; 405 struct group *grp; 406 uid_t duid; 407 gid_t dgid; 408 const char *hash; 409 Display *dpy; 410 int s, nlocks, nscreens; 411 CARD16 standby, suspend, off; 412 BOOL dpms_state; 413 414 ARGBEGIN { 415 case 'v': 416 puts("slock-"VERSION); 417 return 0; 418 default: 419 usage(); 420 } ARGEND 421 422 /* validate drop-user and -group */ 423 errno = 0; 424 if (!(pwd = getpwnam(user))) 425 die("slock: getpwnam %s: %s\n", user, 426 errno ? strerror(errno) : "user entry not found"); 427 duid = pwd->pw_uid; 428 errno = 0; 429 if (!(grp = getgrnam(group))) 430 die("slock: getgrnam %s: %s\n", group, 431 errno ? strerror(errno) : "group entry not found"); 432 dgid = grp->gr_gid; 433 434 #ifdef __linux__ 435 dontkillme(); 436 #endif 437 438 hash = gethash(); 439 errno = 0; 440 if (!crypt("", hash)) 441 die("slock: crypt: %s\n", strerror(errno)); 442 443 if (!(dpy = XOpenDisplay(NULL))) 444 die("slock: cannot open display\n"); 445 446 /* drop privileges */ 447 if (setgroups(0, NULL) < 0) 448 die("slock: setgroups: %s\n", strerror(errno)); 449 if (setgid(dgid) < 0) 450 die("slock: setgid: %s\n", strerror(errno)); 451 if (setuid(duid) < 0) 452 die("slock: setuid: %s\n", strerror(errno)); 453 454 /*Create screenshot Image*/ 455 Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy)); 456 image = imlib_create_image(scr->width,scr->height); 457 imlib_context_set_image(image); 458 imlib_context_set_display(dpy); 459 imlib_context_set_visual(DefaultVisual(dpy,0)); 460 imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr))); 461 imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1); 462 463 #ifdef BLUR 464 465 /*Blur function*/ 466 imlib_image_blur(blurRadius); 467 #endif // BLUR 468 469 #ifdef PIXELATION 470 /*Pixelation*/ 471 int width = scr->width; 472 int height = scr->height; 473 474 for(int y = 0; y < height; y += pixelSize) 475 { 476 for(int x = 0; x < width; x += pixelSize) 477 { 478 int red = 0; 479 int green = 0; 480 int blue = 0; 481 482 Imlib_Color pixel; 483 Imlib_Color* pp; 484 pp = &pixel; 485 for(int j = 0; j < pixelSize && j < height; j++) 486 { 487 for(int i = 0; i < pixelSize && i < width; i++) 488 { 489 imlib_image_query_pixel(x+i,y+j,pp); 490 red += pixel.red; 491 green += pixel.green; 492 blue += pixel.blue; 493 } 494 } 495 red /= (pixelSize*pixelSize); 496 green /= (pixelSize*pixelSize); 497 blue /= (pixelSize*pixelSize); 498 imlib_context_set_color(red,green,blue,pixel.alpha); 499 imlib_image_fill_rectangle(x,y,pixelSize,pixelSize); 500 red = 0; 501 green = 0; 502 blue = 0; 503 } 504 } 505 506 507 #endif 508 /* check for Xrandr support */ 509 rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); 510 511 /* get number of screens in display "dpy" and blank them */ 512 nscreens = ScreenCount(dpy); 513 if (!(locks = calloc(nscreens, sizeof(struct lock *)))) 514 die("slock: out of memory\n"); 515 for (nlocks = 0, s = 0; s < nscreens; s++) { 516 if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) 517 nlocks++; 518 else 519 break; 520 } 521 XSync(dpy, 0); 522 523 /* did we manage to lock everything? */ 524 if (nlocks != nscreens) 525 return 1; 526 527 /* DPMS magic to disable the monitor */ 528 if (!DPMSCapable(dpy)) 529 die("slock: DPMSCapable failed\n"); 530 if (!DPMSInfo(dpy, &standby, &dpms_state)) 531 die("slock: DPMSInfo failed\n"); 532 if (!DPMSEnable(dpy) && !dpms_state) 533 die("slock: DPMSEnable failed\n"); 534 if (!DPMSGetTimeouts(dpy, &standby, &suspend, &off)) 535 die("slock: DPMSGetTimeouts failed\n"); 536 if (!standby || !suspend || !off) 537 die("slock: at least one DPMS variable is zero\n"); 538 if (!DPMSSetTimeouts(dpy, monitortime, monitortime, monitortime)) 539 die("slock: DPMSSetTimeouts failed\n"); 540 541 XSync(dpy, 0); 542 543 /* run post-lock command */ 544 if (argc > 0) { 545 pid_t pid; 546 extern char **environ; 547 int err = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ); 548 if (err) { 549 die("slock: failed to execute post-lock command: %s: %s\n", 550 argv[0], strerror(err)); 551 } 552 } 553 554 /* everything is now blank. Wait for the correct password */ 555 readpw(dpy, &rr, locks, nscreens, hash); 556 557 for (nlocks = 0, s = 0; s < nscreens; s++) { 558 XFreePixmap(dpy, locks[s]->drawable); 559 XFreeGC(dpy, locks[s]->gc); 560 } 561 562 /* reset DPMS values to inital ones */ 563 DPMSSetTimeouts(dpy, standby, suspend, off); 564 if (!dpms_state) 565 DPMSDisable(dpy); 566 XSync(dpy, 0); 567 XCloseDisplay(dpy); 568 return 0; 569 }