Bug#433715: libsasl2-modules-ldap: feature request for LDAP auxprop+canonuser implementation

Dan White dwhite at olp.net
Thu Jul 19 04:04:19 UTC 2007


Package: libsasl2-modules-ldap
Version: 2.1.22.dfsg1-13
Severity: wishlist

This is a combination of a couple of patches from the cyrus-sasl mailing
list:

http://osdir.com/ml/security.cyrus.sasl/2007-01/msg00053.html
http://archives.free.net.ph/message/20070522.142310.c4df1ddd.en.html

Both authored by Howard Chu.

This patch adds canon_user plugin functionality to the existing ldap
auxprop plugin.


*** /usr/src/ldapdb-canon.diff
--- ldapdb.c.orig	2007-04-11 17:29:07.000000000 -0500
+++ ldapdb.c	2007-04-11 17:28:50.000000000 -0500
@@ -1,6 +1,6 @@
 /* $OpenLDAP: pkg/ldap/contrib/ldapsasl/ldapdb.c,v 1.1.2.7 2003/11/29 22:10:03 hyc Exp $ */
-/* SASL LDAP auxprop implementation
- * Copyright (C) 2002,2003 Howard Chu, All rights reserved. <hyc at symas.com>
+/* SASL LDAP auxprop+canonuser implementation
+ * Copyright (C) 2002-2007 Howard Chu, All rights reserved. <hyc at symas.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted only as authorized by the OpenLDAP
@@ -14,6 +14,7 @@
 #include <config.h>
 
 #include <stdio.h>
+#include <ctype.h>
 
 #include "sasl.h"
 #include "saslutil.h"
@@ -26,13 +27,17 @@
 static char ldapdb[] = "ldapdb";
 
 typedef struct ldapctx {
+	int inited;		/* Have we already read the config? */
 	const char *uri;	/* URI of LDAP server */
 	struct berval id;	/* SASL authcid to bind as */
 	struct berval pw;	/* password for bind */
 	struct berval mech;	/* SASL mech */
 	int use_tls;		/* Issue StartTLS request? */
+	struct berval canon;	/* Use attr in user entry for canonical name */
 } ldapctx;
 
+static ldapctx ldapdb_ctx;
+
 static int ldapdb_interact(LDAP *ld, unsigned flags __attribute__((unused)),
 	void *def, void *inter)
 {
@@ -79,7 +84,7 @@
     char *authzid;
 
     if((i=ldap_initialize(&cp->ld, ctx->uri))) {
-    	return i;
+	return i;
     }
 
     authzid = sparams->utils->malloc(ulen + sizeof("u:"));
@@ -203,7 +208,7 @@
 
  done:
     if(attrs) sparams->utils->free(attrs);
-    if(cp.ld) ldap_unbind(cp.ld);
+    if(cp.ld) ldap_unbind_ext(cp.ld, NULL, NULL);
 }
 
 static int ldapdb_auxprop_store(void *glob_context,
@@ -254,58 +259,166 @@
 	if (i == LDAP_NO_MEMORY) i = SASL_NOMEM;
 	else i = SASL_FAIL;
     }
-    if (cp.ld) ldap_unbind(cp.ld);
+    if(cp.ld) ldap_unbind_ext(cp.ld, NULL, NULL);
     return i;
 }
 
