adremap.c 17.4 KB
Newer Older
Howard Chu's avatar
Howard Chu committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/* adremap.c - Case-folding and DN-value remapping for AD proxies */
/* $OpenLDAP$ */
/*
 * Copyright 2015 Howard Chu <hyc@symas.com>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */

#include "portable.h"

/*
 * This file implements an overlay that performs two remapping functions
 * to allow older POSIX clients to use Microsoft AD:
 * 1: downcase the values of a configurable list of attributes
 * 2: dereference some DN-valued attributes and convert to their simple names
 *	   e.g. generate memberUid based on member
 */

#ifdef SLAPD_OVER_ADREMAP

#include <ldap.h>
#include "lutil.h"
#include "slap.h"
#include <ac/errno.h>
#include <ac/time.h>
#include <ac/string.h>
#include <ac/ctype.h>
#include "config.h"

typedef struct adremap_dnv {
	struct adremap_dnv *ad_next;
	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 */
Howard Chu's avatar
Howard Chu committed
42
43
44
45
	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 */
Howard Chu's avatar
Howard Chu committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
} adremap_dnv;
/* example: member uid memberUid */

typedef struct adremap_case {
	struct adremap_case *ac_next;
	AttributeDescription *ac_attr;
} adremap_case;

/* Per-instance configuration information */
typedef struct adremap_info {
	adremap_case *ai_case;	/* attrs to downcase */
	adremap_dnv *ai_dnv;	/* DN attrs to remap */
} adremap_info;

enum {
	ADREMAP_CASE = 1,
	ADREMAP_DNV
};

static ConfigDriver adremap_cf_case;
static ConfigDriver adremap_cf_dnv;

/* configuration attribute and objectclass */
static ConfigTable adremapcfg[] = {
	{ "adremap-downcase", "attrs", 2, 0, 0,
	  ARG_MAGIC|ADREMAP_CASE, adremap_cf_case,
	  "( OLcfgCtAt:6.1 "
	  "NAME 'olcADremapDowncase' "
	  "DESC 'List of attributes to casefold to lower case' "
75
	  "EQUALITY caseIgnoreMatch "
Howard Chu's avatar
Howard Chu committed
76
	  "SYNTAX OMsDirectoryString )", NULL, NULL },
Howard Chu's avatar
Howard Chu committed
77
	{ "adremap-dnmap", "dnattr targetattr newattr remoteOC localOC targetOC baseDN", 8, 8, 0,
Howard Chu's avatar
Howard Chu committed
78
79
80
	  ARG_MAGIC|ADREMAP_DNV, adremap_cf_dnv,
	  "( OLcfgCtAt:6.2 "
	  "NAME 'olcADremapDNmap' "
Howard Chu's avatar
Howard Chu committed
81
82
	  "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' "
83
	  "EQUALITY caseIgnoreMatch "
Howard Chu's avatar
Howard Chu committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
	  "SYNTAX OMsDirectoryString )", NULL, NULL },
	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
};

static ConfigOCs adremapocs[] = {
	{ "( OLcfgCtOc:6.1 "
	  "NAME 'olcADremapConfig' "
	  "DESC 'AD remap configuration' "
	  "SUP olcOverlayConfig "
	  "MAY ( olcADremapDowncase $ olcADremapDNmap ) )",
	  Cft_Overlay, adremapcfg, NULL, NULL },
	{ NULL, 0, NULL }
};

