Add filter remapping

This commit is contained in:
Howard Chu 2015-07-25 22:23:46 +01:00
parent fa705a1814
commit 4cbd3b63c0
2 changed files with 183 additions and 8 deletions

View File

@ -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=<mapgrp>)...)
*/
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 (<newattr>=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=<refgrp>)(<deref>=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=<group>)(<dnattr>=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;
}

View File

@ -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 <dnattr> <derefattr> <newattr>
.B adremap-dnmap <dnattr> <targetattr> <newattr> <remoteOC> <localOC> <targetOC> <baseDN>
Specify a DN-valued attributeType whose values will be dereferenced. The
.B <derefattr>
.B <targetattr>
of the target entry will be retrieved and its value will be added to the
.B <newattr>
in the entry.
in the entry. In addition, searches using a filter of the form
.B (&(objectClass=<localOC>)(<newattr>=xxx))
will be rewritten into the form
.BR (&(objectClass=<remoteOC>)(<dnattr>=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=<targetOC>)(<targetattr>=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