From a0df97d00735c3b259db233a4b6f15d0a81d3644 Mon Sep 17 00:00:00 2001 From: zcake Date: Mon, 8 Feb 2021 11:11:11 +0800 Subject: [PATCH] add Blured or pixelated screenshot patches --- config.def.h | 9 + config.h | 21 + config.mk | 4 +- explicit_bzero.o | Bin 0 -> 1544 bytes patches/slock-blur_pixelated_screen-1.4.diff | 356 +++++++++++++++++ slock | Bin 0 -> 23168 bytes slock.c | 78 +++- slock.c.orig | 387 +++++++++++++++++++ slock.o | Bin 0 -> 13848 bytes 9 files changed, 850 insertions(+), 5 deletions(-) create mode 100644 config.h create mode 100644 explicit_bzero.o create mode 100644 patches/slock-blur_pixelated_screen-1.4.diff create mode 100755 slock create mode 100644 slock.c.orig create mode 100644 slock.o diff --git a/config.def.h b/config.def.h index 9855e21..81a55af 100644 --- a/config.def.h +++ b/config.def.h @@ -10,3 +10,12 @@ static const char *colorname[NUMCOLS] = { /* treat a cleared input like a wrong password (color) */ static const int failonclear = 1; + +/*Enable blur*/ +#define BLUR +/*Set blur radius*/ +static const int blurRadius=5; +/*Enable Pixelation*/ +//#define PIXELATION +/*Set pixelation radius*/ +static const int pixelSize=0; diff --git a/config.h b/config.h new file mode 100644 index 0000000..d73e18b --- /dev/null +++ b/config.h @@ -0,0 +1,21 @@ +/* user and group to drop privileges to */ +static const char *user = "kc"; +static const char *group = "kc"; + +static const char *colorname[NUMCOLS] = { + [INIT] = "black", /* after initialization */ + [INPUT] = "#005577", /* during input */ + [FAILED] = "#CC3333", /* wrong password */ +}; + +/* treat a cleared input like a wrong password (color) */ +static const int failonclear = 1; + +/*Enable blur*/ +#define BLUR +/*Set blur radius*/ +static const int blurRadius=5; +/*Enable Pixelation*/ +//#define PIXELATION +/*Set pixelation radius*/ +static const int pixelSize=0; diff --git a/config.mk b/config.mk index 74429ae..d0c2f01 100644 --- a/config.mk +++ b/config.mk @@ -12,11 +12,11 @@ X11LIB = /usr/X11R6/lib # includes and libs INCS = -I. -I/usr/include -I${X11INC} -LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr +LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lImlib2 # flags CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H -CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} +CFLAGS = -std=c99 -pedantic -Wall -Ofast ${INCS} ${CPPFLAGS} LDFLAGS = -s ${LIBS} COMPATSRC = explicit_bzero.c diff --git a/explicit_bzero.o b/explicit_bzero.o new file mode 100644 index 0000000000000000000000000000000000000000..4a1f38e2ee9db95552d688e31c278bf12f35209f GIT binary patch literal 1544 zcmbu7PiqrV5Wr{CYOB^ZtscY*T|7uE`bb0&dXP;^{vgq!rr@P4oA_edX0u^;g|r}g z5Fs}|f=7>j1i^!T6uk%vN)JMv*?qHpKGus4yq$T!nRzoi?>(=z>IKUJ77K2}@s26L zr^2!AB&GvrVGcg@dSYSaWkMEK9N213zBea7DnCCHYEHgxHzyyzB<{w>#+qGf+}pZp zSIXjsC=;E=W#c-53tdnE>pd|ROYOO*^U7fzJOFE4w3g>)W?!STi2M@!l)ivEDT4YU zvFd#BRpI{pEZKh%sxuAWj`G}7Ig?q!z{?uvK1;}#kW*hINqy9}a4{p!au~wcxw{sxFKy<-%|3q#-2=nN2gi8sBMDUI8T(=*VX0^Brs_75W3_hYXEB8tOQ_t^^Nz!R|?#~>biu?M0PMIgF? z@5>>wVGv7!Z{d0rd)+;?e=>Y3Mqx0LVZ09_IYIW_Ug-H!b?|@6#&o(nnuRWo+N|mj z?d(4lUq(%{bkv^Jp?VNy1x}+T#BY$^C<)D-IL%y_U45h3>e!52LyOM**Zd0R(wW>R znu&1za}1Q``mEQGv#p0d(>I!J#@<2S3@-g`QTPk`pqPE}{8BGK2Ms#Y%zvi>njEOK znZJ!Z@BT{aK(0^sN4cEO_m@|jN*&S% +Date: Wed, 29 Apr 2020 13:52:42 +0200 +Subject: [PATCH 1/8] Added Bg patch and screenshot capabilities + +--- + config.mk | 2 +- + slock.c | 35 +++++++++++++++++++++++++++++++---- + 2 files changed, 32 insertions(+), 5 deletions(-) + +diff --git a/config.mk b/config.mk +index 74429ae..987819e 100644 +--- a/config.mk ++++ b/config.mk +@@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib + + # includes and libs + INCS = -I. -I/usr/include -I${X11INC} +-LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr ++LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lImlib2 + + # flags + CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H +diff --git a/slock.c b/slock.c +index 5ae738c..7c63f34 100644 +--- a/slock.c ++++ b/slock.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + #include "arg.h" + #include "util.h" +@@ -35,6 +36,7 @@ struct lock { + int screen; + Window root, win; + Pixmap pmap; ++ Pixmap bgmap; + unsigned long colors[NUMCOLS]; + }; + +@@ -46,6 +48,8 @@ struct xrandr { + + #include "config.h" + ++Imlib_Image image; ++ + static void + die(const char *errstr, ...) + { +@@ -190,9 +194,10 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, + color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT); + if (running && oldc != color) { + for (screen = 0; screen < nscreens; screen++) { +- XSetWindowBackground(dpy, +- locks[screen]->win, +- locks[screen]->colors[color]); ++ if(locks[screen]->bgmap) ++ XSetWindowBackgroundPixmap(dpy, locks[screen]->win, locks[screen]->bgmap); ++ else ++ XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[0]); + XClearWindow(dpy, locks[screen]->win); + } + oldc = color; +@@ -235,6 +240,17 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen) + lock->screen = screen; + lock->root = RootWindow(dpy, lock->screen); + ++ if(image) ++ { ++ lock->bgmap = XCreatePixmap(dpy, lock->root, DisplayWidth(dpy, lock->screen), DisplayHeight(dpy, lock->screen), DefaultDepth(dpy, lock->screen)); ++ imlib_context_set_image(image); ++ imlib_context_set_display(dpy); ++ imlib_context_set_visual(DefaultVisual(dpy, lock->screen)); ++ imlib_context_set_colormap(DefaultColormap(dpy, lock->screen)); ++ imlib_context_set_drawable(lock->bgmap); ++ imlib_render_image_on_drawable(0, 0); ++ imlib_free_image(); ++ } + for (i = 0; i < NUMCOLS; i++) { + XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen), + colorname[i], &color, &dummy); +@@ -251,6 +267,8 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen) + CopyFromParent, + DefaultVisual(dpy, lock->screen), + CWOverrideRedirect | CWBackPixel, &wa); ++ if(lock->bgmap) ++ XSetWindowBackgroundPixmap(dpy, lock->win, lock->bgmap); + lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8); + invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, + &color, &color, 0, 0); +@@ -354,7 +372,16 @@ main(int argc, char **argv) { + die("slock: setgid: %s\n", strerror(errno)); + if (setuid(duid) < 0) + die("slock: setuid: %s\n", strerror(errno)); +- ++ ++ /*Create screenshot Image*/ ++ Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy)); ++ image = imlib_create_image(scr->width,scr->height); ++ imlib_context_set_image(image); ++ imlib_context_set_display(dpy); ++ imlib_context_set_visual(DefaultVisual(dpy,0)); ++ imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr))); ++ imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1); ++ + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); + +-- +2.27.0 + + +From 9d89604ac52b0949d047dae2f9b78cb5085ee1a2 Mon Sep 17 00:00:00 2001 +From: Lars Niesen +Date: Wed, 29 Apr 2020 14:15:59 +0200 +Subject: [PATCH 2/8] Added blur function + +--- + config.def.h | 3 +++ + slock.c | 3 ++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index c8e52d6..fcc1b39 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -10,3 +10,6 @@ static const char *colorname[NUMCOLS] = { + + /* treat a cleared input like a wrong password (color) */ + static const int failonclear = 1; ++ ++/*Set Blur radius*/ ++static const int blurRadius=5; +\ No newline at end of file +diff --git a/slock.c b/slock.c +index 7c63f34..0f24cd7 100644 +--- a/slock.c ++++ b/slock.c +@@ -372,7 +372,7 @@ main(int argc, char **argv) { + die("slock: setgid: %s\n", strerror(errno)); + if (setuid(duid) < 0) + die("slock: setuid: %s\n", strerror(errno)); +- ++ + /*Create screenshot Image*/ + Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy)); + image = imlib_create_image(scr->width,scr->height); +@@ -381,6 +381,7 @@ main(int argc, char **argv) { + imlib_context_set_visual(DefaultVisual(dpy,0)); + imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr))); + imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1); ++ imlib_image_blur(blurRadius); + + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); +-- +2.27.0 + + +From 069aabd7e30244befd4efe74c85d3468ed076c21 Mon Sep 17 00:00:00 2001 +From: Lars Niesen +Date: Wed, 29 Apr 2020 17:33:09 +0200 +Subject: [PATCH 4/8] added Pixelation + +--- + config.def.h | 3 ++- + slock.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 44 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index fcc1b39..1c1aef3 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -12,4 +12,5 @@ static const char *colorname[NUMCOLS] = { + static const int failonclear = 1; + + /*Set Blur radius*/ +-static const int blurRadius=5; +\ No newline at end of file ++static const int blurRadius=0; ++static const int pixelSize=5; +diff --git a/slock.c b/slock.c +index 0f24cd7..33ca569 100644 +--- a/slock.c ++++ b/slock.c +@@ -381,7 +381,49 @@ main(int argc, char **argv) { + imlib_context_set_visual(DefaultVisual(dpy,0)); + imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr))); + imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1); ++ ++ /*Blur function*/ + imlib_image_blur(blurRadius); ++ ++ ++ /*Pixelation*/ ++ int width = scr->width; ++ int height = scr->height; ++ ++ for(int y = 0; y < height; y += pixelSize) ++ { ++ for(int x = 0; x < width; x += pixelSize) ++ { ++ int red = 0; ++ int green = 0; ++ int blue = 0; ++ ++ Imlib_Color pixel; ++ Imlib_Color* pp; ++ pp = &pixel; ++ for(int j = 0; j < pixelSize && j < height; j++) ++ { ++ for(int i = 0; i < pixelSize && i < width; i++) ++ { ++ imlib_image_query_pixel(x+i,y+j,pp); ++ red += pixel.red; ++ green += pixel.green; ++ blue += pixel.blue; ++ } ++ } ++ red /= (pixelSize*pixelSize); ++ green /= (pixelSize*pixelSize); ++ blue /= (pixelSize*pixelSize); ++ printf("R/G/B: %i/%i/%i\n",red,green,blue); ++ imlib_context_set_color(red,green,blue,pixel.alpha); ++ imlib_image_fill_rectangle(x,y,pixelSize,pixelSize); ++ red = 0; ++ green = 0; ++ blue = 0; ++ } ++ } ++ ++ + + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); +-- +2.27.0 + + +From 109bac015c1c7fbf8440fb42588fe7e0e9cb5e62 Mon Sep 17 00:00:00 2001 +From: Lars Niesen +Date: Wed, 29 Apr 2020 17:42:39 +0200 +Subject: [PATCH 6/8] removed debug printf + +--- + slock.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/slock.c b/slock.c +index 33ca569..f54c459 100644 +--- a/slock.c ++++ b/slock.c +@@ -414,7 +414,6 @@ main(int argc, char **argv) { + red /= (pixelSize*pixelSize); + green /= (pixelSize*pixelSize); + blue /= (pixelSize*pixelSize); +- printf("R/G/B: %i/%i/%i\n",red,green,blue); + imlib_context_set_color(red,green,blue,pixel.alpha); + imlib_image_fill_rectangle(x,y,pixelSize,pixelSize); + red = 0; +-- +2.27.0 + + +From a13a0f4ac86f82e4dff145b7ebd93e52d07492c9 Mon Sep 17 00:00:00 2001 +From: Lars Niesen +Date: Sun, 3 May 2020 18:03:38 +0200 +Subject: [PATCH 7/8] Changed compilerflag to fast + +--- + config.mk | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/config.mk b/config.mk +index 987819e..d0c2f01 100644 +--- a/config.mk ++++ b/config.mk +@@ -16,7 +16,7 @@ LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lImlib2 + + # flags + CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H +-CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} ++CFLAGS = -std=c99 -pedantic -Wall -Ofast ${INCS} ${CPPFLAGS} + LDFLAGS = -s ${LIBS} + COMPATSRC = explicit_bzero.c + +-- +2.27.0 + + +From 31a7001c4954606c066cc3df4318fafd6d216bcd Mon Sep 17 00:00:00 2001 +From: Lars Niesen +Date: Mon, 4 May 2020 10:00:40 +0200 +Subject: [PATCH 8/8] Added defines for BLUR/PIXELATION to remove from code by + compilation + +--- + config.def.h | 11 ++++++++--- + slock.c | 9 ++++++--- + 2 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c1aef3..5407953 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -11,6 +11,11 @@ static const char *colorname[NUMCOLS] = { + /* treat a cleared input like a wrong password (color) */ + static const int failonclear = 1; + +-/*Set Blur radius*/ +-static const int blurRadius=0; +-static const int pixelSize=5; ++/*Enable blur*/ ++#define BLUR ++/*Set blur radius*/ ++static const int blurRadius=5; ++/*Enable Pixelation*/ ++//#define PIXELATION ++/*Set pixelation radius*/ ++static const int pixelSize=0; +diff --git a/slock.c b/slock.c +index f54c459..1a4d6e3 100644 +--- a/slock.c ++++ b/slock.c +@@ -381,11 +381,14 @@ main(int argc, char **argv) { + imlib_context_set_visual(DefaultVisual(dpy,0)); + imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr))); + imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1); +- ++ ++#ifdef BLUR ++ + /*Blur function*/ + imlib_image_blur(blurRadius); ++#endif // BLUR + +- ++#ifdef PIXELATION + /*Pixelation*/ + int width = scr->width; + int height = scr->height; +@@ -423,7 +426,7 @@ main(int argc, char **argv) { + } + + +- ++#endif + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); + +-- +2.27.0 + diff --git a/slock b/slock new file mode 100755 index 0000000000000000000000000000000000000000..509c83c2435c065e8374517fe6feca2c0136daf9 GIT binary patch literal 23168 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 WvPxC9$Pvc{vi$RuqRh;K>^}i@jQVQ; literal 0 HcmV?d00001 diff --git a/slock.c b/slock.c index d2f0886..84ef0b4 100644 --- a/slock.c +++ b/slock.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "arg.h" #include "util.h" @@ -35,6 +36,7 @@ struct lock { int screen; Window root, win; Pixmap pmap; + Pixmap bgmap; unsigned long colors[NUMCOLS]; }; @@ -46,6 +48,8 @@ struct xrandr { #include "config.h" +Imlib_Image image; + static void die(const char *errstr, ...) { @@ -190,9 +194,10 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT); if (running && oldc != color) { for (screen = 0; screen < nscreens; screen++) { - XSetWindowBackground(dpy, - locks[screen]->win, - locks[screen]->colors[color]); + if(locks[screen]->bgmap) + XSetWindowBackgroundPixmap(dpy, locks[screen]->win, locks[screen]->bgmap); + else + XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[0]); XClearWindow(dpy, locks[screen]->win); } oldc = color; @@ -227,6 +232,17 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen) lock->screen = screen; lock->root = RootWindow(dpy, lock->screen); + if(image) + { + lock->bgmap = XCreatePixmap(dpy, lock->root, DisplayWidth(dpy, lock->screen), DisplayHeight(dpy, lock->screen), DefaultDepth(dpy, lock->screen)); + imlib_context_set_image(image); + imlib_context_set_display(dpy); + imlib_context_set_visual(DefaultVisual(dpy, lock->screen)); + imlib_context_set_colormap(DefaultColormap(dpy, lock->screen)); + imlib_context_set_drawable(lock->bgmap); + imlib_render_image_on_drawable(0, 0); + imlib_free_image(); + } for (i = 0; i < NUMCOLS; i++) { XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen), colorname[i], &color, &dummy); @@ -243,6 +259,8 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen) CopyFromParent, DefaultVisual(dpy, lock->screen), CWOverrideRedirect | CWBackPixel, &wa); + if(lock->bgmap) + XSetWindowBackgroundPixmap(dpy, lock->win, lock->bgmap); lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8); invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, &color, &color, 0, 0); @@ -347,6 +365,60 @@ main(int argc, char **argv) { if (setuid(duid) < 0) die("slock: setuid: %s\n", strerror(errno)); + /*Create screenshot Image*/ + Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy)); + image = imlib_create_image(scr->width,scr->height); + imlib_context_set_image(image); + imlib_context_set_display(dpy); + imlib_context_set_visual(DefaultVisual(dpy,0)); + imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr))); + imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1); + +#ifdef BLUR + + /*Blur function*/ + imlib_image_blur(blurRadius); +#endif // BLUR + +#ifdef PIXELATION + /*Pixelation*/ + int width = scr->width; + int height = scr->height; + + for(int y = 0; y < height; y += pixelSize) + { + for(int x = 0; x < width; x += pixelSize) + { + int red = 0; + int green = 0; + int blue = 0; + + Imlib_Color pixel; + Imlib_Color* pp; + pp = &pixel; + for(int j = 0; j < pixelSize && j < height; j++) + { + for(int i = 0; i < pixelSize && i < width; i++) + { + imlib_image_query_pixel(x+i,y+j,pp); + red += pixel.red; + green += pixel.green; + blue += pixel.blue; + } + } + red /= (pixelSize*pixelSize); + green /= (pixelSize*pixelSize); + blue /= (pixelSize*pixelSize); + imlib_context_set_color(red,green,blue,pixel.alpha); + imlib_image_fill_rectangle(x,y,pixelSize,pixelSize); + red = 0; + green = 0; + blue = 0; + } + } + + +#endif /* check for Xrandr support */ rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); diff --git a/slock.c.orig b/slock.c.orig new file mode 100644 index 0000000..d2f0886 --- /dev/null +++ b/slock.c.orig @@ -0,0 +1,387 @@ +/* See LICENSE file for license details. */ +#define _XOPEN_SOURCE 500 +#if HAVE_SHADOW_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arg.h" +#include "util.h" + +char *argv0; + +enum { + INIT, + INPUT, + FAILED, + NUMCOLS +}; + +struct lock { + int screen; + Window root, win; + Pixmap pmap; + unsigned long colors[NUMCOLS]; +}; + +struct xrandr { + int active; + int evbase; + int errbase; +}; + +#include "config.h" + +static void +die(const char *errstr, ...) +{ + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(1); +} + +#ifdef __linux__ +#include +#include + +static void +dontkillme(void) +{ + FILE *f; + const char oomfile[] = "/proc/self/oom_score_adj"; + + if (!(f = fopen(oomfile, "w"))) { + if (errno == ENOENT) + return; + die("slock: fopen %s: %s\n", oomfile, strerror(errno)); + } + fprintf(f, "%d", OOM_SCORE_ADJ_MIN); + if (fclose(f)) { + if (errno == EACCES) + die("slock: unable to disable OOM killer. " + "Make sure to suid or sgid slock.\n"); + else + die("slock: fclose %s: %s\n", oomfile, strerror(errno)); + } +} +#endif + +static const char * +gethash(void) +{ + const char *hash; + struct passwd *pw; + + /* Check if the current user has a password entry */ + errno = 0; + if (!(pw = getpwuid(getuid()))) { + if (errno) + die("slock: getpwuid: %s\n", strerror(errno)); + else + die("slock: cannot retrieve password entry\n"); + } + hash = pw->pw_passwd; + +#if HAVE_SHADOW_H + if (!strcmp(hash, "x")) { + struct spwd *sp; + if (!(sp = getspnam(pw->pw_name))) + die("slock: getspnam: cannot retrieve shadow entry. " + "Make sure to suid or sgid slock.\n"); + hash = sp->sp_pwdp; + } +#else + if (!strcmp(hash, "*")) { +#ifdef __OpenBSD__ + if (!(pw = getpwuid_shadow(getuid()))) + die("slock: getpwnam_shadow: cannot retrieve shadow entry. " + "Make sure to suid or sgid slock.\n"); + hash = pw->pw_passwd; +#else + die("slock: getpwuid: cannot retrieve shadow entry. " + "Make sure to suid or sgid slock.\n"); +#endif /* __OpenBSD__ */ + } +#endif /* HAVE_SHADOW_H */ + + return hash; +} + +static void +readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, + const char *hash) +{ + XRRScreenChangeNotifyEvent *rre; + char buf[32], passwd[256], *inputhash; + int num, screen, running, failure, oldc; + unsigned int len, color; + KeySym ksym; + XEvent ev; + + len = 0; + running = 1; + failure = 0; + oldc = INIT; + + while (running && !XNextEvent(dpy, &ev)) { + if (ev.type == KeyPress) { + explicit_bzero(&buf, sizeof(buf)); + num = XLookupString(&ev.xkey, buf, sizeof(buf), &ksym, 0); + if (IsKeypadKey(ksym)) { + if (ksym == XK_KP_Enter) + ksym = XK_Return; + else if (ksym >= XK_KP_0 && ksym <= XK_KP_9) + ksym = (ksym - XK_KP_0) + XK_0; + } + if (IsFunctionKey(ksym) || + IsKeypadKey(ksym) || + IsMiscFunctionKey(ksym) || + IsPFKey(ksym) || + IsPrivateKeypadKey(ksym)) + continue; + switch (ksym) { + case XK_Return: + passwd[len] = '\0'; + errno = 0; + if (!(inputhash = crypt(passwd, hash))) + fprintf(stderr, "slock: crypt: %s\n", strerror(errno)); + else + running = !!strcmp(inputhash, hash); + if (running) { + XBell(dpy, 100); + failure = 1; + } + explicit_bzero(&passwd, sizeof(passwd)); + len = 0; + break; + case XK_Escape: + explicit_bzero(&passwd, sizeof(passwd)); + len = 0; + break; + case XK_BackSpace: + if (len) + passwd[len--] = '\0'; + break; + default: + if (num && !iscntrl((int)buf[0]) && + (len + num < sizeof(passwd))) { + memcpy(passwd + len, buf, num); + len += num; + } + break; + } + color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT); + if (running && oldc != color) { + for (screen = 0; screen < nscreens; screen++) { + XSetWindowBackground(dpy, + locks[screen]->win, + locks[screen]->colors[color]); + XClearWindow(dpy, locks[screen]->win); + } + oldc = color; + } + } else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) { + rre = (XRRScreenChangeNotifyEvent*)&ev; + for (screen = 0; screen < nscreens; screen++) { + if (locks[screen]->win == rre->window) { + XResizeWindow(dpy, locks[screen]->win, + rre->width, rre->height); + XClearWindow(dpy, locks[screen]->win); + } + } + } else for (screen = 0; screen < nscreens; screen++) + XRaiseWindow(dpy, locks[screen]->win); + } +} + +static struct lock * +lockscreen(Display *dpy, struct xrandr *rr, int screen) +{ + char curs[] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, ptgrab, kbgrab; + struct lock *lock; + XColor color, dummy; + XSetWindowAttributes wa; + Cursor invisible; + + if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(struct lock)))) + return NULL; + + lock->screen = screen; + lock->root = RootWindow(dpy, lock->screen); + + for (i = 0; i < NUMCOLS; i++) { + XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen), + colorname[i], &color, &dummy); + lock->colors[i] = color.pixel; + } + + /* init */ + wa.override_redirect = 1; + wa.background_pixel = lock->colors[INIT]; + lock->win = XCreateWindow(dpy, lock->root, 0, 0, + DisplayWidth(dpy, lock->screen), + DisplayHeight(dpy, lock->screen), + 0, DefaultDepth(dpy, lock->screen), + CopyFromParent, + DefaultVisual(dpy, lock->screen), + CWOverrideRedirect | CWBackPixel, &wa); + lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8); + invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, + &color, &color, 0, 0); + XDefineCursor(dpy, lock->win, invisible); + + /* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */ + for (i = 0, ptgrab = kbgrab = -1; i < 6; i++) { + if (ptgrab != GrabSuccess) { + ptgrab = XGrabPointer(dpy, lock->root, False, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, + GrabModeAsync, None, invisible, CurrentTime); + } + if (kbgrab != GrabSuccess) { + kbgrab = XGrabKeyboard(dpy, lock->root, True, + GrabModeAsync, GrabModeAsync, CurrentTime); + } + + /* input is grabbed: we can lock the screen */ + if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) { + XMapRaised(dpy, lock->win); + if (rr->active) + XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask); + + XSelectInput(dpy, lock->root, SubstructureNotifyMask); + return lock; + } + + /* retry on AlreadyGrabbed but fail on other errors */ + if ((ptgrab != AlreadyGrabbed && ptgrab != GrabSuccess) || + (kbgrab != AlreadyGrabbed && kbgrab != GrabSuccess)) + break; + + usleep(100000); + } + + /* we couldn't grab all input: fail out */ + if (ptgrab != GrabSuccess) + fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n", + screen); + if (kbgrab != GrabSuccess) + fprintf(stderr, "slock: unable to grab keyboard for screen %d\n", + screen); + return NULL; +} + +static void +usage(void) +{ + die("usage: slock [-v] [cmd [arg ...]]\n"); +} + +int +main(int argc, char **argv) { + struct xrandr rr; + struct lock **locks; + struct passwd *pwd; + struct group *grp; + uid_t duid; + gid_t dgid; + const char *hash; + Display *dpy; + int s, nlocks, nscreens; + + ARGBEGIN { + case 'v': + fprintf(stderr, "slock-"VERSION"\n"); + return 0; + default: + usage(); + } ARGEND + + /* validate drop-user and -group */ + errno = 0; + if (!(pwd = getpwnam(user))) + die("slock: getpwnam %s: %s\n", user, + errno ? strerror(errno) : "user entry not found"); + duid = pwd->pw_uid; + errno = 0; + if (!(grp = getgrnam(group))) + die("slock: getgrnam %s: %s\n", group, + errno ? strerror(errno) : "group entry not found"); + dgid = grp->gr_gid; + +#ifdef __linux__ + dontkillme(); +#endif + + hash = gethash(); + errno = 0; + if (!crypt("", hash)) + die("slock: crypt: %s\n", strerror(errno)); + + if (!(dpy = XOpenDisplay(NULL))) + die("slock: cannot open display\n"); + + /* drop privileges */ + if (setgroups(0, NULL) < 0) + die("slock: setgroups: %s\n", strerror(errno)); + if (setgid(dgid) < 0) + die("slock: setgid: %s\n", strerror(errno)); + if (setuid(duid) < 0) + die("slock: setuid: %s\n", strerror(errno)); + + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); + + /* get number of screens in display "dpy" and blank them */ + nscreens = ScreenCount(dpy); + if (!(locks = calloc(nscreens, sizeof(struct lock *)))) + die("slock: out of memory\n"); + for (nlocks = 0, s = 0; s < nscreens; s++) { + if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) + nlocks++; + else + break; + } + XSync(dpy, 0); + + /* did we manage to lock everything? */ + if (nlocks != nscreens) + return 1; + + /* run post-lock command */ + if (argc > 0) { + switch (fork()) { + case -1: + die("slock: fork failed: %s\n", strerror(errno)); + case 0: + if (close(ConnectionNumber(dpy)) < 0) + die("slock: close: %s\n", strerror(errno)); + execvp(argv[0], argv); + fprintf(stderr, "slock: execvp %s: %s\n", argv[0], strerror(errno)); + _exit(1); + } + } + + /* everything is now blank. Wait for the correct password */ + readpw(dpy, &rr, locks, nscreens, hash); + + return 0; +} diff --git a/slock.o b/slock.o new file mode 100644 index 0000000000000000000000000000000000000000..a6423e5bdc046df67235dad190dc2810af8fe4ff GIT binary patch literal 13848 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 yHx@C3