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