]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/adremap/adremap.c
More filter tweaks
[openldap] / contrib / slapd-modules / adremap / adremap.c
1 /* adremap.c - Case-folding and DN-value remapping for AD proxies */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 2015 Howard Chu <hyc@symas.com>.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15
16 #include "portable.h"
17
18 /*
19  * This file implements an overlay that performs two remapping functions
20  * to allow older POSIX clients to use Microsoft AD:
21  * 1: downcase the values of a configurable list of attributes
22  * 2: dereference some DN-valued attributes and convert to their simple names
23  *         e.g. generate memberUid based on member
24  */
25
26 #ifdef SLAPD_OVER_ADREMAP
27
28 #include <ldap.h>
29 #include "lutil.h"
30 #include "slap.h"
31 #include <ac/errno.h>
32 #include <ac/time.h>
33 #include <ac/string.h>
34 #include <ac/ctype.h>
35 #include "config.h"
36
37 typedef struct adremap_dnv {
38         struct adremap_dnv *ad_next;
39         AttributeDescription *ad_dnattr;        /* DN-valued attr to deref */
40         AttributeDescription *ad_deref;         /* target attr's value to retrieve */
41         AttributeDescription *ad_newattr;       /* New attr to collect new values */
42         ObjectClass *ad_group;          /* group objectclass on target */
43         ObjectClass *ad_mapgrp;         /* group objectclass to map */
44         ObjectClass *ad_refgrp;         /* objectclass of target DN */
45         struct berval ad_refbase;       /* base DN of target entries */
46 } adremap_dnv;
47 /* example: member uid memberUid */
48
49 typedef struct adremap_case {
50         struct adremap_case *ac_next;
51         AttributeDescription *ac_attr;
52 } adremap_case;
53
54 /* Per-instance configuration information */
55 typedef struct adremap_info {
56         adremap_case *ai_case;  /* attrs to downcase */
57         adremap_dnv *ai_dnv;    /* DN attrs to remap */
58 } adremap_info;
59
60 enum {
61         ADREMAP_CASE = 1,
62         ADREMAP_DNV
63 };
64
65 static ConfigDriver adremap_cf_case;
66 static ConfigDriver adremap_cf_dnv;
67
68 /* configuration attribute and objectclass */
69 static ConfigTable adremapcfg[] = {
70         { "adremap-downcase", "attrs", 2, 0, 0,
71           ARG_MAGIC|ADREMAP_CASE, adremap_cf_case,
72           "( OLcfgCtAt:6.1 "
73           "NAME 'olcADremapDowncase' "
74           "DESC 'List of attributes to casefold to lower case' "
75           "SYNTAX OMsDirectoryString )", NULL, NULL },
76         { "adremap-dnmap", "dnattr targetattr newattr remoteOC localOC targetOC baseDN", 8, 8, 0,
77           ARG_MAGIC|ADREMAP_DNV, adremap_cf_dnv,
78           "( OLcfgCtAt:6.2 "
79           "NAME 'olcADremapDNmap' "
80           "DESC 'DN attr to map, attr from target to use, attr to generate, objectclass of remote"
81            " group, objectclass mapped group, objectclass of target entry, base DN of target entry' "
82           "SYNTAX OMsDirectoryString )", NULL, NULL },
83         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
84 };
85
86 static ConfigOCs adremapocs[] = {
87         { "( OLcfgCtOc:6.1 "
88           "NAME 'olcADremapConfig' "
89           "DESC 'AD remap configuration' "
90           "SUP olcOverlayConfig "
91           "MAY ( olcADremapDowncase $ olcADremapDNmap ) )",
92           Cft_Overlay, adremapcfg, NULL, NULL },
93         { NULL, 0, NULL }
94 };
95
96 static int
97 adremap_cf_case(ConfigArgs *c)
98 {
99         BackendDB *be = (BackendDB *)c->be;
100         slap_overinst *on = (slap_overinst *)c->bi;
101         adremap_info *ai = on->on_bi.bi_private;
102         adremap_case *ac, **a2;
103         int rc = ARG_BAD_CONF;
104
105         switch(c->op) {
106         case SLAP_CONFIG_EMIT:
107                 for (ac = ai->ai_case; ac; ac=ac->ac_next) {
108                         rc = value_add_one(&c->rvalue_vals, &ac->ac_attr->ad_cname);
109                         if (rc) break;
110                 }
111                 break;
112         case LDAP_MOD_DELETE:
113                 if (c->valx < 0) {
114                         for (ac = ai->ai_case; ac; ac=ai->ai_case) {
115                                 ai->ai_case = ac->ac_next;
116                                 ch_free(ac);
117                         }
118                 } else {
119                         int i;
120                         for (i=0, a2 = &ai->ai_case; i<c->valx; i++, a2 = &(*a2)->ac_next);
121                         ac = *a2;
122                         *a2 = ac->ac_next;
123                         ch_free(ac);
124                 }
125                 rc = 0;
126                 break;
127         default: {
128                 const char *text;
129                 adremap_case ad;
130                 ad.ac_attr = NULL;
131                 rc = slap_str2ad(c->argv[1], &ad.ac_attr, &text);
132                 if (rc) break;
133                 for (a2 = &ai->ai_case; *a2; a2 = &(*a2)->ac_next);
134                 ac = ch_malloc(sizeof(adremap_case));
135                 ac->ac_next = NULL;
136                 ac->ac_attr = ad.ac_attr;
137                 *a2 = ac;
138                 break;
139                 }
140         }
141         return rc;
142 }
143
144 static int
145 adremap_cf_dnv(ConfigArgs *c)
146 {
147         BackendDB *be = (BackendDB *)c->be;
148         slap_overinst *on = (slap_overinst *)c->bi;
149         adremap_info *ai = on->on_bi.bi_private;
150         adremap_dnv *ad, **a2;
151         int rc = ARG_BAD_CONF;
152
153         switch(c->op) {
154         case SLAP_CONFIG_EMIT:
155                 for (ad = ai->ai_dnv; ad; ad=ad->ad_next) {
156                         char *ptr;
157                         struct berval bv;
158                         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;
159                         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;
160                         bv.bv_len += ad->ad_refbase.bv_len + 3;
161                         bv.bv_val = ch_malloc(bv.bv_len + 1);
162                         ptr = lutil_strcopy(bv.bv_val, ad->ad_dnattr->ad_cname.bv_val);
163                         *ptr++ = ' ';
164                         ptr = lutil_strcopy(ptr, ad->ad_deref->ad_cname.bv_val);
165                         *ptr++ = ' ';
166                         ptr = lutil_strcopy(ptr, ad->ad_newattr->ad_cname.bv_val);
167                         *ptr++ = ' ';
168                         ptr = lutil_strcopy(ptr, ad->ad_group->soc_cname.bv_val);
169                         *ptr++ = ' ';
170                         ptr = lutil_strcopy(ptr, ad->ad_mapgrp->soc_cname.bv_val);
171                         *ptr++ = ' ';
172                         ptr = lutil_strcopy(ptr, ad->ad_refgrp->soc_cname.bv_val);
173                         *ptr++ = ' ';
174                         *ptr++ = '"';
175                         ptr = lutil_strcopy(ptr, ad->ad_refbase.bv_val);
176                         *ptr++ = '"';
177                         *ptr = '\0';
178                         ber_bvarray_add(&c->rvalue_vals, &bv);
179                 }
180                 if (ai->ai_dnv) rc = 0;
181                 break;
182         case LDAP_MOD_DELETE:
183                 if (c->valx < 0) {
184                         for (ad = ai->ai_dnv; ad; ad=ai->ai_dnv) {
185                                 ai->ai_dnv = ad->ad_next;
186                                 ch_free(ad);
187                         }
188                 } else {
189                         int i;
190                         for (i=0, a2 = &ai->ai_dnv; i<c->valx; i++, a2 = &(*a2)->ad_next);
191                         ad = *a2;
192                         *a2 = ad->ad_next;
193                         ch_free(ad);
194                 }
195                 rc = 0;
196                 break;
197         default: {
198                 const char *text;
199                 adremap_dnv av = {0};
200                 struct berval dn;
201                 rc = slap_str2ad(c->argv[1], &av.ad_dnattr, &text);
202                 if (rc) break;
203                 if (av.ad_dnattr->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName) {
204                         rc = 1;
205                         snprintf(c->cr_msg, sizeof(c->cr_msg), "<%s> not a DN-valued attribute",
206                                 c->argv[0]);
207                         Debug(LDAP_DEBUG_ANY, "%s: %s(%s)\n", c->log, c->cr_msg, c->argv[1]);
208                         break;
209                 }
210                 rc = slap_str2ad(c->argv[2], &av.ad_deref, &text);
211                 if (rc) break;
212                 rc = slap_str2ad(c->argv[3], &av.ad_newattr, &text);
213                 if (rc) break;
214                 av.ad_group = oc_find(c->argv[4]);
215                 if (!av.ad_group) {
216                         rc = 1;
217                         break;
218                 }
219                 av.ad_mapgrp = oc_find(c->argv[5]);
220                 if (!av.ad_mapgrp) {
221                         rc = 1;
222                         break;
223                 }
224                 av.ad_refgrp = oc_find(c->argv[6]);
225                 if (!av.ad_refgrp) {
226                         rc = 1;
227                         break;
228                 }
229                 ber_str2bv(c->argv[7], 0, 0, &dn);
230                 rc = dnNormalize(0, NULL, NULL, &dn, &av.ad_refbase, NULL);
231                 if (rc) break;
232
233                 for (a2 = &ai->ai_dnv; *a2; a2 = &(*a2)->ad_next);
234                 ad = ch_malloc(sizeof(adremap_dnv));
235                 ad->ad_next = NULL;
236                 ad->ad_dnattr = av.ad_dnattr;
237                 ad->ad_deref = av.ad_deref;
238                 ad->ad_newattr = av.ad_newattr;
239                 ad->ad_group = av.ad_group;
240                 ad->ad_mapgrp = av.ad_mapgrp;
241                 ad->ad_refgrp = av.ad_refgrp;
242                 ad->ad_refbase = av.ad_refbase;
243                 *a2 = ad;
244                 break;
245                 }
246         }
247         return rc;
248 }
249
250 typedef struct adremap_ctx {
251         slap_overinst *on;
252         AttributeName an;
253         AttributeDescription *ad;
254         int an_swap;
255 } adremap_ctx;
256
257 static int
258 adremap_search_resp(
259         Operation *op,
260         SlapReply *rs
261 )
262 {
263         adremap_ctx *ctx = op->o_callback->sc_private;
264         slap_overinst *on = ctx->on;
265         adremap_info *ai = on->on_bi.bi_private;
266         adremap_case *ac;
267         adremap_dnv *ad;
268         Attribute *a;
269         Entry *e;
270
271         if (rs->sr_type != REP_SEARCH)
272                 return SLAP_CB_CONTINUE;
273
274         /* we munged the attr list, restore it to original */
275         if (ctx->an_swap) {
276                 int i;
277                 ctx->an_swap = 0;
278                 for (i=0; rs->sr_attrs[i].an_name.bv_val; i++) {
279                         if (rs->sr_attrs[i].an_desc == ctx->ad) {
280                                 rs->sr_attrs[i] = ctx->an;
281                                 break;
282                         }
283                 }
284                 /* Usually rs->sr_attrs is just op->ors_attrs, but
285                  * overlays like rwm may make a new copy. Fix both
286                  * if needed.
287                  */
288                 if (op->ors_attrs != rs->sr_attrs) {
289                         for (i=0; op->ors_attrs[i].an_name.bv_val; i++) {
290                                 if (op->ors_attrs[i].an_desc == ctx->ad) {
291                                         op->ors_attrs[i] = ctx->an;
292                                         break;
293                                 }
294                         }
295                 }
296         }
297         e = rs->sr_entry;
298         for (ac = ai->ai_case; ac; ac = ac->ac_next) {
299                 a = attr_find(e->e_attrs, ac->ac_attr);
300                 if (a) {
301                         int i, j;
302                         if (!(rs->sr_flags & REP_ENTRY_MODIFIABLE)) {
303                                 e = entry_dup(e);
304                                 rs_replace_entry(op, rs, on, e);
305                                 rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED;
306                                 a = attr_find(e->e_attrs, ac->ac_attr);
307                         }
308                         for (i=0; i<a->a_numvals; i++) {
309                                 unsigned char *c = a->a_vals[i].bv_val;
310                                 for (j=0; j<a->a_vals[i].bv_len; j++)
311                                         if (isupper(c[j]))
312                                                 c[j] = tolower(c[j]);
313                         }
314                 }
315         }
316         for (ad = ai->ai_dnv; ad; ad = ad->ad_next) {
317                 a = attr_find(e->e_attrs, ad->ad_dnattr);
318                 if (a) {
319                         Entry *n;
320                         Attribute *dr;
321                         int i, rc;
322                         if (!(rs->sr_flags & REP_ENTRY_MODIFIABLE)) {
323                                 e = entry_dup(e);
324                                 rs_replace_entry(op, rs, on, e);
325                                 rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED;
326                                 a = attr_find(e->e_attrs, ad->ad_dnattr);
327                         }
328                         for (i=0; i<a->a_numvals; i++) {
329                                 struct berval dv;
330                                 dv = ad->ad_deref->ad_cname;
331                                         /* If the RDN uses the deref attr, just use it directly */
332                                 if (a->a_nvals[i].bv_val[dv.bv_len] == '=' &&
333                                         !memcmp(a->a_nvals[i].bv_val, dv.bv_val, dv.bv_len)) {
334                                         struct berval bv, nv;
335                                         char *ptr;
336                                         bv = a->a_vals[i];
337                                         nv = a->a_nvals[i];
338                                         bv.bv_val += dv.bv_len + 1;
339                                         ptr = strchr(bv.bv_val, ',');
340                                         if (ptr)
341                                                 bv.bv_len = ptr - bv.bv_val;
342                                         else
343                                                 bv.bv_len -= dv.bv_len+1;
344                                         nv.bv_val += dv.bv_len + 1;
345                                         ptr = strchr(nv.bv_val, ',');
346                                         if (ptr)
347                                                 nv.bv_len = ptr - nv.bv_val;
348                                         else
349                                                 nv.bv_len -= dv.bv_len+1;
350                                         attr_merge_one(e, ad->ad_newattr, &bv, &nv);
351                                 } else {
352                                         /* otherwise look up the deref attr */
353                                         n = NULL;
354                                         rc = be_entry_get_rw(op, &a->a_nvals[i], NULL, ad->ad_deref, 0, &n);
355                                         if (!rc && n) {
356                                                 dr = attr_find(n->e_attrs, ad->ad_deref);
357                                                 if (dr)
358                                                         attr_merge_one(e, ad->ad_newattr, dr->a_vals, dr->a_nvals);
359                                                 be_entry_release_r(op, n);
360                                         }
361                                 }
362                         }
363                 }
364         }
365         return SLAP_CB_CONTINUE;
366 }
367
368 static int adremap_refsearch(
369         Operation *op,
370         SlapReply *rs
371 )
372 {
373         if (rs->sr_type == REP_SEARCH) {
374                 slap_callback *sc = op->o_callback;
375                 struct berval *dn = sc->sc_private;
376                 ber_dupbv_x(dn, &rs->sr_entry->e_nname, op->o_tmpmemctx);
377                 return LDAP_SUCCESS;
378         }
379         return rs->sr_err;
380 }
381
382 static adremap_dnv *adremap_filter(
383         Operation *op,
384         adremap_info *ai
385 )
386 {
387         slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
388         Filter *f = op->ors_filter, *fn = NULL;
389         adremap_dnv *ad = NULL;
390         struct berval bv;
391         int fextra = 0;
392
393         /* Do we need to munge the filter? First see if it's of
394          * the form (objectClass=<mapgrp>)
395          * or form (&(objectClass=<mapgrp>)...)
396          * or form (&(&(objectClass=<mapgrp>)...)...)
397          */
398         if (f->f_choice == LDAP_FILTER_AND && f->f_and) {
399                 fextra = 1;
400                 f = f->f_and;
401                 fn = f->f_next;
402         }
403         if (f->f_choice == LDAP_FILTER_AND && f->f_and) {
404                 fextra = 2;
405                 f = f->f_and;
406         }
407         if (f->f_choice == LDAP_FILTER_EQUALITY &&
408                 f->f_av_desc == slap_schema.si_ad_objectClass) {
409                 struct berval bv = f->f_av_value;
410
411                 for (ad = ai->ai_dnv; ad; ad = ad->ad_next) {
412                         if (!ber_bvstrcasecmp( &bv, &ad->ad_mapgrp->soc_cname )) {
413                         /* Now check to see if next element is (<newattr>=foo) */
414                                 Filter *fnew;
415                                 if (fn && fn->f_choice == LDAP_FILTER_EQUALITY &&
416                                         fn->f_av_desc == ad->ad_newattr) {
417                                         Filter fr[3];
418                                         AttributeAssertion aa[2] = {0};
419                                         Operation op2;
420                                         slap_callback cb = {0};
421                                         SlapReply rs = {REP_RESULT};
422                                         struct berval dn = BER_BVNULL;
423
424                                         /* It's a match, setup a search with filter
425                                          * (&(objectclass=<refgrp>)(<deref>=foo))
426                                          */
427                                         fr[0].f_choice = LDAP_FILTER_AND;
428                                         fr[0].f_and = &fr[1];
429                                         fr[0].f_next = NULL;
430
431                                         fr[1].f_choice = LDAP_FILTER_EQUALITY;
432                                         fr[1].f_ava = &aa[0];
433                                         fr[1].f_av_desc = slap_schema.si_ad_objectClass;
434                                         fr[1].f_av_value = ad->ad_refgrp->soc_cname;
435                                         fr[1].f_next = &fr[2];
436
437                                         fr[2].f_choice = LDAP_FILTER_EQUALITY;
438                                         fr[2].f_ava = &aa[1];
439                                         fr[2].f_av_desc = ad->ad_deref;
440                                         fr[2].f_av_value = fn->f_av_value;
441                                         fr[2].f_next = NULL;
442
443                                         /* Search with this filter to retrieve target DN */
444                                         op2 = *op;
445                                         op2.o_callback = &cb;
446                                         cb.sc_response = adremap_refsearch;
447                                         cb.sc_private = &dn;
448                                         op2.o_req_dn = ad->ad_refbase;
449                                         op2.o_req_ndn = ad->ad_refbase;
450                                         op2.ors_filter = fr;
451                                         filter2bv_x(op, fr, &op2.ors_filterstr);
452                                         op2.ors_deref = LDAP_DEREF_NEVER;
453                                         op2.ors_slimit = 1;
454                                         op2.ors_tlimit = SLAP_NO_LIMIT;
455                                         op2.ors_attrs = slap_anlist_no_attrs;
456                                         op2.ors_attrsonly = 1;
457                                         op2.o_no_schema_check = 1;
458                                         op2.o_bd->bd_info = (BackendInfo *)on->on_info;
459                                         op2.o_bd->be_search(&op2, &rs);
460                                         op2.o_bd->bd_info = (BackendInfo *)on;
461                                         op->o_tmpfree(op2.ors_filterstr.bv_val, op->o_tmpmemctx);
462
463                                         if (!dn.bv_len) {       /* no match was found */
464                                                 ad = NULL;
465                                                 break;
466                                         }
467
468                                         if (rs.sr_err) {        /* sizelimit exceeded, etc.: invalid name */
469                                                 op->o_tmpfree(dn.bv_val, op->o_tmpmemctx);
470                                                 ad = NULL;
471                                                 break;
472                                         }
473
474                                         /* Build a new filter of form
475                                          * (&(objectclass=<group>)(<dnattr>=foo-DN)...)
476                                          */
477                                         f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx);
478                                         f->f_choice = LDAP_FILTER_AND;
479                                         fnew = f;
480                                         f->f_next = NULL;
481
482                                         f->f_and = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx);
483                                         f = f->f_and;
484                                         f->f_choice = LDAP_FILTER_EQUALITY;
485                                         f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx);
486                                         f->f_av_desc = slap_schema.si_ad_objectClass;
487                                         ber_dupbv_x(&f->f_av_value, &ad->ad_group->soc_cname, op->o_tmpmemctx);
488
489                                         f->f_next = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx);
490                                         f = f->f_next;
491                                         f->f_choice = LDAP_FILTER_EQUALITY;
492                                         f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx);
493                                         f->f_av_desc = ad->ad_dnattr;
494                                         f->f_av_value = dn;
495
496                                         f->f_next = fn->f_next;
497                                         fn->f_next = NULL;
498                                 } else {
499                                         /* Build a new filter of form
500                                          * (objectclass=<group>)
501                                          */
502                                         f->f_next = NULL;       /* disconnect old chain */
503
504                                         f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx);
505                                         f->f_choice = LDAP_FILTER_EQUALITY;
506                                         f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx);
507                                         f->f_av_desc = slap_schema.si_ad_objectClass;
508                                         ber_dupbv_x(&f->f_av_value, &ad->ad_group->soc_cname, op->o_tmpmemctx);
509
510                                         /* If there was a wrapping (&), attach it. */
511                                         if (fextra) {
512                                                 fnew = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx);
513                                                 fnew->f_choice = LDAP_FILTER_AND;
514                                                 fnew->f_and = f;
515                                                 fnew->f_next = NULL;
516                                                 f->f_next = fn;
517                                         } else {
518                                                 fnew = f;
519                                                 f->f_next = NULL;
520                                         }
521                                 }
522                                 if (fextra > 1) {
523                                         f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx);
524                                         f->f_choice = LDAP_FILTER_AND;
525                                         f->f_and = fnew->f_and;
526                                         f->f_next = f->f_and->f_next;
527                                         f->f_and->f_next = op->ors_filter->f_and->f_and->f_next;
528                                         op->ors_filter->f_and->f_and->f_next = NULL;
529                                         fnew->f_and = f;
530                                 }
531                                 filter_free_x(op, op->ors_filter, 1);
532                                 op->o_tmpfree(op->ors_filterstr.bv_val, op->o_tmpmemctx);
533                                 op->ors_filter = fnew;
534                                 filter2bv_x(op, op->ors_filter, &op->ors_filterstr);
535                                 break;
536                         }
537                 }
538         }
539         return ad;
540 }
541
542 static int
543 adremap_search(
544         Operation *op,
545         SlapReply *rs
546 )
547 {
548         slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
549         adremap_info *ai = (adremap_info *) on->on_bi.bi_private;
550         adremap_ctx *ctx;
551         adremap_dnv *ad = NULL;
552         slap_callback *cb;
553
554         /* Is this our own internal search? Ignore it */
555         if (op->o_no_schema_check)
556                 return SLAP_CB_CONTINUE;
557
558         if (ai->ai_dnv)
559                 /* check for filter match, fallthru if none */
560                 ad = adremap_filter(op, ai);
561
562         cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(adremap_ctx), op->o_tmpmemctx);
563         cb->sc_response = adremap_search_resp;
564         cb->sc_private = cb+1;
565         cb->sc_next = op->o_callback;
566         op->o_callback = cb;
567         ctx = cb->sc_private;
568         ctx->on = on;
569         if (ad && op->ors_attrs) {      /* see if we need to remap a search attr */
570                 int i;
571                 for (i=0; op->ors_attrs[i].an_name.bv_val; i++) {
572                         if (op->ors_attrs[i].an_desc == ad->ad_newattr) {
573                                 ctx->an_swap = 1;
574                                 ctx->ad = ad->ad_dnattr;
575                                 ctx->an = op->ors_attrs[i];
576                                 op->ors_attrs[i].an_desc = ad->ad_dnattr;
577                                 op->ors_attrs[i].an_name = ad->ad_dnattr->ad_cname;
578                                 break;
579                         }
580                 }
581         }
582         return SLAP_CB_CONTINUE;
583 }
584
585 static int
586 adremap_db_init(
587         BackendDB *be,
588         ConfigReply *cr
589 )
590 {
591         slap_overinst *on = (slap_overinst *) be->bd_info;
592
593         /* initialize private structure to store configuration */
594         on->on_bi.bi_private = ch_calloc( 1, sizeof(adremap_info) );
595
596         return 0;
597 }
598
599 static int
600 adremap_db_destroy(
601         BackendDB *be,
602         ConfigReply *cr
603 )
604 {
605         slap_overinst *on = (slap_overinst *) be->bd_info;
606         adremap_info *ai = (adremap_info *) on->on_bi.bi_private;
607         adremap_case *ac;
608         adremap_dnv *ad;
609
610         /* free config */
611         for (ac = ai->ai_case; ac; ac = ai->ai_case) {
612                 ai->ai_case = ac->ac_next;
613                 ch_free(ac);
614         }
615         for (ad = ai->ai_dnv; ad; ad = ai->ai_dnv) {
616                 ai->ai_dnv = ad->ad_next;
617                 ch_free(ad);
618         }
619         free( ai );
620
621         return 0;
622 }
623
624 static slap_overinst adremap;
625
626 int adremap_initialize()
627 {
628         int i, code;
629
630         adremap.on_bi.bi_type = "adremap";
631         adremap.on_bi.bi_db_init = adremap_db_init;
632         adremap.on_bi.bi_db_destroy = adremap_db_destroy;
633         adremap.on_bi.bi_op_search = adremap_search;
634
635         /* register configuration directives */
636         adremap.on_bi.bi_cf_ocs = adremapocs;
637         code = config_register_schema( adremapcfg, adremapocs );
638         if ( code ) return code;
639
640         return overlay_register( &adremap );
641 }
642
643 #if SLAPD_OVER_ADREMAP == SLAPD_MOD_DYNAMIC
644 int init_module(int argc, char *argv[]) {
645         return adremap_initialize();
646 }
647 #endif
648
649 #endif  /* defined(SLAPD_OVER_ADREMAP) */