[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: ldap users auth to ldap ;)



On Tue, Sep 15, 1998 at 05:21:52PM -0700, Michael Thomas Cope wrote:
> On Tue, 15 Sep 1998, Jared Mauch wrote:
> 
> > 
> > 	Anyone doing this?
> > 
> > 	What i am ideally trying to do is the following:
> > 
> > 	for a cn=Luser
> > 
> > 	they have cryptpw=XXXX
> > 
> > 	and to bind they need to auth to that pw.
> > 
> > 	(Yeah, i'm trying to avoid digging too far into source)
> > 
> > 	- jared
> For just crypted passwords you should be fine with the appropritate
> defines in the Makefile.
> What I am more interested in is an authetication backend for LDAP, perhaps
> PAM that would allow pluggable authentication schemes.  I hacked up our
> source to RADIUS as a backend but it's not a good solution long-term.

Attached is a patch I contributed to the Kiruna-LDAP effort, just before
it wrapped up.  It adds two new config items to the back-end sections of
slapd.conf.  These are:

   pam-auth  <on|off>

      Specify whether you want to use PAM to handle authentication for
      bind requests to this backend.

   pam-auth-attr <attr-name>

      Specifies the attribute which should contain the username to pass
      to PAM during authentication.  If pam-auth-attr is not specified,
      the default is the uid attr.

I use this in our company directory.  Each user's entry has a uid attr which 
contains their username  (which is the same across all machines, Linux
and NT).  

The application name passed to PAM is 'slapd', so you can use /etc/pam.d/slapd
to configure the PAM module stack for your directory.

This will probably not apply to the OpenLDAP code, but I'm sure it can
be adapted.  Unfortunately, I don't have time to do it right now.  (I was 
planning to contribute it in a few weeks time, but seeing as someone else
needs it, it's all yours!)

Kenn


> -Mike 
> -- 
> Michael Cope: Harvey Mudd College '00; Armand Hammer UWC '96
> E-mail: Michael_Cope@hmc.edu
> 
> 
diff -urN ldap-980711/servers/slapd/Makefile.am ldap-980711-pam/servers/slapd/Makefile.am
--- ldap-980711/servers/slapd/Makefile.am	Thu May 21 16:25:20 1998
+++ ldap-980711-pam/servers/slapd/Makefile.am	Sun Jul 26 17:43:32 1998
@@ -20,7 +20,7 @@
 	$(top_srcdir)/libraries/libavl/libavl.a \
 	$(top_srcdir)/libraries/libldif/libldif.a \
 	$(top_srcdir)/libraries/liblthread/liblthread.a \
-	-lgdbm
+	-lgdbm -lpam -ldl
 
 slapd_SOURCES=\
 	main.c daemon.c connection.c search.c add.c \
diff -urN ldap-980711/servers/slapd/back-ldbm/back-ldbm.h ldap-980711-pam/servers/slapd/back-ldbm/back-ldbm.h
--- ldap-980711/servers/slapd/back-ldbm/back-ldbm.h	Fri May 22 12:21:22 1998
+++ ldap-980711-pam/servers/slapd/back-ldbm/back-ldbm.h	Sat Jul 25 21:12:02 1998
@@ -109,6 +109,8 @@
 #ifdef USE_THREADS
 	pthread_cond_t		li_dbcache_cv;
 #endif
+	int			li_use_pam_auth;
+	char			*li_pam_auth_attr;
 };
 
 #ifdef NEEDPROTOS
diff -urN ldap-980711/servers/slapd/back-ldbm/bind.c ldap-980711-pam/servers/slapd/back-ldbm/bind.c
--- ldap-980711/servers/slapd/back-ldbm/bind.c	Thu May 21 13:32:15 1998
+++ ldap-980711-pam/servers/slapd/back-ldbm/bind.c	Sun Jul 26 17:44:16 1998
@@ -1,15 +1,18 @@
 /* bind.c - ldbm backend bind and unbind routines */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include "slap.h"
 #include "back-ldbm.h"
+#include <security/pam_appl.h>
 #ifdef KERBEROS
 #include "krb.h"
 #endif
 
+
 extern Entry		*dn2entry();
 extern Attribute	*attr_find();
 
@@ -17,6 +20,9 @@
 extern int	krbv4_ldap_auth();
 #endif
 
+static int do_pam_auth( Backend *be, Connection *conn, Operation *op,
+   char *dn, Entry *e, struct berval *cred, struct ldbminfo *li);
+
 int
 ldbm_back_bind(
     Backend		*be,
@@ -70,26 +76,34 @@
 			return( 0 );
 		}
 
