slock.c (21246B)
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 #include <X11/keysym.h> 21 #include <X11/Xlib.h> 22 #include <X11/Xutil.h> 23 24 #include "patches.h" 25 #if ALPHA_PATCH 26 #include <X11/Xatom.h> 27 #endif // ALPHA_PATCH 28 #if KEYPRESS_FEEDBACK_PATCH 29 #include <time.h> 30 #endif // KEYPRESS_FEEDBACK_PATCH 31 #if CAPSCOLOR_PATCH 32 #include <X11/XKBlib.h> 33 #endif // CAPSCOLOR_PATCH 34 #if MEDIAKEYS_PATCH 35 #include <X11/XF86keysym.h> 36 #endif // MEDIAKEYS_PATCH 37 #if QUICKCANCEL_PATCH || AUTO_TIMEOUT_PATCH 38 #include <time.h> 39 #endif // QUICKCANCEL_PATCH / AUTO_TIMEOUT_PATCH 40 #if DPMS_PATCH 41 #include <X11/extensions/dpms.h> 42 #endif // DPMS_PATCH 43 #ifdef XINERAMA 44 #include <X11/extensions/Xinerama.h> 45 #endif 46 47 #include "arg.h" 48 #include "util.h" 49 50 char *argv0; 51 #if FAILURE_COMMAND_PATCH 52 int failtrack = 0; 53 #endif // FAILURE_COMMAND_PATCH 54 55 #if AUTO_TIMEOUT_PATCH 56 static time_t lasttouched; 57 int runflag = 0; 58 #endif // AUTO_TIMEOUT_PATCH 59 #if QUICKCANCEL_PATCH 60 static time_t locktime; 61 #endif // QUICKCANCEL_PATCH 62 63 #if VISUAL_UNLOCK_PATCH 64 int visual_unlock = 0; 65 #endif // VISUAL_UNLOCK_PATCH 66 67 enum { 68 #if DWM_LOGO_PATCH && !BLUR_PIXELATED_SCREEN_PATCH 69 BACKGROUND, 70 #endif // DWM_LOGO_PATCH 71 INIT, 72 INPUT, 73 FAILED, 74 #if CAPSCOLOR_PATCH 75 CAPS, 76 #endif // CAPSCOLOR_PATCH 77 #if PAMAUTH_PATCH 78 PAM, 79 #endif // PAMAUTH_PATCH 80 #if KEYPRESS_FEEDBACK_PATCH 81 BLOCKS, 82 #endif // KEYPRESS_FEEDBACK_PATCH 83 NUMCOLS 84 }; 85 86 #if XRESOURCES_PATCH 87 /* Xresources preferences */ 88 enum resource_type { 89 STRING = 0, 90 INTEGER = 1, 91 FLOAT = 2 92 }; 93 94 typedef struct { 95 char *name; 96 enum resource_type type; 97 void *dst; 98 } ResourcePref; 99 #endif // XRESOURCES_PATCH 100 101 #if SECRET_PASSWORD_PATCH 102 typedef struct secretpass secretpass; 103 struct secretpass { 104 char *pass; 105 char *command; 106 }; 107 #endif // SECRET_PASSWORD_PATCH 108 109 #include "config.h" 110 111 struct lock { 112 int screen; 113 Window root, win; 114 Pixmap pmap; 115 #if BLUR_PIXELATED_SCREEN_PATCH || BACKGROUND_IMAGE_PATCH 116 Pixmap bgmap; 117 #endif // BLUR_PIXELATED_SCREEN_PATCH | BACKGROUND_IMAGE_PATCH 118 unsigned long colors[NUMCOLS]; 119 #if DWM_LOGO_PATCH 120 unsigned int x, y; 121 unsigned int xoff, yoff, mw, mh; 122 Drawable drawable; 123 GC gc; 124 XRectangle rectangles[LENGTH(rectangles)]; 125 #endif // DWM_LOGO_PATCH 126 }; 127 128 struct xrandr { 129 int active; 130 int evbase; 131 int errbase; 132 }; 133 134 #include "patch/include.h" 135 136 static void 137 die(const char *errstr, ...) 138 { 139 va_list ap; 140 141 va_start(ap, errstr); 142 vfprintf(stderr, errstr, ap); 143 va_end(ap); 144 exit(1); 145 } 146 147 #include "patch/include.c" 148 149 #ifdef __linux__ 150 #include <fcntl.h> 151 #include <linux/oom.h> 152 153 static void 154 dontkillme(void) 155 { 156 FILE *f; 157 const char oomfile[] = "/proc/self/oom_score_adj"; 158 159 if (!(f = fopen(oomfile, "w"))) { 160 if (errno == ENOENT) 161 return; 162 die("slock: fopen %s: %s\n", oomfile, strerror(errno)); 163 } 164 fprintf(f, "%d", OOM_SCORE_ADJ_MIN); 165 if (fclose(f)) { 166 if (errno == EACCES) 167 die("slock: unable to disable OOM killer. " 168 "Make sure to suid or sgid slock.\n"); 169 else 170 die("slock: fclose %s: %s\n", oomfile, strerror(errno)); 171 } 172 } 173 #endif 174 175 static const char * 176 gethash(void) 177 { 178 const char *hash; 179 struct passwd *pw; 180 181 /* Check if the current user has a password entry */ 182 errno = 0; 183 if (!(pw = getpwuid(getuid()))) { 184 if (errno) 185 die("slock: getpwuid: %s\n", strerror(errno)); 186 else 187 die("slock: cannot retrieve password entry\n"); 188 } 189 hash = pw->pw_passwd; 190 191 #if HAVE_SHADOW_H 192 if (!strcmp(hash, "x")) { 193 struct spwd *sp; 194 if (!(sp = getspnam(pw->pw_name))) 195 die("slock: getspnam: cannot retrieve shadow entry. " 196 "Make sure to suid or sgid slock.\n"); 197 hash = sp->sp_pwdp; 198 } 199 #else 200 if (!strcmp(hash, "*")) { 201 #ifdef __OpenBSD__ 202 if (!(pw = getpwuid_shadow(getuid()))) 203 die("slock: getpwnam_shadow: cannot retrieve shadow entry. " 204 "Make sure to suid or sgid slock.\n"); 205 hash = pw->pw_passwd; 206 #else 207 die("slock: getpwuid: cannot retrieve shadow entry. " 208 "Make sure to suid or sgid slock.\n"); 209 #endif /* __OpenBSD__ */ 210 } 211 #endif /* HAVE_SHADOW_H */ 212 213 #if PAMAUTH_PATCH 214 /* pam, store user name */ 215 hash = pw->pw_name; 216 #endif // PAMAUTH_PATCH 217 return hash; 218 } 219 220 static void 221 readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, 222 const char *hash) 223 { 224 XRRScreenChangeNotifyEvent *rre; 225 #if PAMAUTH_PATCH 226 char buf[32]; 227 int retval; 228 pam_handle_t *pamh; 229 #else 230 char buf[32], passwd[256], *inputhash; 231 #endif // PAMAUTH_PATCH 232 int num, screen, running, failure, oldc; 233 unsigned int len, color; 234 #if AUTO_TIMEOUT_PATCH 235 time_t currenttime; 236 #endif // AUTO_TIMEOUT_PATCH 237 #if CAPSCOLOR_PATCH 238 int caps; 239 unsigned int indicators; 240 #endif // CAPSCOLOR_PATCH 241 KeySym ksym; 242 XEvent ev; 243 244 len = 0; 245 #if CAPSCOLOR_PATCH 246 caps = 0; 247 #endif // CAPSCOLOR_PATCH 248 running = 1; 249 failure = 0; 250 oldc = INIT; 251 252 #if CAPSCOLOR_PATCH 253 if (!XkbGetIndicatorState(dpy, XkbUseCoreKbd, &indicators)) 254 caps = indicators & 1; 255 256 #endif // CAPSCOLOR_PATCH 257 #if AUTO_TIMEOUT_PATCH 258 while (running) 259 #else 260 while (running && !XNextEvent(dpy, &ev)) 261 #endif // AUTO_TIMEOUT_PATCH 262 { 263 #if AUTO_TIMEOUT_PATCH 264 while (XPending(dpy)) { 265 XNextEvent(dpy, &ev); 266 #endif // AUTO_TIMEOUT_PATCH 267 #if QUICKCANCEL_PATCH 268 running = !((time(NULL) - locktime < timetocancel) && (ev.type == MotionNotify || ev.type == KeyPress)); 269 #endif // QUICKCANCEL_PATCH 270 if (ev.type == KeyPress) { 271 #if AUTO_TIMEOUT_PATCH 272 time(&lasttouched); 273 #endif // AUTO_TIMEOUT_PATCH 274 explicit_bzero(&buf, sizeof(buf)); 275 num = XLookupString(&ev.xkey, buf, sizeof(buf), &ksym, 0); 276 if (IsKeypadKey(ksym)) { 277 if (ksym == XK_KP_Enter) 278 ksym = XK_Return; 279 else if (ksym >= XK_KP_0 && ksym <= XK_KP_9) 280 ksym = (ksym - XK_KP_0) + XK_0; 281 } 282 if (IsFunctionKey(ksym) || 283 IsKeypadKey(ksym) || 284 IsMiscFunctionKey(ksym) || 285 IsPFKey(ksym) || 286 IsPrivateKeypadKey(ksym)) 287 continue; 288 #if TERMINALKEYS_PATCH 289 if (ev.xkey.state & ControlMask) { 290 switch (ksym) { 291 case XK_u: 292 ksym = XK_Escape; 293 break; 294 case XK_m: 295 ksym = XK_Return; 296 break; 297 case XK_j: 298 ksym = XK_Return; 299 break; 300 case XK_h: 301 ksym = XK_BackSpace; 302 break; 303 } 304 } 305 #endif // TERMINALKEYS_PATCH 306 switch (ksym) { 307 case XK_Return: 308 passwd[len] = '\0'; 309 errno = 0; 310 311 #if SECRET_PASSWORD_PATCH 312 for (int i = 0; i < LENGTH(scom); i++) { 313 if (strcmp(scom[i].pass, passwd) == 0) { 314 if (system(scom[i].command)); 315 #if FAILURE_COMMAND_PATCH 316 failtrack = -1; 317 #endif // FAILURE_COMMAND_PATCH 318 } 319 } 320 #endif // SECRET_PASSWORD_PATCH 321 322 #if PAMAUTH_PATCH 323 retval = pam_start(pam_service, hash, &pamc, &pamh); 324 color = PAM; 325 for (screen = 0; screen < nscreens; screen++) { 326 #if DWM_LOGO_PATCH 327 drawlogo(dpy, locks[screen], color); 328 #elif BLUR_PIXELATED_SCREEN_PATCH || BACKGROUND_IMAGE_PATCH 329 if (locks[screen]->bgmap) 330 XSetWindowBackgroundPixmap(dpy, locks[screen]->win, locks[screen]->bgmap); 331 else 332 XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[0]); 333 XClearWindow(dpy, locks[screen]->win); 334 #else 335 XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[color]); 336 XClearWindow(dpy, locks[screen]->win); 337 XRaiseWindow(dpy, locks[screen]->win); 338 #endif // BLUR_PIXELATED_SCREEN_PATCH 339 340 } 341 XSync(dpy, False); 342 343 if (retval == PAM_SUCCESS) 344 retval = pam_authenticate(pamh, 0); 345 if (retval == PAM_SUCCESS) 346 retval = pam_acct_mgmt(pamh, 0); 347 348 running = 1; 349 if (retval == PAM_SUCCESS) 350 running = 0; 351 else 352 fprintf(stderr, "slock: %s\n", pam_strerror(pamh, retval)); 353 pam_end(pamh, retval); 354 #else 355 if (!(inputhash = crypt(passwd, hash))) 356 fprintf(stderr, "slock: crypt: %s\n", strerror(errno)); 357 else 358 running = !!strcmp(inputhash, hash); 359 #endif // PAMAUTH_PATCH 360 if (running) { 361 XBell(dpy, 100); 362 failure = 1; 363 #if FAILURE_COMMAND_PATCH 364 failtrack++; 365 366 if (failtrack >= failcount && failcount != 0) { 367 system(failcommand); 368 } 369 #endif // FAILURE_COMMAND_PATCH 370 } 371 explicit_bzero(&passwd, sizeof(passwd)); 372 len = 0; 373 break; 374 case XK_Escape: 375 explicit_bzero(&passwd, sizeof(passwd)); 376 len = 0; 377 break; 378 case XK_BackSpace: 379 if (len) 380 passwd[--len] = '\0'; 381 break; 382 #if CAPSCOLOR_PATCH 383 case XK_Caps_Lock: 384 caps = !caps; 385 break; 386 #endif // CAPSCOLOR_PATCH 387 #if MEDIAKEYS_PATCH 388 case XF86XK_AudioLowerVolume: 389 case XF86XK_AudioMute: 390 case XF86XK_AudioRaiseVolume: 391 case XF86XK_AudioPlay: 392 case XF86XK_AudioStop: 393 case XF86XK_AudioPrev: 394 case XF86XK_AudioNext: 395 XSendEvent(dpy, DefaultRootWindow(dpy), True, KeyPressMask, &ev); 396 break; 397 #endif // MEDIAKEYS_PATCH 398 default: 399 #if CONTROLCLEAR_PATCH 400 if (controlkeyclear && iscntrl((int)buf[0]) && !num) 401 continue; 402 #endif // CONTROLCLEAR_PATCH 403 if (num && !iscntrl((int)buf[0]) && 404 (len + num < sizeof(passwd))) 405 { 406 memcpy(passwd + len, buf, num); 407 len += num; 408 } else if (buf[0] == '\025') { /* ctrl-u clears input */ 409 explicit_bzero(&passwd, sizeof(passwd)); 410 len = 0; 411 } 412 #if KEYPRESS_FEEDBACK_PATCH 413 if (blocks_enabled) 414 for (screen = 0; screen < nscreens; screen++) 415 draw_key_feedback(dpy, locks, screen); 416 #endif // KEYPRESS_FEEDBACK_PATCH 417 break; 418 } 419 #if CAPSCOLOR_PATCH 420 color = len ? (caps ? CAPS : INPUT) : (failure || failonclear ? FAILED : INIT); 421 #else 422 color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT); 423 #endif // CAPSCOLOR_PATCH 424 if (running && oldc != color) { 425 for (screen = 0; screen < nscreens; screen++) { 426 #if DWM_LOGO_PATCH 427 drawlogo(dpy, locks[screen], color); 428 #elif BLUR_PIXELATED_SCREEN_PATCH || BACKGROUND_IMAGE_PATCH 429 if (locks[screen]->bgmap) 430 XSetWindowBackgroundPixmap(dpy, locks[screen]->win, locks[screen]->bgmap); 431 else 432 XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[0]); 433 XClearWindow(dpy, locks[screen]->win); 434 #else 435 XSetWindowBackground(dpy, 436 locks[screen]->win, 437 locks[screen]->colors[color]); 438 XClearWindow(dpy, locks[screen]->win); 439 #endif // BLUR_PIXELATED_SCREEN_PATCH 440 #if MESSAGE_PATCH || COLOR_MESSAGE_PATCH 441 writemessage(dpy, locks[screen]->win, screen); 442 #endif // MESSAGE_PATCH | COLOR_MESSAGE_PATCH 443 } 444 oldc = color; 445 } 446 } else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) { 447 rre = (XRRScreenChangeNotifyEvent*)&ev; 448 for (screen = 0; screen < nscreens; screen++) { 449 if (locks[screen]->win == rre->window) { 450 if (rre->rotation == RR_Rotate_90 || 451 rre->rotation == RR_Rotate_270) 452 XResizeWindow(dpy, locks[screen]->win, 453 rre->height, rre->width); 454 else 455 XResizeWindow(dpy, locks[screen]->win, 456 rre->width, rre->height); 457 XClearWindow(dpy, locks[screen]->win); 458 break; 459 } 460 } 461 } else { 462 for (screen = 0; screen < nscreens; screen++) 463 XRaiseWindow(dpy, locks[screen]->win); 464 } 465 466 #if AUTO_TIMEOUT_PATCH 467 } 468 469 time(¤ttime); 470 471 if (currenttime >= lasttouched + timeoffset) { 472 if (!runonce || !runflag) { 473 runflag = 1; 474 system(command); 475 } 476 lasttouched = currenttime; 477 } 478 usleep(50); // artificial sleep for 50ms 479 #endif // AUTO_TIMEOUT_PATCH 480 } 481 } 482 483 static struct lock * 484 lockscreen(Display *dpy, struct xrandr *rr, int screen) 485 { 486 char curs[] = {0, 0, 0, 0, 0, 0, 0, 0}; 487 int i, ptgrab, kbgrab; 488 struct lock *lock; 489 XColor color, dummy; 490 XSetWindowAttributes wa; 491 Cursor invisible; 492 #if DWM_LOGO_PATCH 493 #ifdef XINERAMA 494 XineramaScreenInfo *info; 495 int n; 496 #endif 497 #endif // DWM_LOGO_PATCH 498 #if AUTO_TIMEOUT_PATCH 499 time(&lasttouched); 500 #endif // AUTO_TIMEOUT_PATCH 501 502 if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(struct lock)))) 503 return NULL; 504 505 lock->screen = screen; 506 lock->root = RootWindow(dpy, lock->screen); 507 508 #if BLUR_PIXELATED_SCREEN_PATCH || BACKGROUND_IMAGE_PATCH 509 render_lock_image(dpy, lock, image); 510 #endif // BLUR_PIXELATED_SCREEN_PATCH | BACKGROUND_IMAGE_PATCH 511 512 for (i = 0; i < NUMCOLS; i++) { 513 XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen), 514 colorname[i], &color, &dummy); 515 lock->colors[i] = color.pixel; 516 } 517 518 #if DWM_LOGO_PATCH 519 lock->x = DisplayWidth(dpy, lock->screen); 520 lock->y = DisplayHeight(dpy, lock->screen); 521 #ifdef XINERAMA 522 if ((info = XineramaQueryScreens(dpy, &n))) { 523 lock->xoff = info[0].x_org; 524 lock->yoff = info[0].y_org; 525 lock->mw = info[0].width; 526 lock->mh = info[0].height; 527 } else 528 #endif // XINERAMA 529 { 530 lock->xoff = lock->yoff = 0; 531 lock->mw = lock->x; 532 lock->mh = lock->y; 533 } 534 lock->drawable = XCreatePixmap(dpy, lock->root, lock->x, lock->y, DefaultDepth(dpy, screen)); 535 lock->gc = XCreateGC(dpy, lock->root, 0, NULL); 536 XSetLineAttributes(dpy, lock->gc, 1, LineSolid, CapButt, JoinMiter); 537 #endif // DWM_LOGO_PATCH 538 539 /* init */ 540 wa.override_redirect = 1; 541 #if DWM_LOGO_PATCH && BLUR_PIXELATED_SCREEN_PATCH 542 #elif DWM_LOGO_PATCH 543 wa.background_pixel = lock->colors[BACKGROUND]; 544 #else 545 wa.background_pixel = lock->colors[INIT]; 546 #endif // DWM_LOGO_PATCH 547 lock->win = XCreateWindow(dpy, lock->root, 0, 0, 548 #if DWM_LOGO_PATCH 549 lock->x, 550 lock->y, 551 #else 552 DisplayWidth(dpy, lock->screen), 553 DisplayHeight(dpy, lock->screen), 554 #endif // DWM_LOGO_PATCH 555 0, DefaultDepth(dpy, lock->screen), 556 CopyFromParent, 557 DefaultVisual(dpy, lock->screen), 558 CWOverrideRedirect | CWBackPixel, &wa); 559 #if BLUR_PIXELATED_SCREEN_PATCH || BACKGROUND_IMAGE_PATCH 560 if (lock->bgmap) 561 XSetWindowBackgroundPixmap(dpy, lock->win, lock->bgmap); 562 #endif // BLUR_PIXELATED_SCREEN_PATCH | BACKGROUND_IMAGE_PATCH 563 lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8); 564 invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, 565 &color, &color, 0, 0); 566 XDefineCursor(dpy, lock->win, invisible); 567 568 #if DWM_LOGO_PATCH 569 resizerectangles(lock); 570 #endif // DWM_LOGO_PATCH 571 572 /* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */ 573 for (i = 0, ptgrab = kbgrab = -1; i < 6; i++) { 574 if (ptgrab != GrabSuccess) { 575 ptgrab = XGrabPointer(dpy, lock->root, False, 576 ButtonPressMask | ButtonReleaseMask | 577 PointerMotionMask, GrabModeAsync, 578 GrabModeAsync, None, 579 #if UNLOCKSCREEN_PATCH 580 None, 581 #else 582 invisible, 583 #endif // UNLOCKSCREEN_PATCH 584 CurrentTime); 585 } 586 if (kbgrab != GrabSuccess) { 587 kbgrab = XGrabKeyboard(dpy, lock->root, True, 588 GrabModeAsync, GrabModeAsync, CurrentTime); 589 } 590 591 /* input is grabbed: we can lock the screen */ 592 if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) { 593 #if !UNLOCKSCREEN_PATCH 594 #if VISUAL_UNLOCK_PATCH 595 if (!visual_unlock) 596 XMapRaised(dpy, lock->win); 597 #else 598 XMapRaised(dpy, lock->win); 599 #endif // VISUAL_UNLOCK_PATCH 600 #endif // UNLOCKSCREEN_PATCH 601 if (rr->active) 602 XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask); 603 604 XSelectInput(dpy, lock->root, SubstructureNotifyMask); 605 #if QUICKCANCEL_PATCH 606 locktime = time(NULL); 607 #endif // QUICKCANCEL_PATCH 608 #if DWM_LOGO_PATCH 609 drawlogo(dpy, lock, INIT); 610 #endif // DWM_LOGO_PATCH 611 #if ALPHA_PATCH 612 unsigned int opacity = (unsigned int)((double)alpha * 0xffffffff); 613 XChangeProperty(dpy, lock->win, XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False), XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&opacity, 1L); 614 XSync(dpy, False); 615 #endif // ALPHA_PATCH 616 return lock; 617 } 618 619 /* retry on AlreadyGrabbed but fail on other errors */ 620 if ((ptgrab != AlreadyGrabbed && ptgrab != GrabSuccess) || 621 (kbgrab != AlreadyGrabbed && kbgrab != GrabSuccess)) 622 break; 623 624 usleep(100000); 625 } 626 627 /* we couldn't grab all input: fail out */ 628 if (ptgrab != GrabSuccess) 629 fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n", 630 screen); 631 if (kbgrab != GrabSuccess) 632 fprintf(stderr, "slock: unable to grab keyboard for screen %d\n", 633 screen); 634 return NULL; 635 } 636 637 static void 638 usage(void) 639 { 640 die("usage: slock [-v] " 641 #if VISUAL_UNLOCK_PATCH 642 "[-u] " 643 #endif 644 #if MESSAGE_PATCH || COLOR_MESSAGE_PATCH 645 "[-f] [-m message] " 646 #endif 647 "[cmd [arg ...]]\n" 648 ); 649 } 650 651 int 652 main(int argc, char **argv) { 653 struct xrandr rr; 654 struct lock **locks; 655 struct passwd *pwd; 656 struct group *grp; 657 uid_t duid; 658 gid_t dgid; 659 const char *hash; 660 Display *dpy; 661 int s, nlocks, nscreens; 662 #if DPMS_PATCH 663 CARD16 standby, suspend, off; 664 #endif // DPMS_PATCH 665 #if MESSAGE_PATCH || COLOR_MESSAGE_PATCH 666 int i, count_fonts; 667 char **font_names; 668 #endif // MESSAGE_PATCH | COLOR_MESSAGE_PATCH 669 ARGBEGIN { 670 case 'v': 671 puts("slock-"VERSION); 672 return 0; 673 #if MESSAGE_PATCH || COLOR_MESSAGE_PATCH 674 case 'm': 675 message = EARGF(usage()); 676 break; 677 case 'f': 678 if (!(dpy = XOpenDisplay(NULL))) 679 die("slock: cannot open display\n"); 680 font_names = XListFonts(dpy, "*", 10000 /* list 10000 fonts*/, &count_fonts); 681 for (i=0; i<count_fonts; i++) { 682 fprintf(stderr, "%s\n", *(font_names+i)); 683 } 684 return 0; 685 #endif // MESSAGE_PATCH | COLOR_MESSAGE_PATCH 686 #if VISUAL_UNLOCK_PATCH 687 case 'u': 688 visual_unlock = 1; 689 break; 690 #endif // VISUAL_UNLOCK_PATCH 691 default: 692 usage(); 693 } ARGEND 694 695 /* validate drop-user and -group */ 696 errno = 0; 697 if (!(pwd = getpwnam(user))) 698 die("slock: getpwnam %s: %s\n", user, 699 errno ? strerror(errno) : "user entry not found"); 700 duid = pwd->pw_uid; 701 errno = 0; 702 if (!(grp = getgrnam(group))) 703 die("slock: getgrnam %s: %s\n", group, 704 errno ? strerror(errno) : "group entry not found"); 705 dgid = grp->gr_gid; 706 707 #ifdef __linux__ 708 dontkillme(); 709 #endif 710 711 #if PAMAUTH_PATCH 712 /* the contents of hash are used to transport the current user name */ 713 #endif // PAMAUTH_PATCH 714 hash = gethash(); 715 errno = 0; 716 #if !PAMAUTH_PATCH 717 if (!crypt("", hash)) 718 die("slock: crypt: %s\n", strerror(errno)); 719 #endif // PAMAUTH_PATCH 720 721 if (!(dpy = XOpenDisplay(NULL))) 722 die("slock: cannot open display\n"); 723 724 /* drop privileges */ 725 if (setgroups(0, NULL) < 0) 726 die("slock: setgroups: %s\n", strerror(errno)); 727 if (setgid(dgid) < 0) 728 die("slock: setgid: %s\n", strerror(errno)); 729 if (setuid(duid) < 0) 730 die("slock: setuid: %s\n", strerror(errno)); 731 732 #if XRESOURCES_PATCH 733 config_init(dpy); 734 #endif // XRESOURCES_PATCH 735 736 #if BLUR_PIXELATED_SCREEN_PATCH || BACKGROUND_IMAGE_PATCH 737 create_lock_image(dpy); 738 #endif // BLUR_PIXELATED_SCREEN_PATCH | BACKGROUND_IMAGE_PATCH 739 740 #if KEYPRESS_FEEDBACK_PATCH 741 time_t t; 742 srand((unsigned) time(&t)); 743 #endif // KEYPRESS_FEEDBACK_PATCH 744 745 /* check for Xrandr support */ 746 rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); 747 748 /* get number of screens in display "dpy" and blank them */ 749 nscreens = ScreenCount(dpy); 750 if (!(locks = calloc(nscreens, sizeof(struct lock *)))) 751 die("slock: out of memory\n"); 752 for (nlocks = 0, s = 0; s < nscreens; s++) { 753 if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) { 754 #if MESSAGE_PATCH || COLOR_MESSAGE_PATCH 755 writemessage(dpy, locks[s]->win, s); 756 #endif // MESSAGE_PATCH | COLOR_MESSAGE_PATCH 757 nlocks++; 758 } else { 759 break; 760 } 761 } 762 XSync(dpy, 0); 763 764 /* did we manage to lock everything? */ 765 if (nlocks != nscreens) 766 return 1; 767 768 #if DPMS_PATCH 769 /* DPMS magic to disable the monitor */ 770 #if VISUAL_UNLOCK_PATCH 771 if (visual_unlock) 772 monitortime = monitortime_vu; 773 #endif // VISUAL_UNLOCK_PATCH 774 775 if (!DPMSCapable(dpy)) 776 die("slock: DPMSCapable failed\n"); 777 if (!DPMSEnable(dpy)) 778 die("slock: DPMSEnable failed\n"); 779 if (!DPMSGetTimeouts(dpy, &standby, &suspend, &off)) 780 die("slock: DPMSGetTimeouts failed\n"); 781 if (!standby || !suspend || !off) 782 die("slock: at least one DPMS variable is zero\n"); 783 if (!DPMSSetTimeouts(dpy, monitortime, monitortime, monitortime)) 784 die("slock: DPMSSetTimeouts failed\n"); 785 786 XSync(dpy, 0); 787 #endif // DPMS_PATCH 788 789 /* run post-lock command */ 790 if (argc > 0) { 791 pid_t pid; 792 extern char **environ; 793 int err = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ); 794 if (err) { 795 die("slock: failed to execute post-lock command: %s: %s\n", 796 argv[0], strerror(err)); 797 } 798 } 799 800 /* everything is now blank. Wait for the correct password */ 801 readpw(dpy, &rr, locks, nscreens, hash); 802 #if DPMS_PATCH 803 /* reset DPMS values to inital ones */ 804 DPMSSetTimeouts(dpy, standby, suspend, off); 805 XSync(dpy, 0); 806 #endif // DPMS_PATCH 807 808 #if DWM_LOGO_PATCH 809 for (nlocks = 0, s = 0; s < nscreens; s++) { 810 XFreePixmap(dpy, locks[s]->drawable); 811 XFreeGC(dpy, locks[s]->gc); 812 } 813 814 XSync(dpy, 0); 815 XCloseDisplay(dpy); 816 #endif // DWM_LOGO_PATCH 817 818 return 0; 819 }