Sponsoring a canon_user plugin for LDAP lookup
Torsten Schlabach
tschlabach at gmx.net
Mon Feb 19 10:51:12 EST 2007
Hi,
little update on this one:
I had
sasl_ldap_uri: localhost
instead of
sasl_ldap_uri: ldap://localhost
Now it's asking the LDAP server again, but I am back to
Feb 19 16:49:40 box-k-07 cyrus/master[11779]: about to exec
/usr/lib/cyrus/bin/imapd
Feb 19 16:49:40 box-k-07 cyrus/imap[11779]: executed
Feb 19 16:49:40 box-k-07 cyrus/imapd[11779]: accepted connection
Feb 19 16:49:40 box-k-07 slapd[7177]: conn=4 fd=10 ACCEPT from
IP=127.0.0.1:41040 (IP=0.0.0.0:389)
Feb 19 16:49:40 box-k-07 cyrus/master[11636]: process 11779 exited,
signaled to death by 11
Feb 19 16:49:40 box-k-07 cyrus/master[11636]: service imap pid 11779 in
BUSY state: terminated abnormally
Feb 19 16:49:40 box-k-07 slapd[7177]: conn=4 fd=10 closed (connection lost)
My best guess would be that it dies somewhere on the SASL layer as this
is what I have changed. But how to debug this?
Regards,
Torsten
Howard Chu schrieb:
> Torsten Schlabach wrote:
>
>> > And now just to doublecheck - you actually want just the simple name
>> > returned, not the full DN. Correct?
>>
>> Sure. As this is what Cyrus IMAPd expects.
>>
>> Without the canon_user, you'd type
>>
>> AUTH id000012
>>
>> You wouldn't type
>>
>> AUTH uid=id000012,ou=user,ou=...
>>
>> It's getting 1:00 a.m. now where I am. So I hope you got all the info
>> and I can go to bed now. I'd really be thankful for you help with
>> that. Any probably many others as well.
>>
> The attached patch should do what you want. Add "ldapdb_canon_attr: uid"
> to your configuration to use it.
>
>
> ------------------------------------------------------------------------
>
> Index: doc/options.html
> ===================================================================
> RCS file: /cvs/src/sasl/doc/options.html,v
> retrieving revision 1.30
> diff -u -r1.30 options.html
> --- doc/options.html 16 Feb 2005 20:52:05 -0000 1.30
> +++ doc/options.html 13 Jan 2007 01:05:49 -0000
> @@ -83,6 +83,14 @@
> <TD>none</TD>
> </TR>
> <TR>
> +<TD>ldapdb_canon_attr</TD><TD>LDAPDB plugin</TD>
> +<TD>Use the value of the specified attribute as the user's
> +canonical name. The attribute will be looked up in the user's LDAP
> +entry. This setting must be configured in order to use LDAPDB as
> +a canonuser plugin.</TD>
> +<TD>none</TD>
> +</TR>
> +<TR>
> <TD>log_level</TD><TD>SASL Library</TD>
> <TD><b>Numeric</b> Logging Level (see <TT>SASL_LOG_*</TT> in <tt>sasl.h</tt>
> for values and descriptions</TD>
> @@ -273,7 +281,7 @@
> </pre>
> is a valid value for <tt>sql_select</tt>.
>
> -<h2>Notes on LDAPDB auxprop options</h2>
> +<h2>Notes on LDAPDB plugin options</h2>
>
> <p>
> </p>
> @@ -286,7 +294,8 @@
> makes the configuration of remote services much simpler.</p>
>
> <p>This plugin is not for use with slapd itself. When OpenLDAP is
> -built with SASL support, slapd uses its own internal auxprop module.
> +built with SASL support, slapd uses its own internal auxprop and
> +canonuser module.
> By default, without configuring anything else, slapd will fail to load
> the ldapdb module when it's present. This is as it should be. If you
> don't like the "auxpropfunc: error -7" message that is sent to syslog
> @@ -303,6 +312,7 @@
> ldapdb_id: root
> ldapdb_pw: secret
> ldapdb_mech: DIGEST-MD5
> +ldapdb_canon_attr: uid
> </pre>
>
> <p>The LDAP server must be configured to map the SASL authcId "root" into a DN
> Index: plugins/ldapdb.c
> ===================================================================
> RCS file: /cvs/src/sasl/plugins/ldapdb.c,v
> retrieving revision 1.2
> diff -u -r1.2 ldapdb.c
> --- plugins/ldapdb.c 19 Feb 2005 02:26:31 -0000 1.2
> +++ plugins/ldapdb.c 13 Jan 2007 01:05:49 -0000
> @@ -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,133 @@
> 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;
>
> -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 */
> -};
> + /* If no canon attribute was configured, we can't do anything */
> + if(!ctx->canon.bv_val) 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) {
> + 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 + 2;
> + 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_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 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 +400,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;
>
> - p = utils->malloc(sizeof(ldapctx));
> - if (!p) return SASL_NOMEM;
> - *p = tmp;
> - ldapdb_auxprop_plugin.glob_context = p;
> + 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;
> +
> + 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 */
> + NULL, /* 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;
> }
> Index: plugins/makeinit.sh
> ===================================================================
> RCS file: /cvs/src/sasl/plugins/makeinit.sh,v
> retrieving revision 1.10
> diff -u -r1.10 makeinit.sh
> --- plugins/makeinit.sh 16 Feb 2005 20:52:12 -0000 1.10
> +++ plugins/makeinit.sh 13 Jan 2007 01:05:49 -0000
> @@ -45,7 +45,7 @@
> " > ${mech}_init.c
> done
>
> -for mech in sasldb sql ldapdb; do
> +for mech in sasldb sql; do
>
> echo "
> #include <config.h>
> @@ -87,3 +87,46 @@
> " > ${mech}_init.c
> done
>
> +for mech in ldapdb; do
> +
> +echo "
> +#include <config.h>
> +
> +#include <string.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#ifndef macintosh
> +#include <sys/stat.h>
> +#endif
> +#include <fcntl.h>
> +#include <assert.h>
> +
> +#include <sasl.h>
> +#include <saslplug.h>
> +#include <saslutil.h>
> +
> +#include \"plugin_common.h\"
> +
> +#ifdef WIN32
> +BOOL APIENTRY DllMain( HANDLE hModule,
> + DWORD ul_reason_for_call,
> + LPVOID lpReserved
> + )
> +{
> + switch (ul_reason_for_call)
> + {
> + case DLL_PROCESS_ATTACH:
> + case DLL_THREAD_ATTACH:
> + case DLL_THREAD_DETACH:
> + case DLL_PROCESS_DETACH:
> + break;
> + }
> + return TRUE;
> +}
> +#endif
> +
> +SASL_AUXPROP_PLUG_INIT( $mech )
> +SASL_CANONUSER_PLUG_INIT( $mech )
> +" > ${mech}_init.c
> +done
> +
More information about the Cyrus-sasl
mailing list