static int
adremap_cf_case(ConfigArgs *c)
{
	BackendDB *be = (BackendDB *)c->be;
	slap_overinst *on = (slap_overinst *)c->bi;
	adremap_info *ai = on->on_bi.bi_private;
	adremap_case *ac, **a2;
	int rc = ARG_BAD_CONF;

	switch(c->op) {
	case SLAP_CONFIG_EMIT:
		for (ac = ai->ai_case; ac; ac=ac->ac_next) {
			rc = value_add_one(&c->rvalue_vals, &ac->ac_attr->ad_cname);
			if (rc) break;
		}
		break;
	case LDAP_MOD_DELETE:
		if (c->valx < 0) {
			for (ac = ai->ai_case; ac; ac=ai->ai_case) {
				ai->ai_case = ac->ac_next;
				ch_free(ac);
			}
		} else {
			int i;
			for (i=0, a2 = &ai->ai_case; i<c->valx; i++, a2 = &(*a2)->ac_next);
			ac = *a2;
			*a2 = ac->ac_next;
			ch_free(ac);
		}
		rc = 0;
		break;
	default: {
		const char *text;
		adremap_case ad;
		ad.ac_attr = NULL;
		rc = slap_str2ad(c->argv[1], &ad.ac_attr, &text);
		if (rc) break;
		for (a2 = &ai->ai_case; *a2; a2 = &(*a2)->ac_next);
		ac = ch_malloc(sizeof(adremap_case));
		ac->ac_next = NULL;
		ac->ac_attr = ad.ac_attr;
		*a2 = ac;
		break;
		}
	}
	return rc;
}

static int
adremap_cf_dnv(ConfigArgs *c)
{
	BackendDB *be = (BackendDB *)c->be;
	slap_overinst *on = (slap_overinst *)c->bi;
	adremap_info *ai = on->on_bi.bi_private;
	adremap_dnv *ad, **a2;
	int rc = ARG_BAD_CONF;

	switch(c->op) {
	case SLAP_CONFIG_EMIT:
		for (ad = ai->ai_dnv; ad; ad=ad->ad_next) {
			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;
Howard Chu's avatar
Howard Chu committed
161
162
			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;
Howard Chu's avatar
Howard Chu committed
163
164
165
166
167
			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++ = ' ';
Howard Chu's avatar
Howard Chu committed
168
169
170
171
172
173
174
175
176
177
178
179
			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';
Howard Chu's avatar
Howard Chu committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
			ber_bvarray_add(&c->rvalue_vals, &bv);
		}
		if (ai->ai_dnv) rc = 0;
		break;
	case LDAP_MOD_DELETE:
		if (c->valx < 0) {
			for (ad = ai->ai_dnv; ad; ad=ai->ai_dnv) {
				ai->ai_dnv = ad->ad_next;
				ch_free(ad);
			}
		} else {
			int i;
			for (i=0, a2 = &ai->ai_dnv; i<c->valx; i++, a2 = &(*a2)->ad_next);
			ad = *a2;
			*a2 = ad->ad_next;
			ch_free(ad);
		}
		rc = 0;
		break;
	default: {
		const char *text;
		adremap_dnv av = {0};
Howard Chu's avatar
Howard Chu committed
202
		struct berval dn;
Howard Chu's avatar
Howard Chu committed
203
204
205
206
207
208
209
210
211
212
213
214
215
		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) {
			rc = 1;
			snprintf(c->cr_msg, sizeof(c->cr_msg), "<%s> not a DN-valued attribute",
				c->argv[0]);
			Debug(LDAP_DEBUG_ANY, "%s: %s(%s)\n", c->log, c->cr_msg, c->argv[1]);
			break;
		}
		rc = slap_str2ad(c->argv[2], &av.ad_deref, &text);
		if (rc) break;
		rc = slap_str2ad(c->argv[3], &av.ad_newattr, &text);
		if (rc) break;
Howard Chu's avatar
Howard Chu committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
		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;
Howard Chu's avatar
Howard Chu committed
234
235
236
237
238
239
240

		for (a2 = &ai->ai_dnv; *a2; a2 = &(*a2)->ad_next);
		ad = ch_malloc(sizeof(adremap_dnv));
		ad->ad_next = NULL;
		ad->ad_dnattr = av.ad_dnattr;
		ad->ad_deref = av.ad_deref;
		ad->ad_newattr = av.ad_newattr;
Howard Chu's avatar
Howard Chu committed
241
242
243
244
		ad->ad_group = av.ad_group;
		ad->ad_mapgrp = av.ad_mapgrp;
		ad->ad_refgrp = av.ad_refgrp;
		ad->ad_refbase = av.ad_refbase;
Howard Chu's avatar
Howard Chu committed
245
246
247
248
249
250
251
		*a2 = ad;
		break;
		}
	}
	return rc;
}

