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