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. <[EMAIL PROTECTED]> +/* SASL LDAP auxprop+canonuser implementation + * Copyright (C) 2002-2007 Howard Chu, All rights reserved. <[EMAIL PROTECTED]> * * 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 -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