-static void ldapdb_auxprop_free(void *glob_ctx, const sasl_utils_t *utils)
+static int
+ldapdb_canon_server(void *glob_context,
+		    sasl_server_params_t *sparams,
+		    const char *user,
+		    unsigned ulen,
+		    unsigned flags,
+		    char *out,
+		    unsigned out_max,
+		    unsigned *out_ulen)
 {
-	utils->free(glob_ctx);
+    ldapctx *ctx = glob_context;
+    connparm cp;
+    struct berval **bvals;
+    LDAPMessage *msg, *res;
+    char *rdn, *attrs[2];
+    unsigned len;
+    int ret;
+    
+    if(!ctx || !sparams || !user) return SASL_BADPARAM;
+
+    /* If no canon attribute was configured, we can't do anything */
+    if(!ctx->canon.bv_val) return SASL_BADPARAM;
+
+    /* Trim whitespace */
+    while(isspace(*(unsigned char *)user)) {
+	user++;
+	ulen--;
+    }
+    while(isspace((unsigned char)user[ulen-1])) {
+    	ulen--;
+    }
+    
+    if (!ulen) {
+    	sparams->utils->seterror(sparams->utils->conn, 0,
+	    "All-whitespace username.");
+	return SASL_FAIL;
+    }
+
+    ret = ldapdb_connect(ctx, sparams, user, ulen, &cp);
+    if ( ret ) goto done;
+
+    /* See if the RDN uses the canon attr. If so, just use the RDN
+     * value, we don't need to do a search.
+     */
+    rdn = cp.dn->bv_val+3;
+    if (!strncasecmp(ctx->canon.bv_val, rdn, ctx->canon.bv_len) &&
+    	rdn[ctx->canon.bv_len] == '=') {
+	char *comma;
+	rdn += ctx->canon.bv_len + 1;
+	comma = strchr(rdn, ',');
+	if ( comma )
+	    len = comma - rdn;
+	else 
+	    len = cp.dn->bv_len - (rdn - cp.dn->bv_val);
+	if ( len > out_max )
+	    len = out_max;
+	memcpy(out, rdn, len);
+	out[len] = '\0';
+	*out_ulen = len;
+	ret = SASL_OK;
+	ber_bvfree(cp.dn);
+	goto done;
+    }
+
+    /* Have to read the user's entry */
+    attrs[0] = ctx->canon.bv_val;
+    attrs[1] = NULL;
+    ret = ldap_search_ext_s(cp.ld, cp.dn->bv_val+3, LDAP_SCOPE_BASE,
+    	"(objectclass=*)", attrs, 0, cp.ctrl, NULL, NULL, 1, &res);
+    ber_bvfree(cp.dn);
+
+    if (ret != LDAP_SUCCESS) goto done;
+
+    for(msg=ldap_first_message(cp.ld, res); msg; msg=ldap_next_message(cp.ld, msg))
+    {
+    	if (ldap_msgtype(msg) != LDAP_RES_SEARCH_ENTRY) continue;
+	bvals = ldap_get_values_len(cp.ld, msg, attrs[0]);
+	if (!bvals) continue;
+	len = bvals[0]->bv_len;
+	if ( len > out_max )
+	    len = out_max;
+	memcpy(out, bvals[0]->bv_val, len);
+	*out_ulen = len;
+	ber_bvecfree(bvals);
+    }
+    ldap_msgfree(res);
+
+ done:
+    if(cp.ld) ldap_unbind_ext(cp.ld, NULL, NULL);
+    if (ret) {
+    	sparams->utils->seterror(sparams->utils->conn, 0,
+	    ldap_err2string(ret));
+	if (ret == LDAP_NO_MEMORY) ret = SASL_NOMEM;
+	else ret = SASL_FAIL;
+    }
+    return ret;
 }
 
-static sasl_auxprop_plug_t ldapdb_auxprop_plugin = {
-    0,				/* Features */
-    0,				/* spare */
-    NULL,			/* glob_context */
-    ldapdb_auxprop_free,	/* auxprop_free */
-    ldapdb_auxprop_lookup,	/* auxprop_lookup */
-    ldapdb,			/* name */
-    ldapdb_auxprop_store	/* auxprop store */
-};
+static int
+ldapdb_canon_client(void *glob_context,
+		    sasl_client_params_t *cparams,
+		    const char *user,
+		    unsigned ulen,
+		    unsigned flags,
+		    char *out,
+		    unsigned out_max,
+		    unsigned *out_ulen)
+{
+    if(!cparams || !user) return SASL_BADPARAM;
 
-int ldapdb_auxprop_plug_init(const sasl_utils_t *utils,
-                             int max_version,
-                             int *out_version,
-                             sasl_auxprop_plug_t **plug,
-                             const char *plugname __attribute__((unused))) 
+    /* Trim whitespace */
+    while(isspace(*(unsigned char *)user)) {
+	user++;
+	ulen--;
+    }
+    while(isspace((unsigned char)user[ulen-1])) {
+    	ulen--;
+    }
+    
+    if (!ulen) {
+    	cparams->utils->seterror(cparams->utils->conn, 0,
+	    "All-whitespace username.");
+	return SASL_FAIL;
+    }
+    memcpy(out, user, ulen);
+    out[ulen] = '\0';
+    *out_ulen = ulen;
+    return SASL_OK;
+}
+
+static int
+ldapdb_config(const sasl_utils_t *utils)
 {
-    ldapctx tmp, *p;
+    ldapctx *p = &ldapdb_ctx;
     const char *s;
     unsigned len;
 
-    if(!out_version || !plug) return SASL_BADPARAM;
-
-    if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS;
-    
-    memset(&tmp, 0, sizeof(tmp));
+    if(p->inited) return SASL_OK;
 
-    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_uri", &tmp.uri, NULL);
-    if(!tmp.uri) return SASL_BADPARAM;
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_uri", &p->uri, NULL);
+    if(!p->uri) return SASL_BADPARAM;
 
     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_id",
-    	(const char **)&tmp.id.bv_val, &len);
-    tmp.id.bv_len = len;
+    	(const char **)&p->id.bv_val, &len);
+    p->id.bv_len = len;
     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_pw",
