From 340e56ed0ed8b8634fbfd26be45aad3c8c3304a6 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sat, 13 Jul 2002 07:20:38 +0000 Subject: [PATCH] LDAP auxprop plugin for external SASL-enabled servers --- contrib/ldapsasl/README | 50 +++++++++ contrib/ldapsasl/ldapdb.c | 220 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+) create mode 100644 contrib/ldapsasl/README create mode 100644 contrib/ldapsasl/ldapdb.c diff --git a/contrib/ldapsasl/README b/contrib/ldapsasl/README new file mode 100644 index 0000000000..36c3f6b990 --- /dev/null +++ b/contrib/ldapsasl/README @@ -0,0 +1,50 @@ +LDAP auxprop plugin for SASL-enabled servers. +Copyright (C) 2002 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. + +The file ldapdb.c was written for Cyrus SASL 2.1.3 and OpenLDAP 2.1.3. +It can be compiled by copying into the Cyrus SASL source tree, in the +plugins subdirectory. No configuration or build script is provided. + +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 + +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_id: root +ldapdb_pw: secret +ldapdb_mech: PLAIN + +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.) + +Unlike other LDAP-enabled plugins for other services that are common +on the web, this plugin does not require you to configure DN search +patterns to map usernames to LDAP DNs. This plugin requires SASL name +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. +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 +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. + + -- Howard Chu, 2002-07-12 diff --git a/contrib/ldapsasl/ldapdb.c b/contrib/ldapsasl/ldapdb.c new file mode 100644 index 0000000000..0772aeafa2 --- /dev/null +++ b/contrib/ldapsasl/ldapdb.c @@ -0,0 +1,220 @@ +/* SASL LDAP auxprop implementation + * Copyright (C) 2002 Howard Chu, hyc@symas.com + */ + +#include + +#include + +#include "sasl.h" +#include "saslutil.h" +#include "saslplug.h" + +#include "plugin_common.h" + +#include + +static char ldapdb[] = "ldapdb"; + +SASL_AUXPROP_PLUG_INIT( ldapdb ) + +typedef struct ldapctx { + const char *uri; /* URI of LDAP server */ + const char *id; /* SASL authcid to bind as */ + const char *pw; /* password for bind */ + const char *mech; /* SASL mech */ +} ldapctx; + +typedef struct gluectx { + ldapctx *lc; + sasl_server_params_t *lp; + const char *user; +} gluectx; + +static int ldapdb_interact(LDAP *ld, unsigned flags __attribute__((unused)), + void *def, void *inter) +{ + sasl_interact_t *in = inter; + gluectx *gc = def; + const char *p; + + for (;in->id != SASL_CB_LIST_END;in++) + { + p = NULL; + switch(in->id) + { + case SASL_CB_GETREALM: + ldap_get_option(ld, LDAP_OPT_X_SASL_REALM, &p); + break; + case SASL_CB_AUTHNAME: + p = gc->lc->id; + break; + case SASL_CB_PASS: + p = gc->lc->pw; + break; + case SASL_CB_USER: + p = gc->user; + break; + } + if (p) + { + int l = strlen(p); + in->result = gc->lp->utils->malloc(l+1); + if (!in->result) + return LDAP_NO_MEMORY; + strcpy((char *)in->result, p); + in->len = l; + } + } + return LDAP_SUCCESS; +} + +static void ldapdb_auxprop_lookup(void *glob_context, + sasl_server_params_t *sparams, + unsigned flags, + const char *user, + unsigned ulen) +{ + ldapctx *ctx = glob_context; + int ret, i, n, *aindx; + const struct propval *pr; + LDAP *ld = NULL; + gluectx gc = { ctx, sparams, NULL }; + struct berval *dn = NULL, **bvals; + LDAPMessage *msg, *res; + char **attrs = NULL, *authzid = NULL; + + if(!ctx || !sparams || !user) return; + + pr = sparams->utils->prop_get(sparams->propctx); + if(!pr) return; + + /* count how many attrs to fetch */ + for(i = 0, n = 0; pr[i].name; i++) { + if(pr[i].name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID)) + continue; + if(pr[i].values && !(flags & SASL_AUXPROP_OVERRIDE)) + continue; + n++; + } + /* nothing to do, bail out */ + if (!n) return; + + /* alloc an array of attr names for search, and index to the props */ + attrs = sparams->utils->malloc((n+1)*sizeof(char *)*2); + if (!attrs) return; + + aindx = (int *)(attrs + n + 1); + + /* copy attr list */ + for (i=0, n=0; pr[i].name; i++) { + if(pr[i].name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID)) + continue; + if(pr[i].values && !(flags & SASL_AUXPROP_OVERRIDE)) + continue; + attrs[n] = (char *)pr[i].name; + if (pr[i].name[0] == '*') attrs[n]++; + aindx[n] = i; + 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); + gc.user = authzid; + + i = LDAP_VERSION3; + ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &i); + + ret = ldap_sasl_interactive_bind_s(ld, NULL, ctx->mech, NULL, NULL, + LDAP_SASL_QUIET, ldapdb_interact, &gc); + if (ret != LDAP_SUCCESS) goto done; + + ret = ldap_extended_operation_s(ld, LDAP_EXOP_X_WHO_AM_I, NULL, NULL, + NULL, NULL, &dn); + if (ret != LDAP_SUCCESS || !dn) goto done; + + if (dn->bv_val && !strncmp(dn->bv_val, "dn:", 3)) + ret = ldap_search_s(ld, dn->bv_val+3, LDAP_SCOPE_BASE, "(objectclass=*)", + attrs, 0, &res); + ber_bvfree(dn); + + if (ret != LDAP_SUCCESS) goto done; + + for(msg=ldap_first_message(ld, res); msg; msg=ldap_next_message(ld, msg)) + { + if (ldap_msgtype(msg) != LDAP_RES_SEARCH_ENTRY) continue; + for (i=0; iutils->prop_erase(sparams->propctx, pr[aindx[i]].name); + sparams->utils->prop_set(sparams->propctx, pr[aindx[i]].name, + bvals[0]->bv_val, bvals[0]->bv_len); + ber_bvecfree(bvals); + } + } + ldap_msgfree(res); + + done: + if(authzid) sparams->utils->free(authzid); + if(attrs) sparams->utils->free(attrs); + if(ld) ldap_unbind(ld); +} + +static void ldapdb_auxprop_free(void *glob_ctx, const sasl_utils_t *utils) +{ + utils->free(glob_ctx); +} + +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 */ + NULL /* spare */ +}; + +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))) +{ + ldapctx tmp, *p; + const char *s; + + if(!out_version || !plug) return SASL_BADPARAM; + + if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS; + + utils->getopt(utils->getopt_context, ldapdb, "ldapdb_uri", &tmp.uri, NULL); + if(!tmp.uri) return SASL_BADPARAM; + + utils->getopt(utils->getopt_context, ldapdb, "ldapdb_id", &tmp.id, NULL); + utils->getopt(utils->getopt_context, ldapdb, "ldapdb_pw", &tmp.pw, NULL); + utils->getopt(utils->getopt_context, ldapdb, "ldapdb_mech", &tmp.mech, NULL); + utils->getopt(utils->getopt_context, ldapdb, "ldapdb_rc", &s, NULL); + if(s && setenv("LDAPRC", s, 1)) return SASL_BADPARAM; + + p = utils->malloc(sizeof(ldapctx)); + if (!p) return SASL_NOMEM; + *p = tmp; + ldapdb_auxprop_plugin.glob_context = p; + + *out_version = SASL_AUXPROP_PLUG_VERSION; + + *plug = &ldapdb_auxprop_plugin; + + return SASL_OK; +} -- 2.39.5