252
253
254
typedef struct adremap_ctx {
	slap_overinst *on;
	AttributeName an;
Howard Chu's avatar
Howard Chu committed
255
	AttributeDescription *ad;
256
257
258
	int an_swap;
} adremap_ctx;

Howard Chu's avatar
Howard Chu committed
259
260
261
262
263
264
static int
adremap_search_resp(
	Operation *op,
	SlapReply *rs
)
{
265
266
	adremap_ctx *ctx = op->o_callback->sc_private;
	slap_overinst *on = ctx->on;
Howard Chu's avatar
Howard Chu committed
267
268
269
270
271
272
273
274
275
	adremap_info *ai = on->on_bi.bi_private;
	adremap_case *ac;
	adremap_dnv *ad;
	Attribute *a;
	Entry *e;

	if (rs->sr_type != REP_SEARCH)
		return SLAP_CB_CONTINUE;

Howard Chu's avatar
Howard Chu committed
276
	/* we munged the attr list, restore it to original */
277
	if (ctx->an_swap) {
Howard Chu's avatar
Howard Chu committed
278
		int i;
279
		ctx->an_swap = 0;
Howard Chu's avatar
Howard Chu committed
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
		for (i=0; rs->sr_attrs[i].an_name.bv_val; i++) {
			if (rs->sr_attrs[i].an_desc == ctx->ad) {
				rs->sr_attrs[i] = ctx->an;
				break;
			}
		}
		/* Usually rs->sr_attrs is just op->ors_attrs, but
		 * overlays like rwm may make a new copy. Fix both
		 * if needed.
		 */
		if (op->ors_attrs != rs->sr_attrs) {
			for (i=0; op->ors_attrs[i].an_name.bv_val; i++) {
				if (op->ors_attrs[i].an_desc == ctx->ad) {
					op->ors_attrs[i] = ctx->an;
					break;
				}
			}
		}
298
	}
Howard Chu's avatar
Howard Chu committed
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
	e = rs->sr_entry;
	for (ac = ai->ai_case; ac; ac = ac->ac_next) {
		a = attr_find(e->e_attrs, ac->ac_attr);
		if (a) {
			int i, j;
			if (!(rs->sr_flags & REP_ENTRY_MODIFIABLE)) {
				e = entry_dup(e);
				rs_replace_entry(op, rs, on, e);
				rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED;
				a = attr_find(e->e_attrs, ac->ac_attr);
			}
			for (i=0; i<a->a_numvals; i++) {
				unsigned char *c = a->a_vals[i].bv_val;
				for (j=0; j<a->a_vals[i].bv_len; j++)
					if (isupper(c[j]))
						c[j] = tolower(c[j]);
			}
		}
	}
	for (ad = ai->ai_dnv; ad; ad = ad->ad_next) {
		a = attr_find(e->e_attrs, ad->ad_dnattr);
		if (a) {
			Entry *n;
			Attribute *dr;
			int i, rc;
			if (!(rs->sr_flags & REP_ENTRY_MODIFIABLE)) {
				e = entry_dup(e);
				rs_replace_entry(op, rs, on, e);
				rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED;
				a = attr_find(e->e_attrs, ad->ad_dnattr);
			}
			for (i=0; i<a->a_numvals; i++) {
Howard Chu's avatar
Howard Chu committed
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
				struct berval dv;
				dv = ad->ad_deref->ad_cname;
					/* If the RDN uses the deref attr, just use it directly */
				if (a->a_nvals[i].bv_val[dv.bv_len] == '=' &&
					!memcmp(a->a_nvals[i].bv_val, dv.bv_val, dv.bv_len)) {
					struct berval bv, nv;
					char *ptr;
					bv = a->a_vals[i];
					nv = a->a_nvals[i];
					bv.bv_val += dv.bv_len + 1;
					ptr = strchr(bv.bv_val, ',');
					if (ptr)
						bv.bv_len = ptr - bv.bv_val;
					else
						bv.bv_len -= dv.bv_len+1;
					nv.bv_val += dv.bv_len + 1;
					ptr = strchr(nv.bv_val, ',');
					if (ptr)
						nv.bv_len = ptr - nv.bv_val;
					else
						nv.bv_len -= dv.bv_len+1;
					attr_merge_one(e, ad->ad_newattr, &bv, &nv);
				} else {
					/* otherwise look up the deref attr */
					n = NULL;
					rc = be_entry_get_rw(op, &a->a_nvals[i], NULL, ad->ad_deref, 0, &n);
					if (!rc && n) {
						dr = attr_find(n->e_attrs, ad->ad_deref);
						if (dr)
							attr_merge_one(e, ad->ad_newattr, dr->a_vals, dr->a_nvals);
						be_entry_release_r(op, n);
					}
Howard Chu's avatar
Howard Chu committed
363
364
365
366
367
368
369
				}
			}
		}
	}
	return SLAP_CB_CONTINUE;
}