-		if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) {
-			if ( be_isroot_pw( be, dn, cred ) ) {
-				/* front end will send result */
-				return( 0 );
+		if ( li->li_use_pam_auth ) {
+			if ( do_pam_auth( be, conn, op, dn, e, cred, li ) ) {
+				/* PAM auth failed.  do_pam_auth() has
+				   already called send_ldap_result() */
+				return( 1 );
+			}
+		} else {
+			if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) {
+				if ( be_isroot_pw( be, dn, cred ) ) {
+					/* front end will send result */
+					return( 0 );
+				}
+				send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
+				    NULL, NULL );
+				cache_return_entry( &li->li_cache, e );
+				return( 1 );
 			}
-			send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
-			    NULL, NULL );
-			cache_return_entry( &li->li_cache, e );
-			return( 1 );
-		}
 
-		if ( value_find( a->a_vals, cred, a->a_syntax, 0 ) != 0 ) {
-			if ( be_isroot_pw( be, dn, cred ) ) {
-				/* front end will send result */
-				return( 0 );
+			if ( value_find( a->a_vals, cred, a->a_syntax, 0 ) != 0 ) {
+				if ( be_isroot_pw( be, dn, cred ) ) {
+					/* front end will send result */
+					return( 0 );
+				}
+				send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
+				    NULL, NULL );
+				cache_return_entry( &li->li_cache, e );
+				return( 1 );
 			}
-			send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
-			    NULL, NULL );
-			cache_return_entry( &li->li_cache, e );
-			return( 1 );
 		}
 		break;
 
@@ -148,3 +162,146 @@
 	/* success:  front end will send result */
 	return( 0 );
 }
+
+
+/* Use PAM to authenticate.  First, a user ID is obtained from the
+   attribute specified by the pam-auth-attr config option (default
+   is the 'uid' attribute).  Then the PAM library is called to 
+   perform the authentication itself.  The application name passed
+   to PAM is 'slapd'.
+
+   This code is based on Michael K Johnson's PAM auth code in
+   RedHat's IMAP server.  */
+
+/* The pam_auth_info structure is used to pass info to the
+   PAM conversation function */
+
+struct pam_auth_info {
+   char *username;
+   char *password;
+   int pam_error;
+};
+
+/* Forward declaration of the PAM conversation function */
+static int pam_conv_func (int num_msg, const struct pam_message **msg,
+   struct pam_response **resp, void *appdata_ptr);
+
+static int do_pam_auth( Backend *be, Connection *conn, Operation *op,
+   char *dn, Entry *e, struct berval *cred, struct ldbminfo *li)
+{
+	char *uid_attr = "uid";
+	Attribute *a;
+	char *uid;
+	pam_handle_t *pamh = NULL;
+	int pam_error;
+	struct pam_auth_info auth_info;
+	struct pam_conv pam_conv_info;
+
+	if (li->li_pam_auth_attr != NULL) {
+		uid_attr = li->li_pam_auth_attr;
+	}
+
+        if ( (a = attr_find( e->e_attrs, uid_attr )) == NULL ) {
+                if ( be_isroot_pw( be, dn, cred ) ) {
+                        /* front end will send result */
+                        return( 0 );
+                }
+                send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
+                    NULL, NULL );
+                cache_return_entry( &li->li_cache, e );
+                return( 1 );
+        }
+
+	if ( (a->a_vals[0] == NULL) || 
+	    ( (uid = a->a_vals[0]->bv_val) == NULL) ) {
+                send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
+                    NULL, NULL );
+                cache_return_entry( &li->li_cache, e );
+                return( 1 );
+	}
+
+	auth_info.username = uid;
+	auth_info.password = cred->bv_val;
+	auth_info.pam_error = 0;
+
+	pam_conv_info.conv = pam_conv_func;
+	pam_conv_info.appdata_ptr = &auth_info;
+
+#define PAM_BAIL \
+	if (auth_info.pam_error || (pam_error != PAM_SUCCESS)) { \
+		pam_end(pamh, 0); \
+                send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH, \
+                    NULL, NULL ); \
+                cache_return_entry( &li->li_cache, e ); \
+                return( 1 ); \
+	}
+
+	pam_error = pam_start("slapd", uid, &pam_conv_info, &pamh);
+	PAM_BAIL;
+
+	pam_error = pam_authenticate(pamh, 0);
+	PAM_BAIL;
+
+	pam_error = pam_acct_mgmt(pamh, 0);
+	PAM_BAIL;
+
+	/* I'm not sure if this call is really needed */
+	pam_error = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+	PAM_BAIL;
+
+	pam_end(pamh, PAM_SUCCESS);
+
+	/* If we've got to here, then the uid and password were
+	   successfully authenticated */
+
+	return( 0 );
+}
+
+/* PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+static int pam_conv_func (int num_msg, const struct pam_message **msg,
+   struct pam_response **resp, void *appdata_ptr)
+{
+	int replies = 0;
+	struct pam_response *reply = NULL;
+	struct pam_auth_info *auth_info;
+
+	auth_info = (struct pam_auth_info *) appdata_ptr;
+
+#define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+	reply = malloc(sizeof(struct pam_response) * num_msg);
+	if (reply == NULL) return PAM_CONV_ERR;
+
+	for (replies = 0; replies < num_msg; replies++) {
+		switch (msg[replies]->msg_style) {
+			case PAM_PROMPT_ECHO_ON:
+				reply[replies].resp_retcode = PAM_SUCCESS;
+				reply[replies].resp = COPY_STRING(auth_info->username);
+				/* PAM frees resp */
+				break;
+			case PAM_PROMPT_ECHO_OFF:
+				reply[replies].resp_retcode = PAM_SUCCESS;
+				reply[replies].resp = COPY_STRING(auth_info->password);
+				/* PAM frees resp */
+				break;
+			case PAM_TEXT_INFO:
+				/* fall through */
+			case PAM_ERROR_MSG:
+				/* ignore it, but pam still wants a NULL response... */
+				reply[replies].resp_retcode = PAM_SUCCESS;
+				reply[replies].resp = NULL;
+				break;
+			default:
+				/* Must be an error of some sort... */
+				free (reply);
+				auth_info->pam_error = 1;
+				return PAM_CONV_ERR;
+			}
+		}
+	*resp = reply;
+	return PAM_SUCCESS;
+}
+
diff -urN ldap-980711/servers/slapd/back-ldbm/config.c ldap-980711-pam/servers/slapd/back-ldbm/config.c
--- ldap-980711/servers/slapd/back-ldbm/config.c	Thu May 21 13:32:15 1998
+++ ldap-980711-pam/servers/slapd/back-ldbm/config.c	Sun Jul 26 17:43:51 1998
@@ -77,6 +77,30 @@
 		}
 		li->li_dbcachesize = atoi( argv[1] );
 
