From 4c85b3db8974759026bb318110baa19a5d6fe844 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sat, 25 Jul 2015 22:23:46 +0100 Subject: [PATCH] Add filter remapping --- contrib/slapd-modules/adremap/adremap.c | 171 +++++++++++++++++- contrib/slapd-modules/adremap/slapo-adremap.5 | 20 +- 2 files changed, 183 insertions(+), 8 deletions(-) diff --git a/contrib/slapd-modules/adremap/adremap.c b/contrib/slapd-modules/adremap/adremap.c index 38c95aafce..df11694597 100644 --- a/contrib/slapd-modules/adremap/adremap.c +++ b/contrib/slapd-modules/adremap/adremap.c @@ -39,6 +39,10 @@ typedef struct adremap_dnv { AttributeDescription *ad_dnattr; /* DN-valued attr to deref */ AttributeDescription *ad_deref; /* target attr's value to retrieve */ AttributeDescription *ad_newattr; /* New attr to collect new values */ + ObjectClass *ad_group; /* group objectclass on target */ + ObjectClass *ad_mapgrp; /* group objectclass to map */ + ObjectClass *ad_refgrp; /* objectclass of target DN */ + struct berval ad_refbase; /* base DN of target entries */ } adremap_dnv; /* example: member uid memberUid */ @@ -69,11 +73,12 @@ static ConfigTable adremapcfg[] = { "NAME 'olcADremapDowncase' " "DESC 'List of attributes to casefold to lower case' " "SYNTAX OMsDirectoryString )", NULL, NULL }, - { "adremap-dnmap", "dnattr simpleattr newattr", 4, 4, 0, + { "adremap-dnmap", "dnattr targetattr newattr remoteOC localOC targetOC baseDN", 8, 8, 0, ARG_MAGIC|ADREMAP_DNV, adremap_cf_dnv, "( OLcfgCtAt:6.2 " "NAME 'olcADremapDNmap' " - "DESC 'DN attr to map, attr from target to use, attr to generate' " + "DESC 'DN attr to map, attr from target to use, attr to generate, objectclass of remote" + " group, objectclass mapped group, objectclass of target entry, base DN of target entry' " "SYNTAX OMsDirectoryString )", NULL, NULL }, { NULL, NULL, 0, 0, 0, ARG_IGNORED } }; @@ -151,12 +156,25 @@ adremap_cf_dnv(ConfigArgs *c) char *ptr; struct berval bv; bv.bv_len = ad->ad_dnattr->ad_cname.bv_len + ad->ad_deref->ad_cname.bv_len + ad->ad_newattr->ad_cname.bv_len + 2; + bv.bv_len += ad->ad_group->soc_cname.bv_len + ad->ad_mapgrp->soc_cname.bv_len + ad->ad_refgrp->soc_cname.bv_len + 3; + bv.bv_len += ad->ad_refbase.bv_len + 3; bv.bv_val = ch_malloc(bv.bv_len + 1); ptr = lutil_strcopy(bv.bv_val, ad->ad_dnattr->ad_cname.bv_val); *ptr++ = ' '; ptr = lutil_strcopy(ptr, ad->ad_deref->ad_cname.bv_val); *ptr++ = ' '; - strcpy(ptr, ad->ad_newattr->ad_cname.bv_val); + ptr = lutil_strcopy(ptr, ad->ad_newattr->ad_cname.bv_val); + *ptr++ = ' '; + ptr = lutil_strcopy(ptr, ad->ad_group->soc_cname.bv_val); + *ptr++ = ' '; + ptr = lutil_strcopy(ptr, ad->ad_mapgrp->soc_cname.bv_val); + *ptr++ = ' '; + ptr = lutil_strcopy(ptr, ad->ad_refgrp->soc_cname.bv_val); + *ptr++ = ' '; + *ptr++ = '"'; + ptr = lutil_strcopy(ptr, ad->ad_refbase.bv_val); + *ptr++ = '"'; + *ptr = '\0'; ber_bvarray_add(&c->rvalue_vals, &bv); } if (ai->ai_dnv) rc = 0; @@ -179,6 +197,7 @@ adremap_cf_dnv(ConfigArgs *c) default: { const char *text; adremap_dnv av = {0}; + struct berval dn; rc = slap_str2ad(c->argv[1], &av.ad_dnattr, &text); if (rc) break; if (av.ad_dnattr->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName) { @@ -192,6 +211,24 @@ adremap_cf_dnv(ConfigArgs *c) if (rc) break; rc = slap_str2ad(c->argv[3], &av.ad_newattr, &text); if (rc) break; + av.ad_group = oc_find(c->argv[4]); + if (!av.ad_group) { + rc = 1; + break; + } + av.ad_mapgrp = oc_find(c->argv[5]); + if (!av.ad_mapgrp) { + rc = 1; + break; + } + av.ad_refgrp = oc_find(c->argv[6]); + if (!av.ad_refgrp) { + rc = 1; + break; + } + ber_str2bv(c->argv[7], 0, 0, &dn); + rc = dnNormalize(0, NULL, NULL, &dn, &av.ad_refbase, NULL); + if (rc) break; for (a2 = &ai->ai_dnv; *a2; a2 = &(*a2)->ad_next); ad = ch_malloc(sizeof(adremap_dnv)); @@ -199,6 +236,10 @@ adremap_cf_dnv(ConfigArgs *c) ad->ad_dnattr = av.ad_dnattr; ad->ad_deref = av.ad_deref; ad->ad_newattr = av.ad_newattr; + ad->ad_group = av.ad_group; + ad->ad_mapgrp = av.ad_mapgrp; + ad->ad_refgrp = av.ad_refgrp; + ad->ad_refbase = av.ad_refbase; *a2 = ad; break; } @@ -268,6 +309,123 @@ adremap_search_resp( return SLAP_CB_CONTINUE; } +static int adremap_refsearch( + Operation *op, + SlapReply *rs +) +{ + if (rs->sr_type == REP_SEARCH) { + slap_callback *sc = op->o_callback; + struct berval *dn = sc->sc_private; + ber_dupbv_x(dn, &rs->sr_entry->e_nname, op->o_tmpmemctx); + } + return LDAP_SUCCESS; +} + +static int adremap_filter( + Operation *op, + adremap_info *ai +) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + Filter *f = op->ors_filter; + adremap_dnv *ad; + + /* Do we need to munge the filter? First see if it's of + * the form (&(objectClass=)...) + */ + if (f->f_choice == LDAP_FILTER_AND && f->f_and && + f->f_and->f_choice == LDAP_FILTER_EQUALITY && + f->f_and->f_av_desc == slap_schema.si_ad_objectClass) { + struct berval bv = f->f_and->f_av_value; + for (ad = ai->ai_dnv; ad; ad = ad->ad_next) { + if (!ber_bvstrcasecmp( &bv, &ad->ad_mapgrp->soc_cname )) { + /* Now check to see if next element is (=foo) */ + Filter *fn = f->f_and->f_next; + if (fn && fn->f_choice == LDAP_FILTER_EQUALITY && + fn->f_av_desc == ad->ad_newattr) { + Filter fr[3], *fnew; + AttributeAssertion aa[2]; + Operation op2; + slap_callback cb = {0}; + SlapReply rs = {REP_RESULT}; + struct berval dn = BER_BVNULL; + + /* It's a match, setup a search with filter + * (&(objectclass=)(=foo)) + */ + fr[0].f_choice = LDAP_FILTER_AND; + fr[0].f_and = &fr[1]; + + fr[1].f_choice = LDAP_FILTER_EQUALITY; + fr[1].f_ava = &aa[0]; + fr[1].f_av_desc = slap_schema.si_ad_objectClass; + fr[1].f_av_value = ad->ad_refgrp->soc_cname; + fr[1].f_next = &fr[2]; + + fr[2].f_choice = LDAP_FILTER_EQUALITY; + fr[2].f_ava = &aa[1]; + fr[2].f_av_desc = ad->ad_deref; + fr[2].f_av_value = fn->f_av_value; + fr[2].f_next = NULL; + + /* Search with this filter to retrieve target DN */ + op2 = *op; + op2.o_callback = &cb; + cb.sc_response = adremap_refsearch; + cb.sc_private = &dn; + op2.o_req_dn = ad->ad_refbase; + op2.o_req_ndn = ad->ad_refbase; + op2.ors_filter = fr; + filter2bv_x(op, fr, &op2.ors_filterstr); + op2.ors_deref = LDAP_DEREF_NEVER; + op2.ors_slimit = 1; + op2.ors_tlimit = SLAP_NO_LIMIT; + op2.ors_attrs = slap_anlist_no_attrs; + op2.ors_attrsonly = 1; + op2.o_bd->bd_info = (BackendInfo *)on->on_info; + op2.o_bd->be_search(&op2, &rs); + op2.o_bd->bd_info = (BackendInfo *)on; + op->o_tmpfree(op2.ors_filterstr.bv_val, op->o_tmpmemctx); + + if (!dn.bv_len) /* no match was found */ + return 0; + + /* Build a new filter of form + * (&(objectclass=)(=foo-DN)...) + */ + f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); + f->f_choice = LDAP_FILTER_AND; + fnew = f; + + f->f_and = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); + f = f->f_and; + f->f_choice = LDAP_FILTER_EQUALITY; + f->f_ava = op->o_tmpalloc(sizeof(AttributeAssertion), op->o_tmpmemctx); + f->f_av_desc = slap_schema.si_ad_objectClass; + ber_dupbv_x(&f->f_av_value, &ad->ad_group->soc_cname, op->o_tmpmemctx); + + f->f_next = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); + f = f->f_next; + f->f_choice = LDAP_FILTER_EQUALITY; + f->f_ava = op->o_tmpalloc(sizeof(AttributeAssertion), op->o_tmpmemctx); + f->f_av_desc = ad->ad_dnattr; + f->f_av_value = dn; + f->f_next = fn->f_next; + + fn->f_next = NULL; + filter_free_x(op, op->ors_filter, 1); + op->o_tmpfree(op->ors_filterstr.bv_val, op->o_tmpmemctx); + op->ors_filter = fnew; + filter2bv_x(op, op->ors_filter, &op->ors_filterstr); + return 1; + } + } + } + } + return 0; /* didn't match anything */ +} + static int adremap_search( Operation *op, @@ -275,13 +433,20 @@ adremap_search( ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + adremap_info *ai = (adremap_info *) on->on_bi.bi_private; slap_callback *cb; + if (ai->ai_dnv) { + /* check for filter match, fallthru if none */ + if (!adremap_filter(op, ai)) + return SLAP_CB_CONTINUE; + } cb = op->o_tmpcalloc(1, sizeof(slap_callback), op->o_tmpmemctx); cb->sc_response = adremap_search_resp; cb->sc_private = on; cb->sc_next = op->o_callback; op->o_callback = cb; + return SLAP_CB_CONTINUE; } diff --git a/contrib/slapd-modules/adremap/slapo-adremap.5 b/contrib/slapd-modules/adremap/slapo-adremap.5 index bf382241d8..8b1fa45865 100644 --- a/contrib/slapd-modules/adremap/slapo-adremap.5 +++ b/contrib/slapd-modules/adremap/slapo-adremap.5 @@ -45,12 +45,19 @@ directive. They can each be specified multiple times: Specify an attributeType whose values will all be mapped to lowercase when returned in search responses. .TP -.B adremap-dnmap +.B adremap-dnmap Specify a DN-valued attributeType whose values will be dereferenced. The -.B +.B of the target entry will be retrieved and its value will be added to the .B -in the entry. +in the entry. In addition, searches using a filter of the form +.B (&(objectClass=)(=xxx)) +will be rewritten into the form +.BR (&(objectClass=)(=xxx-DN)) . +This rewrite will accomplished by performing an additional internal search, +with subtree scope, using the specified baseDN and a filter of the form +.BR (&(objectClass=)(=xxx)) . + .SH EXAMPLE This example configures the @@ -59,7 +66,10 @@ overlay to map all .B uid attributes to lowercase, and create .B memberUid -values for group entries. +values for group entries. The mapping will turn requests for posixGroup +entries into requests for groupOfNames entries, and the internal search +will use inetOrgPerson entries under the ou=People,dc=example,dc=com subtree. + Add the following to .BR slapd.conf (5): @@ -70,7 +80,7 @@ Add the following to overlay adremap adremap-downcase uid - adremap-dnmap member uid memberUid + adremap-dnmap member uid memberUid groupOfNames posixGroup inetOrgPerson ou=people,dc=example,dc=com .fi .LP .B slapd -- 2.39.5