Howard Chu's avatar
Howard Chu committed
370
371
372
373
374
375
376
377
378
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);
Howard Chu's avatar
Howard Chu committed
379
		return LDAP_SUCCESS;
Howard Chu's avatar
Howard Chu committed
380
	}
Howard Chu's avatar
Howard Chu committed
381
	return rs->sr_err;
Howard Chu's avatar
Howard Chu committed
382
383
}

384
static adremap_dnv *adremap_filter(
Howard Chu's avatar
Howard Chu committed
385
386
387
388
389
	Operation *op,
	adremap_info *ai
)
{
	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
Howard Chu's avatar
Howard Chu committed
390
	Filter *f = op->ors_filter, *fn = NULL;
391
	adremap_dnv *ad = NULL;
Howard Chu's avatar
Howard Chu committed
392
	struct berval bv;
Howard Chu's avatar
Howard Chu committed
393
	int fextra = 0;
Howard Chu's avatar
Howard Chu committed
394
395

	/* Do we need to munge the filter? First see if it's of
Howard Chu's avatar
Howard Chu committed
396
397
	 * the form (objectClass=<mapgrp>)
	 * or form (&(objectClass=<mapgrp>)...)
Howard Chu's avatar
Howard Chu committed
398
	 * or form (&(&(objectClass=<mapgrp>)...)...)
Howard Chu's avatar
Howard Chu committed
399
	 */
Howard Chu's avatar
Howard Chu committed
400
	if (f->f_choice == LDAP_FILTER_AND && f->f_and) {
Howard Chu's avatar
Howard Chu committed
401
402
403
404
405
406
407
408
409
410
411
412
		fextra = 1;
		f = f->f_and;
		fn = f->f_next;
	}
	if (f->f_choice == LDAP_FILTER_AND && f->f_and) {
		fextra = 2;
		f = f->f_and;
	}
	if (f->f_choice == LDAP_FILTER_EQUALITY &&
		f->f_av_desc == slap_schema.si_ad_objectClass) {
		struct berval bv = f->f_av_value;

Howard Chu's avatar
Howard Chu committed
413
414
415
		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) */
Howard Chu's avatar
Howard Chu committed
416
				Filter *fnew;
Howard Chu's avatar
Howard Chu committed
417
418
				if (fn && fn->f_choice == LDAP_FILTER_EQUALITY &&
					fn->f_av_desc == ad->ad_newattr) {
Howard Chu's avatar
Howard Chu committed
419
					Filter fr[3];
Howard Chu's avatar
Howard Chu committed
420
					AttributeAssertion aa[2] = {0};
Howard Chu's avatar
Howard Chu committed
421
422
423
424
425
426
427
428
429
430
					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];
Howard Chu's avatar
Howard Chu committed
431
					fr[0].f_next = NULL;
Howard Chu's avatar
Howard Chu committed
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458

					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;
Howard Chu's avatar
Howard Chu committed
459
					op2.o_no_schema_check = 1;
Howard Chu's avatar
Howard Chu committed
460
461
462
463
464
					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);

