Hey, this patch should enable Linux-PAM support in slock. It's my first try with Linux-PAM whatsoever so there's a chance it won't work everywhere :) Maybe it could be useful to some...
-- Petr 'contyk' Sabata, Red Hat, Brno () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments
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 <shadow.h>
#endif
@@ -17,11 +18,16 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
-#if HAVE_BSD_AUTH
+#if defined(HAVE_BSD_AUTH)
#include <login_cap.h>
#include <bsd_auth.h>
#endif
+#if defined(HAVE_PAM)
+#define PAM_REALM "login"
+#include <security/pam_appl.h>
+#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);
pgpnokbWhIYH0.pgp
Description: PGP signature
