lock

Fork of xl, the simplest screen locker
git clone git://git.laack.co/lock.git
Log | Files | Refs | README | LICENSE

commit 269b78729601107d10ba648fe2910d9630c0cb6a
Author: Andrew Laack <andrew@laack.co>
Date:   Tue, 15 Sep 2026 08:37:45 -0500

fork from dannyfiresnake/xl

Diffstat:
ALICENSE | 21+++++++++++++++++++++
AMakefile | 27+++++++++++++++++++++++++++
AREADME.md | 17+++++++++++++++++
Amain.c | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 155 insertions(+), 0 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 dannyfiresnake + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile @@ -0,0 +1,27 @@ +# uncomment next line if you need shadow passwd support +#NEEDSHADOW= -DNEED_SHADOW + +X11HOME = /usr/X11R6 + +CC = gcc +CFLAGS = -O2 -Wall -I${X11HOME}/include ${NEEDSHADOW} +LIBS = -L${X11HOME}/lib -lX11 + +# Uncomment for systems with libcrypt +LIBS += -lcrypt + +# uncomment if you are running under solaris +#LIBS += -lnsl -lsocket + +OBJS = main.o + +all: xl + +xl: $(OBJS) + $(CC) $(CFLAGS) -o xl $(OBJS) $(LIBS) + +clean: + rm -f $(OBJS) + +realclean: clean + rm -f xl diff --git a/README.md b/README.md @@ -0,0 +1,17 @@ +xl: The simple X11 lock +== + +xscreensaver, xlock, xlockmore, all of them, completley useless. They have +overflows, they have buggy drawning routines, they are very prone to crashing. +The more complex they get, the more useless they are. If a screen locking +program decides to crash on me, its not doing a very good job of keeping my +terminal locked. I've had many people just go to my screen and hit tons of keys +just to make it crash, or cycling the screen saver to get to a certain one +known to crash. Absolutly ridiculous! + +This is my solution to the problem. Very simple, very small, very few features. +Doesn't even blank your screen, all this program does is lock your keyboard and +mouse, and only unlocks it if you type your login password and hit return. + +You can also override the password by specifying it as the first argument of +the command line. A third way is to set the XLPASSWD environment variable. diff --git a/main.c b/main.c @@ -0,0 +1,90 @@ +/* + * Simple, transparent screen locker in X11 + */ +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <crypt.h> +#include <string.h> +#include <pwd.h> + +#ifdef NEED_SHADOW +#include <shadow.h> +#endif + +int +main(int argc, char *argv[]) +{ + Display *display; + Window root; + int len = 0, i; + XEvent ev; + char keybuffer[256], *passwd; + + if (argc > 1) { + setenv("XLPASSWD", argv[1], 1); + execl("/proc/self/exe", argv[0], NULL); + fprintf(stderr, "failed to execute self, use XLPASSWD environment\n"); + exit(1); + } + else if ((passwd = getenv("XLPASSWD"))) + passwd = strdup(crypt(passwd, "ax")); + else { +#ifndef NEED_SHADOW + passwd = getpwuid(getuid())->pw_passwd; +#else + { + struct spwd *sp = getspnam(getpwuid(getuid())->pw_name); + if (sp) + passwd = sp->sp_pwdp; + else { + fprintf(stderr, "could not get shadow entry\n"); + exit(1); + } + } +#endif + if (!passwd) { + fprintf(stderr, "could not get passwd\n"); + exit(1); + } + } + + if (strlen(passwd) < 2) { + fprintf(stderr, "passwd too short\n"); + exit(1); + } + + if ((display = XOpenDisplay(NULL)) == NULL) { + fprintf(stderr, "could not connect to $DISPLAY\n"); + exit(1); + } + + root = DefaultRootWindow(display); + XGrabPointer(display, root, 1, ButtonPress, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + XGrabKeyboard(display, root, 0, GrabModeAsync, GrabModeAsync, CurrentTime); + XSelectInput(display, root, KeyPressMask); + + while (XNextEvent(display, &ev), 1) { + if (ev.type == KeyPress) { + KeySym keysym; + XComposeStatus compose; + if (len > sizeof(keybuffer)-10) + len = 0; + i = XLookupString(&ev.xkey, keybuffer+len, 10, &keysym, &compose); + + if (keysym == XK_Return) { + keybuffer[len] = 0; + if (len && !strcmp(crypt(keybuffer, passwd), passwd)) { + XUngrabKeyboard(display, CurrentTime); + XUngrabPointer(display, CurrentTime); + exit(0); + } else + len = 0; + } else + len += i; + } + } +}