From bcb7c49622148b6518b5022584b26d63f2f40b95 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sat, 29 Nov 2003 23:10:03 +0000 Subject: [PATCH] ITS#2838, sync with HEAD --- contrib/ldapsasl/README | 48 ++++++--- contrib/ldapsasl/ldapdb.c | 218 +++++++++++++++++++++++++------------- 2 files changed, 178 insertions(+), 88 deletions(-) diff --git a/contrib/ldapsasl/README b/contrib/ldapsasl/README index 3ac8f814a4..feed4c26d7 100644 --- a/contrib/ldapsasl/README +++ b/contrib/ldapsasl/README @@ -1,10 +1,17 @@ LDAP auxprop plugin for SASL-enabled servers. -Copyright (C) 2002 by Howard Chu, hyc@symas.com +Copyright (C) 2002,2003 by Howard Chu, hyc@symas.com -This software is an experimental proof-of-concept and is not intended for -general use. It is licensed under the terms ofthe OpenLDAP license. +This software is licensed under the terms of the OpenLDAP license. The file ldapdb.c was written for Cyrus SASL 2.1.3 and OpenLDAP 2.1.3. +Due to various bugs in the Cyrus source you should use Cyrus SASL 2.1.15 +or newer. You need at least Cyrus SASL 2.1.16 to use the auxprop-store +functionality. + +The version of ldapdb bundled with OpenLDAP 2.1.22 and older will work +with all OpenLDAP releases 2.1.3 and up. The ldapdb in OpenLDAP 2.1.23 +uses a different LDAP request and requires the server to be 2.1.23 or newer. + It can be compiled by copying into the Cyrus SASL source tree, in the plugins subdirectory. No configuration or build script is provided. @@ -12,21 +19,21 @@ To compile, type "make ldapdb.lo". To link, you'll have to copy the link rule for one of the other plugins. Below is a sample on my Linux system: - /bin/sh ./libtool --mode=link gcc -Wall -W -g -O2 -L/usr/local/lib -Wl,-rpath,/usr/local/lib -module -export-dynamic -rpath /usr/lib/sasl2 -o libldapdb.la -version-info 2:4:0 ldapdb.lo -lldap -llber -lssl -lcrypto + /bin/sh ../libtool --mode=link gcc -Wall -W -g -O2 -L/usr/local/lib -Wl,-rpath,/usr/local/lib -module -export-dynamic -rpath /usr/lib/sasl2 -o libldapdb.la -version-info 2:4:0 ldapdb.lo -lldap -llber -lssl -lcrypto Once installed, you need to add some config items to the SASL server's config file in /usr/lib/sasl2. For example: -ldapdb_uri: ldapi:// +ldapdb_uri: ldap://ldap.example.com ldapdb_id: root ldapdb_pw: secret -ldapdb_mech: PLAIN +ldapdb_mech: DIGEST-MD5 This config assumes an LDAP server on the same machine as the server that is using SASL. The LDAP server must be configured to map the SASL authcId "root" into a DN that has proxy authorization privileges to every account that is allowed to login to this server. (See the OpenLDAP -Admin Guide for details.) +Admin Guide section 10 for details.) Unlike other LDAP-enabled plugins for other services that are common on the web, this plugin does not require you to configure DN search @@ -35,7 +42,7 @@ mapping to be configured on the target slapd. This approach keeps the LDAP-specific configuration details in one place, the slapd.conf, and makes the configuration of remote services much simpler. -One additional keyword "ldapdb_rc" may be specified in the config file. +An additional keyword "ldapdb_rc" may be specified in the config file. The filename specified here will be put into the server's LDAPRC environment variable, and libldap-specific config options may be set in that ldaprc file. The main purpose behind this option is to allow @@ -43,11 +50,22 @@ a client TLS certificate to be configured, so that SASL/EXTERNAL may be used between the SASL server and the LDAP server. This is the most optimal way to use this plugin when the servers are on separate machines. -This plugin likely has very poor performance. You'll need something -better for a real production environment. Please send feedback via the -openldap-software mailing list for now. +Note: this plugin is not for use with slapd itself. When OpenLDAP is +built with SASL support, slapd uses its own internal auxprop 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 +by slapd, you can stop it by creating /usr/lib/sasl2/slapd.conf with: + + auxprop_plugin: slapd + +which will force the SASL library to ignore all other auxprop modules. + +This plugin has been in use for over a year at many sites with good +results. If you have questions or problems, please send feedback via +the openldap-software mailing list. - -- Howard Chu, 2002-07-12 + -- Howard Chu Update... With OpenLDAP 2.1.13 you can use SASL/EXTERNAL on ldapi://. This is fast and secure, and needs no username or password to be stored. @@ -64,9 +82,9 @@ sasl-regexp uidNumber=(.*)\\+gidNumber=(.*),cn=peercred,cn=external,cn=auth sasl-regexp uid=(.*),cn=external,cn=auth ldap:///dc=example,dc=com??sub?(uid=$1) -One more update: you can use the ldapdb_starttls keyword to use the -StartTLS extended operation on an LDAP session. This item may be set -to either "try" or "demand", e.g.: +Update... With OpenLDAP 2.1.23 you can use the ldapdb_starttls keyword +to use the StartTLS extended operation on an LDAP session. This item +may be set to either "try" or "demand", e.g.: ldapdb_uri: ldap://ldap.example.com ldapdb_starttls: try diff --git a/contrib/ldapsasl/ldapdb.c b/contrib/ldapsasl/ldapdb.c index 0f89121b95..da52ec1fba 100644 --- a/contrib/ldapsasl/ldapdb.c +++ b/contrib/ldapsasl/ldapdb.c @@ -1,22 +1,14 @@ +/* $OpenLDAP$ */ /* SASL LDAP auxprop implementation * Copyright (C) 2002,2003 Howard Chu, All rights reserved. * - * Permission is granted to anyone to use this software for any purpose - * on any computer system, and to alter it and redistribute it, subject - * to the following restrictions: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. * - * 1. The author is not responsible for the consequences of use of this - * software, no matter how awful, even if they arise from flaws in it. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Since few users ever read sources, - * credits should appear in the documentation. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. Since few users - * ever read sources, credits should appear in the documentation. - * - * 4. This notice may not be removed or altered. + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . */ #include @@ -27,6 +19,9 @@ #include "saslutil.h" #include "saslplug.h" +#define SASL_VERSION_FULL ((SASL_VERSION_MAJOR << 16) |\ + (SASL_VERSION_MINOR << 8) |SASL_VERSION_STEP) + #include "plugin_common.h" #include @@ -41,16 +36,11 @@ typedef struct ldapctx { int use_tls; /* Issue StartTLS request? */ } ldapctx; -typedef struct gluectx { - ldapctx *lc; - sasl_server_params_t *lp; -} gluectx; - static int ldapdb_interact(LDAP *ld, unsigned flags __attribute__((unused)), void *def, void *inter) { sasl_interact_t *in = inter; - gluectx *gc = def; + ldapctx *ctx = def; struct berval p; for (;in->id != SASL_CB_LIST_END;in++) @@ -63,10 +53,10 @@ static int ldapdb_interact(LDAP *ld, unsigned flags __attribute__((unused)), if (p.bv_val) p.bv_len = strlen(p.bv_val); break; case SASL_CB_AUTHNAME: - p = gc->lc->id; + p = ctx->id; break; case SASL_CB_PASS: - p = gc->lc->pw; + p = ctx->pw; break; } if (p.bv_val) @@ -78,6 +68,67 @@ static int ldapdb_interact(LDAP *ld, unsigned flags __attribute__((unused)), return LDAP_SUCCESS; } +typedef struct connparm { + LDAP *ld; + LDAPControl c; + LDAPControl *ctrl[2]; + struct berval *dn; +} connparm; + +static int ldapdb_connect(ldapctx *ctx, sasl_server_params_t *sparams, + const char *user, unsigned ulen, connparm *cp) +{ + int i; + char *authzid; + + if((i=ldap_initialize(&cp->ld, ctx->uri))) { + return i; + } + + authzid = sparams->utils->malloc(ulen + sizeof("u:")); + if (!authzid) { + return LDAP_NO_MEMORY; + } + strcpy(authzid, "u:"); + strcpy(authzid+2, user); + cp->c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; + cp->c.ldctl_value.bv_val = authzid; + cp->c.ldctl_value.bv_len = ulen + 2; + cp->c.ldctl_iscritical = 1; + + i = LDAP_VERSION3; + ldap_set_option(cp->ld, LDAP_OPT_PROTOCOL_VERSION, &i); + + /* If TLS is set and it fails, continue or bail out as requested */ + if (ctx->use_tls && (i=ldap_start_tls_s(cp->ld, NULL, NULL)) != LDAP_SUCCESS + && ctx->use_tls > 1) { + sparams->utils->free(authzid); + return i; + } + + i = ldap_sasl_interactive_bind_s(cp->ld, NULL, ctx->mech.bv_val, NULL, + NULL, LDAP_SASL_QUIET, ldapdb_interact, ctx); + if (i != LDAP_SUCCESS) { + sparams->utils->free(authzid); + return i; + } + + cp->ctrl[0] = &cp->c; + cp->ctrl[1] = NULL; + i = ldap_whoami_s(cp->ld, &cp->dn, cp->ctrl, NULL); + if (i == LDAP_SUCCESS && cp->dn) { + if (!cp->dn->bv_val || strncmp(cp->dn->bv_val, "dn:", 3)) { + ber_bvfree(cp->dn); + cp->dn = NULL; + i = LDAP_INVALID_SYNTAX; + } else { + cp->c.ldctl_value = *(cp->dn); + } + } + sparams->utils->free(authzid); + return i; +} + static void ldapdb_auxprop_lookup(void *glob_context, sasl_server_params_t *sparams, unsigned flags, @@ -85,14 +136,12 @@ static void ldapdb_auxprop_lookup(void *glob_context, unsigned ulen) { ldapctx *ctx = glob_context; + connparm cp; int ret, i, n, *aindx; const struct propval *pr; - LDAP *ld = NULL; - gluectx gc; - struct berval *dn = NULL, **bvals; + struct berval **bvals; LDAPMessage *msg, *res; - char **attrs = NULL, *authzid = NULL; - LDAPControl c, *ctrl[2]; + char **attrs = NULL; if(!ctx || !sparams || !user) return; @@ -128,57 +177,23 @@ static void ldapdb_auxprop_lookup(void *glob_context, n++; } attrs[n] = NULL; - - if(ldap_initialize(&ld, ctx->uri)) { - sparams->utils->free(attrs); - return; - } - - authzid = sparams->utils->malloc(ulen + sizeof("u:")); - if (!authzid) goto done; - strcpy(authzid, "u:"); - strcpy(authzid+2, user); - c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; - c.ldctl_value.bv_val = authzid; - c.ldctl_value.bv_len = ulen + 2; - c.ldctl_iscritical = 1; - - i = LDAP_VERSION3; - ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &i); - /* If TLS is set and it fails, continue or bail out as requested */ - if (ctx->use_tls && ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) { - if (ctx->use_tls > 1) goto done; + if(ldapdb_connect(ctx, sparams, user, ulen, &cp)) { + goto done; } - gc.lc = ctx; - gc.lp = sparams; - ret = ldap_sasl_interactive_bind_s(ld, NULL, ctx->mech.bv_val, NULL, NULL, - LDAP_SASL_QUIET, ldapdb_interact, &gc); - if (ret != LDAP_SUCCESS) goto done; - - ctrl[0] = &c; - ctrl[1] = NULL; - ret = ldap_whoami_s(ld, &dn, ctrl, NULL); - if (ret != LDAP_SUCCESS || !dn) goto done; - - if (!dn->bv_val || strncmp(dn->bv_val, "dn:", 3)) { - ber_bvfree(dn); - goto done; - } - c.ldctl_value = *dn; - ret = ldap_search_ext_s(ld, dn->bv_val+3, LDAP_SCOPE_BASE, - "(objectclass=*)", attrs, 0, ctrl, NULL, NULL, 1, &res); - ber_bvfree(dn); + 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(ld, res); msg; msg=ldap_next_message(ld, msg)) + 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; for (i=0; iutils->prop_erase(sparams->propctx, pr[aindx[i]].name); @@ -190,10 +205,63 @@ static void ldapdb_auxprop_lookup(void *glob_context, ldap_msgfree(res); done: - if(authzid) sparams->utils->free(authzid); if(attrs) sparams->utils->free(attrs); - if(ld) ldap_unbind(ld); + if(cp.ld) ldap_unbind(cp.ld); +} + +#if SASL_VERSION_FULL >= 0x020110 +static int ldapdb_auxprop_store(void *glob_context, + sasl_server_params_t *sparams, + struct propctx *prctx, + const char *user, + unsigned ulen) +{ + ldapctx *ctx = glob_context; + connparm cp; + const struct propval *pr; + int i, n; + LDAPMod **mods; + + /* just checking if we are enabled */ + if (!prctx) return SASL_OK; + + if (!sparams || !user) return SASL_BADPARAM; + + pr = sparams->utils->prop_get(prctx); + if (!pr) return SASL_BADPARAM; + + for (n=0; pr[n].name; n++); + if (!n) return SASL_BADPARAM; + + mods = sparams->utils->malloc((n+1) * sizeof(LDAPMod*) + n * sizeof(LDAPMod)); + if (!mods) return SASL_NOMEM; + + if((i=ldapdb_connect(ctx, sparams, user, ulen, &cp)) == 0) { + + for (i=0; imod_op = LDAP_MOD_REPLACE; + mods[i]->mod_type = (char *)pr[i].name; + mods[i]->mod_values = (char **)pr[i].values; + } + mods[i] = NULL; + + i = ldap_modify_ext_s(cp.ld, cp.dn->bv_val+3, mods, cp.ctrl, NULL); + ber_bvfree(cp.dn); + } + + sparams->utils->free(mods); + + if (i) { + sparams->utils->seterror(sparams->utils->conn, 0, + ldap_err2string(i)); + if (i == LDAP_NO_MEMORY) i = SASL_NOMEM; + else i = SASL_FAIL; + } + if (cp.ld) ldap_unbind(cp.ld); + return i; } +#endif /* SASL_VERSION_FULL >= 2.1.16 */ static void ldapdb_auxprop_free(void *glob_ctx, const sasl_utils_t *utils) { @@ -205,9 +273,13 @@ static sasl_auxprop_plug_t ldapdb_auxprop_plugin = { 0, /* spare */ NULL, /* glob_context */ ldapdb_auxprop_free, /* auxprop_free */ - ldapdb_auxprop_lookup, /* auxprop_lookup */ + ldapdb_auxprop_lookup, /* auxprop_lookup */ ldapdb, /* name */ - NULL /* spare */ +#if SASL_VERSION_FULL >=0x020110 + ldapdb_auxprop_store /* spare if <2.1.16*/ +#else + NULL +#endif }; static int ldapdb_auxprop_plug_init(const sasl_utils_t *utils, -- 2.47.2