+	/* should we use PAM for authentication? */
+        } else if ( strcasecmp( argv[0], "pam-auth" ) == 0 ) {
+                if ( argc < 2 ) {
+                        fprintf( stderr,
+    "%s: line %d: missing on|off in \"pam-auth <on|off>\" line\n",
+                            fname, lineno, 0 );
+                        exit( 1 );
+                }
+                if ( strcasecmp( argv[1], "on" ) == 0 ) {
+                        li->li_use_pam_auth = 1;
+                } else {
+                        li->li_use_pam_auth = 0;
+                }
+
+	/* which attribute should we use as the user ID for PAM */
+	} else if ( strcasecmp( argv[0], "pam-auth-attr" ) == 0 ) {
+		if ( argc < 2 ) {
+			fprintf( stderr,
+		"%s: line %d: missing dir in \"pam-auth-attr <dir>\" line\n",
+			    fname, lineno );
+			exit( 1 );
+		}
+		li->li_pam_auth_attr = strdup( argv[1] );
+
 	/* anything else */
 	} else {
 		fprintf( stderr,
diff -urN ldap-980711/servers/slapd/back-ldbm/init.c ldap-980711-pam/servers/slapd/back-ldbm/init.c
--- ldap-980711/servers/slapd/back-ldbm/init.c	Fri May 22 12:21:23 1998
+++ ldap-980711-pam/servers/slapd/back-ldbm/init.c	Sat Jul 25 22:45:22 1998
@@ -33,6 +33,10 @@
 	/* default database directory */
 	li->li_directory = DEFAULT_DB_DIRECTORY;
 
+	/* Default to not using PAM */
+	li->li_use_pam_auth = 0;
+	li->li_pam_auth_attr = 0;
+
 	/* always index dn, id2children, objectclass (used in some searches) */
 	argv[ 0 ] = "dn";
 	argv[ 1 ] = "dn";
diff -urN ldap-980711/servers/tools/Makefile.am ldap-980711-pam/servers/tools/Makefile.am
--- ldap-980711/servers/tools/Makefile.am	Thu May 21 16:25:26 1998
+++ ldap-980711-pam/servers/tools/Makefile.am	Sun Jul 26 19:38:09 1998
@@ -16,7 +16,7 @@
 	$(top_srcdir)/libraries/liblthread/liblthread.a \
 	../slapd/back-passwd/libbackpasswd.a \
 	../slapd/libslap.a \
-	-lgdbm
+	-lgdbm -lpam -ldl
 
 INCLUDES=-I$(top_srcdir)/include -I../slapd
 
diff -urN ldap-980711/servers/tools/Makefile.in ldap-980711-pam/servers/tools/Makefile.in
--- ldap-980711/servers/tools/Makefile.in	Sun Jul 26 20:19:53 1998
+++ ldap-980711-pam/servers/tools/Makefile.in	Sun Jul 26 20:20:53 1998
@@ -73,7 +73,7 @@
 	$(top_srcdir)/libraries/liblthread/liblthread.a \
 	../slapd/back-passwd/libbackpasswd.a \
 	../slapd/libslap.a \
-	-lgdbm
+	-lgdbm -lpam -ldl
 
 INCLUDES=-I$(top_srcdir)/include -I../slapd