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