465
466
467
468
					if (!dn.bv_len) {	/* no match was found */
						ad = NULL;
						break;
					}
Howard Chu's avatar
Howard Chu committed
469

Howard Chu's avatar
Howard Chu committed
470
471
					if (rs.sr_err) {	/* sizelimit exceeded, etc.: invalid name */
						op->o_tmpfree(dn.bv_val, op->o_tmpmemctx);
472
473
						ad = NULL;
						break;
Howard Chu's avatar
Howard Chu committed
474
475
					}

Howard Chu's avatar
Howard Chu committed
476
477
478
479
480
481
					/* 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;
Howard Chu's avatar
Howard Chu committed
482
					f->f_next = NULL;
Howard Chu's avatar
Howard Chu committed
483
484
485
486

					f->f_and = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx);
					f = f->f_and;
					f->f_choice = LDAP_FILTER_EQUALITY;
Howard Chu's avatar
Howard Chu committed
487
					f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx);
Howard Chu's avatar
Howard Chu committed
488
489
490
491
492
493
					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;
Howard Chu's avatar
Howard Chu committed
494
					f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx);
Howard Chu's avatar
Howard Chu committed
495
496
					f->f_av_desc = ad->ad_dnattr;
					f->f_av_value = dn;
Howard Chu's avatar
Howard Chu committed
497
498
499

					f->f_next = fn->f_next;
					fn->f_next = NULL;
Howard Chu's avatar
Howard Chu committed
500
501
				} else {
					/* Build a new filter of form
Howard Chu's avatar
Howard Chu committed
502
					 * (objectclass=<group>)
Howard Chu's avatar
Howard Chu committed
503
					 */
Howard Chu's avatar
Howard Chu committed
504
					f->f_next = NULL;	/* disconnect old chain */
Howard Chu's avatar
Howard Chu committed
505

Howard Chu's avatar
Howard Chu committed
506
					f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx);
Howard Chu's avatar
Howard Chu committed
507
508
509
510
					f->f_choice = LDAP_FILTER_EQUALITY;
					f->f_ava = op->o_tmpcalloc(1, 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);
Howard Chu's avatar
Howard Chu committed
511
512
513
514
515
516
517
518
519
520
521
522

					/* If there was a wrapping (&), attach it. */
					if (fextra) {
						fnew = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx);
						fnew->f_choice = LDAP_FILTER_AND;
						fnew->f_and = f;
						fnew->f_next = NULL;
						f->f_next = fn;
					} else {
						fnew = f;
						f->f_next = NULL;
					}
Howard Chu's avatar
Howard Chu committed
523
				}
Howard Chu's avatar
Howard Chu committed
524
				if (fextra > 1) {
Howard Chu's avatar
Howard Chu committed
525
526
527
528
529
530
531
532
533
534
535
536
537
					f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx);
					f->f_choice = LDAP_FILTER_AND;
					f->f_and = fnew->f_and;
					f->f_next = f->f_and->f_next;
					f->f_and->f_next = op->ors_filter->f_and->f_and->f_next;
					op->ors_filter->f_and->f_and->f_next = NULL;
					fnew->f_and = f;
				}
				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);
				break;
Howard Chu's avatar
Howard Chu committed
538
539
540
			}
		}
	}
541
	return ad;
Howard Chu's avatar
Howard Chu committed
542
543
}

