diff -r 4d3769ac5d02 config.mk --- a/config.mk Thu Nov 26 12:53:26 2009 +0000 +++ b/config.mk Tue Nov 16 11:32:30 2010 +0100 @@ -20,6 +20,7 @@ # On *BSD remove -DHAVE_SHADOW_H from CPPFLAGS and add -DHAVE_BSD_AUTH # On OpenBSD and Darwin remove -lcrypt from LIBS +# To use Linux-PAM, use -DHAVE_PAM instead of SHADOW_H or BSD_AUTH in CPPFLAGS and add -lpam to LIBS # compiler and linker CC = cc diff -r 4d3769ac5d02 slock.c --- a/slock.c Thu Nov 26 12:53:26 2009 +0000 +++ b/slock.c Tue Nov 16 11:32:30 2010 +0100 @@ -1,6 +1,7 @@ /* See LICENSE file for license details. */ #define _XOPEN_SOURCE 500 -#if HAVE_SHADOW_H +#define PASSLEN 256 +#if defined(HAVE_SHADOW_H) #include #endif @@ -17,11 +18,16 @@ #include #include -#if HAVE_BSD_AUTH +#if defined(HAVE_BSD_AUTH) #include #include #endif +#if defined(HAVE_PAM) +#define PAM_REALM "login" +#include +#endif + struct st_lock { int screen; Window root, w; @@ -44,7 +50,7 @@ exit(EXIT_FAILURE); } -#ifndef HAVE_BSD_AUTH +#if !defined(HAVE_BSD_AUTH) && !defined(HAVE_PAM) static const char * get_password(void) { /* only run as root */ const char *rval; @@ -56,7 +62,7 @@ endpwent(); rval = pw->pw_passwd; -#if HAVE_SHADOW_H +#if defined(HAVE_SHADOW_H) { struct spwd *sp; sp = getspnam(getenv("USER")); @@ -73,29 +79,24 @@ #endif static void -#ifdef HAVE_BSD_AUTH -read_password(Display *dpy) -#else -read_password(Display *dpy, const char *pws) -#endif +read_password(Display *dpy, char *passwd) { - char buf[32], passwd[256]; + char buf[32]; int num; unsigned int len; - Bool running = True; KeySym ksym; XEvent ev; len = 0; - running = True; /* As "slock" stands for "Simple X display locker", the DPMS settings * had been removed and you can set it with "xset" or some other * utility. This way the user can easily set a customized DPMS * timeout. */ - while(running && !XNextEvent(dpy, &ev)) { + for(;;) { + XNextEvent(dpy, &ev); if(ev.type == KeyPress) { buf[0] = 0; num = XLookupString(&ev.xkey, buf, sizeof buf, &ksym, 0); @@ -112,14 +113,7 @@ 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 - if (running != 0) - XBell(dpy, 100); - len = 0; + return; break; case XK_Escape: len = 0; @@ -127,11 +121,13 @@ case XK_BackSpace: if(len) --len; - break; + passwd[len] = 0; + break; default: - if(num && !iscntrl((int) buf[0]) && (len + num < sizeof passwd)) { + if(num && !iscntrl((int) buf[0]) && (len + num < PASSLEN)) { memcpy(passwd + len, buf, num); len += num; + passwd[len] = 0; } break; } @@ -139,6 +135,40 @@ } } +#if defined(HAVE_PAM) +static int +pamconv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { + int i; + *resp = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response)); + for (i = 0; i < num_msg; ++i) { + if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) { + if ((resp[i]->resp = malloc(PASSLEN)) == NULL ) + die("Not enough memory"); + read_password((Display *) appdata_ptr, resp[i]->resp); + } + resp[i]->resp_retcode = 0; + } + return PAM_SUCCESS; +} +#endif + +#if !defined(HAVE_PAM) +static Bool +#if defined(HAVE_BSD_AUTH) +authenticate(const char *user, const char *passwd) { +#else +authenticate(const char *user, const char *passwd, const char *pws) { +#endif + Bool ret; +#if defined(HAVE_BSD_AUTH) + ret = auth_userokay(user, NULL, "auth-xlock", passwd) ? True : False; +#else + ret = !strcmp(crypt(passwd, pws), pws) ? True : False; +#endif + return ret; +} +#endif + static void unlockscreen(Display *dpy, struct st_lock *lock) { if (dpy == NULL || lock == NULL) @@ -215,9 +245,15 @@ int main(int argc, char **argv) { -#ifndef HAVE_BSD_AUTH +#if !defined(HAVE_BSD_AUTH) && !defined(HAVE_PAM) const char *pws; #endif +#if defined(HAVE_PAM) + pam_handle_t *pamh = NULL; + int pamret; + struct pam_conv conv; +#endif + char *passwd = NULL; Display *dpy; int nscreens, screen; @@ -228,7 +264,7 @@ else if(argc != 1) usage(); -#ifndef HAVE_BSD_AUTH +#if !defined(HAVE_BSD_AUTH) && !defined(HAVE_PAM) pws = get_password(); #endif @@ -247,10 +283,28 @@ XSync(dpy, False); /* Everything is now blank. Now wait for the correct password. */ -#ifdef HAVE_BSD_AUTH - read_password(dpy); + if ((passwd = malloc(PASSLEN)) == NULL) + die("Not enough memory"); + passwd[0] = 0; +#if defined(HAVE_PAM) + conv.conv = pamconv; + conv.appdata_ptr = dpy; + pamret = pam_start(PAM_REALM, getenv("USER"), &conv, &pamh); + if (pamret != PAM_SUCCESS) + die("PAM not available"); +#endif + do { + XBell(dpy, 100); +#if defined(HAVE_BSD_AUTH) + read_password(dpy, passwd); + } while (!authenticate(getlogin(), passwd)); +#elif defined(HAVE_PAM) + } while ((pamret = pam_authenticate(pamh, 0)) != PAM_SUCCESS); + if (pam_end(pamh, pamret) != PAM_SUCCESS) + pamh = NULL; #else - read_password(dpy, pws); + read_password(dpy, passwd); + } while (!authenticate(getenv("USER"), passwd, pws)); #endif /* Password ok, unlock everything and quit. */ @@ -258,6 +312,7 @@ unlockscreen(dpy, locks[screen]); free(locks); + free(passwd); XCloseDisplay(dpy);