i3lock-color

The world's most popular non-default computer lockscreen.
Index Commits Files Refs README LICENSE
commit 715e46b45e0077e265bfb42f6b71b00923086bcf
parent ded5d6eed493f9bf08df6c875fee80e9e6eff262
Author: Michael Stapelberg <michael+x200@stapelberg.de>
Date:   Sun, 10 May 2009 12:22:41 +0200

Implement PAM support (and retab! the file)

Diffstat:
Mconfig.mk | 2+-
Mi3lock.c | 326+++++++++++++++++++++++++++++++++++++++++--------------------------------------
2 files changed, 171 insertions(+), 157 deletions(-)
diff --git a/config.mk b/config.mk
@@ -13,7 +13,7 @@ MANDIR = $(DESTDIR)$(PREFIX)/share/man
 
 # includes and libs
 INCS = -I. -I/usr/include -I${X11INC}
-LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11
+LIBS = -L/usr/lib -L${X11LIB} -lX11 -lpam
 
 # flags
 CPPFLAGS = -DVERSION=\"${VERSION}\" -DHAVE_SHADOW_H
diff --git a/i3lock.c b/i3lock.c
@@ -1,11 +1,22 @@
-/* See LICENSE file for license details. */
+/*
+ * vim:ts=8:expandtab
+ *
+ * i3lock - an improved version of slock
+ *
+ * i3lock © 2009 Michael Stapelberg and contributors
+ * slock  © 2006-2008 Anselm R Garbe
+ *
+ * See file LICENSE for license information.
+ *
+ * Note that on any error (calloc is out of memory for example)
+ * we do not do anything so that the user can fix the error by
+ * himself (kill X to get more free memory or stop some other
+ * program using SSH/console).
+ *
+ */
 #define _XOPEN_SOURCE 500
-#if HAVE_SHADOW_H
-#include <shadow.h>
-#endif
 
 #include <ctype.h>
-#include <pwd.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -15,161 +26,164 @@
 #include <X11/keysym.h>
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
+#include <stdbool.h>
 
-#if HAVE_BSD_AUTH
-#include <login_cap.h>
-#include <bsd_auth.h>
-#endif
+#include <security/pam_appl.h>
 
