aboutsummaryrefslogtreecommitdiff
path: root/slock.c
blob: 12c991f9af45477fda6e469db38e6fdaa3f24080 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com>
 * See LICENSE file for license details.
 */
#define _XOPEN_SOURCE 500

#if HAVE_SHADOW_H
#include <shadow.h>
#else
#include <pwd.h>
#endif

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

int
main(int argc, char **argv) {
	char curs[] = {0, 0, 0, 0, 0, 0, 0, 0};
	char buf[32], passwd[256];
	int num, screen;
#if HAVE_SHADOW_H
	struct spwd *sp;
#else
	struct passwd *pw;
#endif
	unsigned int len;
	Bool running = True;
	Cursor invisible;
	Display *dpy;
	KeySym ksym;
	Pixmap pmap;
	Window w;
	XColor black, dummy;
	XEvent ev;
	XSetWindowAttributes wa;

	if((argc > 1) && !strncmp(argv[1], "-v", 3)) {
		fputs("slock-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout);
		exit(EXIT_SUCCESS);
	}
	if(geteuid() != 0) {
		fputs("slock: cannot retrieve password entry (make sure to suid slock)\n", stderr);
		exit(EXIT_FAILURE);
	}
#if HAVE_SHADOW_H
	sp = getspnam(getenv("USER"));
	endspent();
#else
	pw = getpwuid(getuid());
	endpwent();
#endif
	if(!(dpy = XOpenDisplay(0))) {
		fputs("slock: cannot open display\n", stderr);
		exit(EXIT_FAILURE);
	}
	screen = DefaultScreen(dpy);

	/* init */
	passwd[0] = 0;
	while(XGrabKeyboard(dpy, RootWindow(dpy, screen), True, GrabModeAsync,
			 GrabModeAsync, CurrentTime) != GrabSuccess)
		usleep(1000);

	wa.override_redirect = 1;
	wa.background_pixel = BlackPixel(dpy, screen);
	w = XCreateWindow(dpy, RootWindow(dpy, screen), 0, 0,
			DisplayWidth(dpy, screen), DisplayHeight(dpy, screen),
			0, DefaultDepth(dpy, screen), CopyFromParent,
			DefaultVisual(dpy, screen), CWOverrideRedirect | CWBackPixel, &wa);

	XAllocNamedColor(dpy, DefaultColormap(dpy, screen), "black", &black, &dummy);
	pmap = XCreateBitmapFromData(dpy, w, curs, 8, 8);
	invisible = XCreatePixmapCursor(dpy, pmap, pmap, &black, &black, 0, 0);
	XDefineCursor(dpy, w, invisible);
	XMapRaised(dpy, w);
	XSync(dpy, False);

	/* main event loop */
	while(running && !XNextEvent(dpy, &ev))
		if(ev.type == KeyPress) {
			len = strlen(passwd);
			buf[0] = 0;
			num = XLookupString(&ev.xkey, buf, sizeof(buf), &ksym, 0);
			if(IsFunctionKey(ksym) || IsKeypadKey(ksym)
					|| IsMiscFunctionKey(ksym) || IsPFKey(ksym)
					|| IsPrivateKeypadKey(ksym))
				continue;
			/* first check if a control mask is omitted */
			if(ev.xkey.state & ControlMask) {
				switch (ksym) {
				case XK_h:
				case XK_H: ksym = XK_BackSpace;
					break;
				case XK_u:
				case XK_U: passwd[0] = 0;
					continue;
				}
			}
			switch(ksym) {
			case XK_Return:
#if HAVE_SHADOW_H
				if((running = strncmp(crypt(passwd, sp->sp_pwdp), sp->sp_pwdp, sizeof(passwd))))
#else
				if((running = strncmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd, sizeof(passwd))))
#endif
					XBell(dpy, 100);
				passwd[0] = 0;
				break;
			case XK_Escape:
				passwd[0] = 0;
				break;
			case XK_BackSpace:
				if(len)
					passwd[--len] = 0;
				break;
			default:
				if(num && !iscntrl((int) buf[0])) {
					buf[num] = 0;
					if(len)
						strncat(passwd, buf, sizeof(passwd));
					else
						strncpy(passwd, buf, sizeof(passwd));
				}
				break;
			}
		}
	XFreePixmap(dpy, pmap);
	XDestroyWindow(dpy, w);
	XCloseDisplay(dpy);
	return 0;
}