Howard Chu's avatar
Howard Chu committed
544
545
546
547
548
549
550
static int
adremap_search(
	Operation *op,
	SlapReply *rs
)
{
	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
Howard Chu's avatar
Howard Chu committed
551
	adremap_info *ai = (adremap_info *) on->on_bi.bi_private;
552
553
	adremap_ctx *ctx;
	adremap_dnv *ad = NULL;
Howard Chu's avatar
Howard Chu committed
554
555
	slap_callback *cb;

Howard Chu's avatar
Howard Chu committed
556
557
558
559
	/* Is this our own internal search? Ignore it */
	if (op->o_no_schema_check)
		return SLAP_CB_CONTINUE;

560
	if (ai->ai_dnv)
Howard Chu's avatar
Howard Chu committed
561
		/* check for filter match, fallthru if none */
562
		ad = adremap_filter(op, ai);
563

564
	cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(adremap_ctx), op->o_tmpmemctx);
Howard Chu's avatar
Howard Chu committed
565
	cb->sc_response = adremap_search_resp;
566
	cb->sc_private = cb+1;
Howard Chu's avatar
Howard Chu committed
567
568
	cb->sc_next = op->o_callback;
	op->o_callback = cb;
569
570
	ctx = cb->sc_private;
	ctx->on = on;
Howard Chu's avatar
Howard Chu committed
571
	if (ad && op->ors_attrs) {	/* see if we need to remap a search attr */
572
573
574
575
		int i;
		for (i=0; op->ors_attrs[i].an_name.bv_val; i++) {
			if (op->ors_attrs[i].an_desc == ad->ad_newattr) {
				ctx->an_swap = 1;
Howard Chu's avatar
Howard Chu committed
576
				ctx->ad = ad->ad_dnattr;
577
578
579
580
581
582
583
				ctx->an = op->ors_attrs[i];
				op->ors_attrs[i].an_desc = ad->ad_dnattr;
				op->ors_attrs[i].an_name = ad->ad_dnattr->ad_cname;
				break;
			}
		}
	}
Howard Chu's avatar
Howard Chu committed
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
	return SLAP_CB_CONTINUE;
}

static int
adremap_db_init(
	BackendDB *be,
	ConfigReply *cr
)
{
	slap_overinst *on = (slap_overinst *) be->bd_info;

	/* initialize private structure to store configuration */
	on->on_bi.bi_private = ch_calloc( 1, sizeof(adremap_info) );

	return 0;
}

static int
adremap_db_destroy(
	BackendDB *be,
	ConfigReply *cr
)
{
	slap_overinst *on = (slap_overinst *) be->bd_info;
	adremap_info *ai = (adremap_info *) on->on_bi.bi_private;
	adremap_case *ac;
	adremap_dnv *ad;

	/* free config */
	for (ac = ai->ai_case; ac; ac = ai->ai_case) {
		ai->ai_case = ac->ac_next;
		ch_free(ac);
	}
	for (ad = ai->ai_dnv; ad; ad = ai->ai_dnv) {
		ai->ai_dnv = ad->ad_next;
		ch_free(ad);
	}
	free( ai );

	return 0;
}

static slap_overinst adremap;

int adremap_initialize()
{
	int i, code;

	adremap.on_bi.bi_type = "adremap";
633
	adremap.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
Howard Chu's avatar
Howard Chu committed
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
	adremap.on_bi.bi_db_init = adremap_db_init;
	adremap.on_bi.bi_db_destroy = adremap_db_destroy;
	adremap.on_bi.bi_op_search = adremap_search;

	/* register configuration directives */
	adremap.on_bi.bi_cf_ocs = adremapocs;
	code = config_register_schema( adremapcfg, adremapocs );
	if ( code ) return code;

	return overlay_register( &adremap );
}

#if SLAPD_OVER_ADREMAP == SLAPD_MOD_DYNAMIC
int init_module(int argc, char *argv[]) {
	return adremap_initialize();
}
#endif

#endif	/* defined(SLAPD_OVER_ADREMAP) */