-    	(const char **)&tmp.pw.bv_val, &len);
-    tmp.pw.bv_len = len;
+    	(const char **)&p->pw.bv_val, &len);
+    p->pw.bv_len = len;
     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_mech",
-    	(const char **)&tmp.mech.bv_val, &len);
-    tmp.mech.bv_len = len;
+    	(const char **)&p->mech.bv_val, &len);
+    p->mech.bv_len = len;
     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_starttls", &s, NULL);
     if (s)
     {
-    	if (!strcasecmp(s, "demand")) tmp.use_tls = 2;
-	else if (!strcasecmp(s, "try")) tmp.use_tls = 1;
+    	if (!strcasecmp(s, "demand")) p->use_tls = 2;
+	else if (!strcasecmp(s, "try")) p->use_tls = 1;
     }
     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_rc", &s, &len);
     if (s)
@@ -320,15 +433,75 @@
 	    return SASL_NOMEM;
 	}
     }
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_canon_attr",
+	(const char **)&p->canon.bv_val, &len);
+    p->canon.bv_len = len;
+    p->inited = 1;
+
+    return SASL_OK;
+}
+
+static sasl_auxprop_plug_t ldapdb_auxprop_plugin = {
+    0,				/* Features */
+    0,				/* spare */
+    &ldapdb_ctx,		/* glob_context */
+    NULL,	/* auxprop_free */
+    ldapdb_auxprop_lookup,	/* auxprop_lookup */
+    ldapdb,			/* name */
+    ldapdb_auxprop_store	/* auxprop store */
+};
+
+int ldapdb_auxprop_plug_init(const sasl_utils_t *utils,
+                             int max_version,
+                             int *out_version,
+                             sasl_auxprop_plug_t **plug,
+                             const char *plugname __attribute__((unused))) 
+{
+    int rc;
+
+    if(!out_version || !plug) return SASL_BADPARAM;
 
-    p = utils->malloc(sizeof(ldapctx));
-    if (!p) return SASL_NOMEM;
-    *p = tmp;
-    ldapdb_auxprop_plugin.glob_context = p;
+    if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS;
+    
+    rc = ldapdb_config(utils);
 
     *out_version = SASL_AUXPROP_PLUG_VERSION;
 
     *plug = &ldapdb_auxprop_plugin;
 
-    return SASL_OK;
+    return rc;
+}
+
+static sasl_canonuser_plug_t ldapdb_canonuser_plugin = {
+	0,	/* features */
+	0,	/* spare */
+	&ldapdb_ctx,	/* glob_context */
+	ldapdb,	/* name */
+	NULL,	/* canon_user_free */
+	ldapdb_canon_server,	/* canon_user_server */
+	ldapdb_canon_client,	/* canon_user_client */
+	NULL,
+	NULL,
+	NULL
+};
+
+int ldapdb_canonuser_plug_init(const sasl_utils_t *utils,
+                             int max_version,
+                             int *out_version,
+                             sasl_canonuser_plug_t **plug,
+                             const char *plugname __attribute__((unused))) 
+{
+    int rc;
+
+    if(!out_version || !plug) return SASL_BADPARAM;
+
+    if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
+    
+    rc = ldapdb_config(utils);
+
+    *out_version = SASL_CANONUSER_PLUG_VERSION;
+
+    *plug = &ldapdb_canonuser_plugin;
+
+    return rc;
 }


-- System Information:
Debian Release: lenny/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.21-1-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash

Versions of packages libsasl2-modules-ldap depends on:
ii  libc6                    2.6-2           GNU C Library: Shared libraries
ii  libldap2                 2.1.30-13.4     OpenLDAP libraries
ii  libsasl2-modules         2.1.22.dfsg1-13 Pluggable Authentication Modules f

libsasl2-modules-ldap recommends no packages.

-- no debconf information




More information about the Pkg-cyrus-sasl2-debian-devel mailing list