-static void
-die(const char *errstr, ...) {
-    va_list ap;
+static char passwd[256];
 
-    va_start(ap, errstr);
-    vfprintf(stderr, errstr, ap);
-    va_end(ap);
-    exit(EXIT_FAILURE);
+static void die(const char *errstr, ...) {
+        va_list ap;
+
+        va_start(ap, errstr);
+        vfprintf(stderr, errstr, ap);
+        va_end(ap);
+        exit(EXIT_FAILURE);
 }
 
-#ifndef HAVE_BSD_AUTH
-static const char *
-get_password() { /* only run as root */
-    const char *rval;
-    struct passwd *pw;
-
-    if(geteuid() != 0)
-        die("slock: cannot retrieve password entry (make sure to suid slock)\n");
-    pw = getpwuid(getuid());
-    endpwent();
-    rval =  pw->pw_passwd;
-
-#if HAVE_SHADOW_H
-    {
-        struct spwd *sp;
-        sp = getspnam(getenv("USER"));
-        endspent();
-        rval = sp->sp_pwdp;
-    }
-#endif
-
-    /* drop privileges */
-    if(setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0)
-        die("slock: cannot drop privileges\n");
-    return rval;
+/*
+ * Callback function for PAM. We only react on password request callbacks.
+ *
+ */
+static int conv_callback(int num_msg, const struct pam_message **msg,
+                         struct pam_response **resp, void *appdata_ptr) {
+        if (num_msg == 0)
+                return 1;
+
+        /* PAM expects an arry of responses, one for each message */
+        if ((*resp = calloc(num_msg, sizeof(struct pam_message))) == NULL) {
+                perror("calloc");
+                return 1;
+        }
+
+        for (int c = 0; c < num_msg; c++) {
+                if (msg[c]->msg_style != PAM_PROMPT_ECHO_OFF &&
+                    msg[c]->msg_style != PAM_PROMPT_ECHO_ON)
+                        continue;
+
+                /* return code is currently not used but should be set to zero */
+                resp[c]->resp_retcode = 0;
+                if ((resp[c]->resp = strdup(passwd)) == NULL) {
+                        perror("strdup");
+                        return 1;
+                }
+        }
+
+        return 0;
 }
-#endif
-
-int
-main(int argc, char **argv) {
-    char curs[] = {0, 0, 0, 0, 0, 0, 0, 0};
-    char buf[32], passwd[256];
-    int num, screen;
-
-#ifndef HAVE_BSD_AUTH
-    const char *pws;
-#endif
-    unsigned int len;
-    Bool running = True;
-    Cursor invisible;
-    Display *dpy;
-    KeySym ksym;
-    Pixmap pmap;
-    Window root, w;
-    XColor black, dummy;
-    XEvent ev;
-    XSetWindowAttributes wa;
-
-    if((argc == 2) && !strcmp("-v", argv[1]))
-        die("i3lock-"VERSION", © 2009 Michael Stapelberg\n"
-            "based on slock, which is © 2006-2008 Anselm R Garbe\n");
-    else if(argc != 1)
-        die("usage: slock [-v]\n");
-
-#ifndef HAVE_BSD_AUTH
-    pws = get_password();
-#endif
-
-    if(!(dpy = XOpenDisplay(0)))
-        die("slock: cannot open display\n");
-    screen = DefaultScreen(dpy);
-    root = RootWindow(dpy, screen);
-
-    if (fork() != 0)
-        return 0;
-
-    /* init */
-    wa.override_redirect = 1;
-    wa.background_pixel = WhitePixel(dpy, screen);
-    w = XCreateWindow(dpy, root, 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);
-    for(len = 1000; len; len--) {
-        if(XGrabPointer(dpy, root, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
-            GrabModeAsync, GrabModeAsync, None, invisible, CurrentTime) == GrabSuccess)
-            break;
-        usleep(1000);
-    }
-    if((running = running && (len > 0))) {
-        for(len = 1000; len; len--) {
-            if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)
-                == GrabSuccess)
-                break;
-            usleep(1000);
-        }
-        running = (len > 0);
-    }
-    len = 0;
-    XSync(dpy, False);
-
-    /* main event loop */
-    while(running && !XNextEvent(dpy, &ev)) {
-        if(ev.type == KeyPress) {
-            buf[0] = 0;
-            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;
-#ifdef HAVE_BSD_AUTH
-                running = !auth_userokay(getlogin(), NULL, "auth-xlock", passwd);
-#else
-                running = strcmp(crypt(passwd, pws), pws);
-#endif
-                len = 0;
-                break;
-            case XK_Escape:
-                len = 0;
-                break;
-            case XK_BackSpace:
-                if(len)
-                    --len;
-                break;
-            default:
-                if(num && !iscntrl((int) buf[0]) && (len + num < sizeof passwd)) { 
-                    memcpy(passwd + len, buf, num);
-                    len += num;
-                }
-                break;
-            }
-        }
-    }
-    XUngrabPointer(dpy, CurrentTime);
-    XFreePixmap(dpy, pmap);
-    XDestroyWindow(dpy, w);
-    XCloseDisplay(dpy);
-    return 0;
+
+int main(int argc, char *argv[]) {
+        char curs[] = {0, 0, 0, 0, 0, 0, 0, 0};
+        char buf[32];
+        int num, screen;
+
+        unsigned int len;
+        bool running = true;
+        Cursor invisible;
+        Display *dpy;
+        KeySym ksym;
+        Pixmap pmap;
+        Window root, w;
+        XColor black, dummy;
+        XEvent ev;
+        XSetWindowAttributes wa;
+
+        /* TODO: use getopt */
+        if((argc == 2) && !strcmp("-v", argv[1]))
+                die("i3lock-"VERSION", © 2009 Michael Stapelberg\n"
+                    "based on slock, which is © 2006-2008 Anselm R Garbe\n");
+        else if(argc != 1)
+                die("usage: i3lock [-v]\n");
+
+        pam_handle_t *handle;
+
+        struct pam_conv conv;
+        conv.conv = conv_callback;
+
+        int ret = pam_start("i3lock", getenv("USER"), &conv, &handle);
+        printf("pam_start = %d\n", ret);
+        if (ret != PAM_SUCCESS)
+                die("error = %s\n", pam_strerror(handle, ret));
+
+        if(!(dpy = XOpenDisplay(0)))
+                die("slock: cannot open display\n");
+        screen = DefaultScreen(dpy);
+        root = RootWindow(dpy, screen);
+
+        if (fork() != 0)
+                return 0;
+
+        /* init */
+        wa.override_redirect = 1;
+        wa.background_pixel = WhitePixel(dpy, screen);
+        w = XCreateWindow(dpy, root, 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);
+        for(len = 1000; len; len--) {
+                if(XGrabPointer(dpy, root, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+                        GrabModeAsync, GrabModeAsync, None, invisible, CurrentTime) == GrabSuccess)
+                        break;
+                usleep(1000);
+        }
+        if((running = running && (len > 0))) {
+                for(len = 1000; len; len--) {
+                        if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)
+                                == GrabSuccess)
+                                break;
+                        usleep(1000);
+                }
+                running = (len > 0);
+        }
+        len = 0;
+        XSync(dpy, False);
+
+        /* main event loop */
+        while(running && !XNextEvent(dpy, &ev)) {
+                if(ev.type == KeyPress) {
+                        buf[0] = 0;
+                        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;
+                                if ((ret = pam_authenticate(handle, 0)) == PAM_SUCCESS)
+                                        running = false;
+                                else fprintf(stderr, "PAM: %s\n", pam_strerror(handle, ret));
+                                len = 0;
+                                break;
+                        case XK_Escape:
+                                len = 0;
+                                break;
+                        case XK_BackSpace:
+                                if (len > 0)
+                                        len--;
+                                break;
+                        default:
+                                if(num && !iscntrl((int) buf[0]) && (len + num < sizeof passwd)) {
+                                        memcpy(passwd + len, buf, num);
+                                        len += num;
+                                }
+                                break;
+                        }
+                }
+        }
+        XUngrabPointer(dpy, CurrentTime);
+        XFreePixmap(dpy, pmap);
+        XDestroyWindow(dpy, w);
+        XCloseDisplay(dpy);
+        return 0;
 }