xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/overlays/rwmmap.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: rwmmap.c,v 1.1.1.4 2014/05/28 09:58:52 tron Exp $	*/
2 
3 /* rwmmap.c - rewrite/mapping routines */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1999-2014 The OpenLDAP Foundation.
8  * Portions Copyright 1999-2003 Howard Chu.
9  * Portions Copyright 2000-2003 Pierangelo Masarati.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* ACKNOWLEDGEMENTS:
21  * This work was initially developed by the Howard Chu for inclusion
22  * in OpenLDAP Software and subsequently enhanced by Pierangelo
23  * Masarati.
24  */
25 
26 #include "portable.h"
27 
28 #ifdef SLAPD_OVER_RWM
29 
30 #include <stdio.h>
31 
32 #include <ac/string.h>
33 #include <ac/socket.h>
34 
35 #include "slap.h"
36 #include "rwm.h"
37 
38 #undef ldap_debug	/* silence a warning in ldap-int.h */
39 #include "../../../libraries/libldap/ldap-int.h"
40 
41 int
42 rwm_mapping_cmp( const void *c1, const void *c2 )
43 {
44 	struct ldapmapping *map1 = (struct ldapmapping *)c1;
45 	struct ldapmapping *map2 = (struct ldapmapping *)c2;
46 	int rc = map1->m_src.bv_len - map2->m_src.bv_len;
47 
48 	if ( rc ) {
49 		return rc;
50 	}
51 
52 	return strcasecmp( map1->m_src.bv_val, map2->m_src.bv_val );
53 }
54 
55 int
56 rwm_mapping_dup( void *c1, void *c2 )
57 {
58 	struct ldapmapping *map1 = (struct ldapmapping *)c1;
59 	struct ldapmapping *map2 = (struct ldapmapping *)c2;
60 	int rc = map1->m_src.bv_len - map2->m_src.bv_len;
61 
62 	if ( rc ) {
63 		return 0;
64 	}
65 
66 	return ( ( strcasecmp( map1->m_src.bv_val, map2->m_src.bv_val ) == 0 ) ? -1 : 0 );
67 }
68 
69 int
70 rwm_map_init( struct ldapmap *lm, struct ldapmapping **m )
71 {
72 	struct ldapmapping	*mapping;
73 	const char		*text;
74 	int			rc;
75 
76 	assert( m != NULL );
77 
78 	*m = NULL;
79 
80 	mapping = (struct ldapmapping *)ch_calloc( 2,
81 			sizeof( struct ldapmapping ) );
82 	if ( mapping == NULL ) {
83 		return LDAP_NO_MEMORY;
84 	}
85 
86 	/* NOTE: this is needed to make sure that
87 	 *	rwm-map attribute *
88 	 * does not  filter out all attributes including objectClass */
89 	rc = slap_str2ad( "objectClass", &mapping[0].m_src_ad, &text );
90 	if ( rc != LDAP_SUCCESS ) {
91 		ch_free( mapping );
92 		return rc;
93 	}
94 
95 	mapping[0].m_dst_ad = mapping[0].m_src_ad;
96 	ber_dupbv( &mapping[0].m_src, &mapping[0].m_src_ad->ad_cname );
97 	ber_dupbv( &mapping[0].m_dst, &mapping[0].m_src );
98 
99 	mapping[1].m_src = mapping[0].m_src;
100 	mapping[1].m_dst = mapping[0].m_dst;
101 	mapping[1].m_src_ad = mapping[0].m_src_ad;
102 	mapping[1].m_dst_ad = mapping[1].m_src_ad;
103 
104 	avl_insert( &lm->map, (caddr_t)&mapping[0],
105 			rwm_mapping_cmp, rwm_mapping_dup );
106 	avl_insert( &lm->remap, (caddr_t)&mapping[1],
107 			rwm_mapping_cmp, rwm_mapping_dup );
108 
109 	*m = mapping;
110 
111 	return rc;
112 }
113 
114 int
115 rwm_mapping( struct ldapmap *map, struct berval *s, struct ldapmapping **m, int remap )
116 {
117 	Avlnode *tree;
118 	struct ldapmapping fmapping;
119 
120 	if ( map == NULL ) {
121 		return 0;
122 	}
123 
124 	assert( m != NULL );
125 
126 	/* let special attrnames slip through (ITS#5760) */
127 	if ( bvmatch( s, slap_bv_no_attrs )
128 		|| bvmatch( s, slap_bv_all_user_attrs )
129 		|| bvmatch( s, slap_bv_all_operational_attrs ) )
130 	{
131 		*m = NULL;
132 		return 0;
133 	}
134 
135 	if ( remap == RWM_REMAP ) {
136 		tree = map->remap;
137 
138 	} else {
139 		tree = map->map;
140 	}
141 
142 	fmapping.m_src = *s;
143 	*m = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping,
144 			rwm_mapping_cmp );
145 
146 	if ( *m == NULL ) {
147 		return map->drop_missing;
148 	}
149 
150 	return 0;
151 }
152 
153 void
154 rwm_map( struct ldapmap *map, struct berval *s, struct berval *bv, int remap )
155 {
156 	struct ldapmapping *mapping;
157 
158 	/* map->map may be NULL when mapping is configured,
159 	 * but map->remap can't */
160 	if ( map->remap == NULL ) {
161 		*bv = *s;
162 		return;
163 	}
164 
165 	BER_BVZERO( bv );
166 	( void )rwm_mapping( map, s, &mapping, remap );
167 	if ( mapping != NULL ) {
168 		if ( !BER_BVISNULL( &mapping->m_dst ) ) {
169 			*bv = mapping->m_dst;
170 		}
171 		return;
172 	}
173 
174 	if ( !map->drop_missing ) {
175 		*bv = *s;
176 	}
177 }
178 
179 /*
180  * Map attribute names in place
181  */
182 int
183 rwm_map_attrnames(
184 	Operation	*op,
185 	struct ldapmap	*at_map,
186 	struct ldapmap	*oc_map,
187 	AttributeName	*an,
188 	AttributeName	**anp,
189 	int		remap )
190 {
191 	int		i, j, x;
192 
193 	assert( anp != NULL );
194 
195 	*anp = NULL;
196 
197 	if ( an == NULL && op->o_bd->be_extra_anlist == NULL ) {
198 		return LDAP_SUCCESS;
199 	}
200 
201 	i = 0;
202 	if ( an != NULL ) {
203 		for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ )
204 			/* just count */ ;
205 	}
206 
207 	x = 0;
208 	if ( op->o_bd->be_extra_anlist ) {
209 		for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ )
210 			/* just count */ ;
211 	}
212 
213 	assert( i > 0 || x > 0 );
214 	*anp = op->o_tmpcalloc( ( i + x + 1 ), sizeof( AttributeName ),
215 		op->o_tmpmemctx );
216 	if ( *anp == NULL ) {
217 		return LDAP_NO_MEMORY;
218 	}
219 
220 	for ( i = 0, j = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
221 		struct ldapmapping	*m;
222 		int			at_drop_missing = 0,
223 					oc_drop_missing = 0;
224 
225 		if ( an[i].an_desc ) {
226 			if ( !at_map ) {
227 				/* FIXME: better leave as is? */
228 				continue;
229 			}
230 
231 			at_drop_missing = rwm_mapping( at_map, &an[i].an_name, &m, remap );
232 			if ( at_drop_missing || ( m && BER_BVISNULL( &m->m_dst ) ) ) {
233 				continue;
234 			}
235 
236 			if ( !m ) {
237 				(*anp)[j] = an[i];
238 				j++;
239 				continue;
240 			}
241 
242 			(*anp)[j] = an[i];
243 			if ( remap == RWM_MAP ) {
244 				(*anp)[j].an_name = m->m_dst;
245 				(*anp)[j].an_desc = m->m_dst_ad;
246 			} else {
247 				(*anp)[j].an_name = m->m_src;
248 				(*anp)[j].an_desc = m->m_src_ad;
249 
250 			}
251 
252 			j++;
253 			continue;
254 
255 		} else if ( an[i].an_oc ) {
256 			if ( !oc_map ) {
257 				/* FIXME: better leave as is? */
258 				continue;
259 			}
260 
261 			oc_drop_missing = rwm_mapping( oc_map, &an[i].an_name, &m, remap );
262 
263 			if ( oc_drop_missing || ( m && BER_BVISNULL( &m->m_dst ) ) ) {
264 				continue;
265 			}
266 
267 			if ( !m ) {
268 				(*anp)[j] = an[i];
269 				j++;
270 				continue;
271 			}
272 
273 			(*anp)[j] = an[i];
274 			if ( remap == RWM_MAP ) {
275 				(*anp)[j].an_name = m->m_dst;
276 				(*anp)[j].an_oc = m->m_dst_oc;
277 			} else {
278 				(*anp)[j].an_name = m->m_src;
279 				(*anp)[j].an_oc = m->m_src_oc;
280 			}
281 
282 		} else {
283 			at_drop_missing = rwm_mapping( at_map, &an[i].an_name, &m, remap );
284 
285 			if ( at_drop_missing || !m ) {
286 				oc_drop_missing = rwm_mapping( oc_map, &an[i].an_name, &m, remap );
287 
288 				/* if both at_map and oc_map required to drop missing,
289 				 * then do it */
290 				if ( oc_drop_missing && at_drop_missing ) {
291 					continue;
292 				}
293 
294 				/* if no oc_map mapping was found and at_map required
295 				 * to drop missing, then do it; otherwise, at_map wins
296 				 * and an is considered an attr and is left unchanged */
297 				if ( !m ) {
298 					if ( at_drop_missing ) {
299 						continue;
300 					}
301 					(*anp)[j] = an[i];
302 					j++;
303 					continue;
304 				}
305 
306 				if ( BER_BVISNULL( &m->m_dst ) ) {
307 					continue;
308 				}
309 
310 				(*anp)[j] = an[i];
311 				if ( remap == RWM_MAP ) {
312 					(*anp)[j].an_name = m->m_dst;
313 					(*anp)[j].an_oc = m->m_dst_oc;
314 				} else {
315 					(*anp)[j].an_name = m->m_src;
316 					(*anp)[j].an_oc = m->m_src_oc;
317 				}
318 				j++;
319 				continue;
320 			}
321 
322 			if ( !BER_BVISNULL( &m->m_dst ) ) {
323 				(*anp)[j] = an[i];
324 				if ( remap == RWM_MAP ) {
325 					(*anp)[j].an_name = m->m_dst;
326 					(*anp)[j].an_desc = m->m_dst_ad;
327 				} else {
328 					(*anp)[j].an_name = m->m_src;
329 					(*anp)[j].an_desc = m->m_src_ad;
330 				}
331 				j++;
332 				continue;
333 			}
334 		}
335 	}
336 
337 	if ( op->o_bd->be_extra_anlist != NULL ) {
338 		/* we assume be_extra_anlist are already mapped */
339 		for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) {
340 			BER_BVZERO( &(*anp)[j].an_name );
341 			if ( op->o_bd->be_extra_anlist[x].an_desc &&
342 				ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, *anp ) )
343 			{
344 				continue;
345 			}
346 
347 			(*anp)[j] = op->o_bd->be_extra_anlist[x];
348 			j++;
349 		}
350 	}
351 
352 	if ( j == 0 && ( i != 0 || x != 0 ) ) {
353 		memset( &(*anp)[0], 0, sizeof( AttributeName ) );
354 		(*anp)[0].an_name = *slap_bv_no_attrs;
355 		j = 1;
356 	}
357 	memset( &(*anp)[j], 0, sizeof( AttributeName ) );
358 
359 	return LDAP_SUCCESS;
360 }
361 
362 #if 0 /* unused! */
363 int
364 rwm_map_attrs(
365 	struct ldapmap	*at_map,
366 	AttributeName	*an,
367 	int		remap,
368 	char		***mapped_attrs )
369 {
370 	int i, j;
371 	char **na;
372 
373 	if ( an == NULL ) {
374 		*mapped_attrs = NULL;
375 		return LDAP_SUCCESS;
376 	}
377 
378 	for ( i = 0; !BER_BVISNULL( &an[ i ].an_name ); i++ )
379 		/* count'em */ ;
380 
381 	na = (char **)ch_calloc( i + 1, sizeof( char * ) );
382 	if ( na == NULL ) {
383 		*mapped_attrs = NULL;
384 		return LDAP_NO_MEMORY;
385 	}
386 
387 	for ( i = j = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
388 		struct ldapmapping	*mapping;
389 
390 		if ( rwm_mapping( at_map, &an[i].an_name, &mapping, remap ) ) {
391 			continue;
392 		}
393 
394 		if ( !mapping ) {
395 			na[ j++ ] = an[ i ].an_name.bv_val;
396 
397 		} else if ( !BER_BVISNULL( &mapping->m_dst ) ) {
398 			na[ j++ ] = mapping->m_dst.bv_val;
399 		}
400 	}
401 
402 	if ( j == 0 && i != 0 ) {
403 		na[ j++ ] = LDAP_NO_ATTRS;
404 	}
405 
406 	na[ j ] = NULL;
407 
408 	*mapped_attrs = na;
409 
410 	return LDAP_SUCCESS;
411 }
412 #endif
413 
414 static int
415 map_attr_value(
416 	dncookie		*dc,
417 	AttributeDescription 	**adp,
418 	struct berval		*mapped_attr,
419 	struct berval		*value,
420 	struct berval		*mapped_value,
421 	int			remap,
422 	void			*memctx )
423 {
424 	struct berval		vtmp = BER_BVNULL;
425 	int			freeval = 0;
426 	AttributeDescription	*ad = *adp;
427 	struct ldapmapping	*mapping = NULL;
428 
429 	rwm_mapping( &dc->rwmap->rwm_at, &ad->ad_cname, &mapping, remap );
430 	if ( mapping == NULL ) {
431 		if ( dc->rwmap->rwm_at.drop_missing ) {
432 			return -1;
433 		}
434 
435 		*mapped_attr = ad->ad_cname;
436 
437 	} else {
438 		*mapped_attr = mapping->m_dst;
439 	}
440 
441 	if ( value != NULL ) {
442 		assert( mapped_value != NULL );
443 
444 		if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
445 				|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
446 		{
447 			dncookie 	fdc = *dc;
448 			int		rc;
449 
450 			fdc.ctx = "searchFilterAttrDN";
451 
452 			vtmp = *value;
453 			rc = rwm_dn_massage_normalize( &fdc, value, &vtmp );
454 			switch ( rc ) {
455 			case LDAP_SUCCESS:
456 				if ( vtmp.bv_val != value->bv_val ) {
457 					freeval = 1;
458 				}
459 				break;
460 
461 			case LDAP_UNWILLING_TO_PERFORM:
462 			case LDAP_OTHER:
463 			default:
464 				return -1;
465 			}
466 
467 		} else if ( ad->ad_type->sat_equality &&
468 			( ad->ad_type->sat_equality->smr_usage & SLAP_MR_MUTATION_NORMALIZER ) )
469 		{
470 			if ( ad->ad_type->sat_equality->smr_normalize(
471 				(SLAP_MR_DENORMALIZE|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX),
472 				NULL, NULL, value, &vtmp, memctx ) )
473 			{
474 				return -1;
475 			}
476 			freeval = 2;
477 
478 		} else if ( ad == slap_schema.si_ad_objectClass
479 				|| ad == slap_schema.si_ad_structuralObjectClass )
480 		{
481 			rwm_map( &dc->rwmap->rwm_oc, value, &vtmp, remap );
482 			if ( BER_BVISNULL( &vtmp ) || BER_BVISEMPTY( &vtmp ) ) {
483 				vtmp = *value;
484 			}
485 
486 		} else {
487 			vtmp = *value;
488 		}
489 
490 		filter_escape_value_x( &vtmp, mapped_value, memctx );
491 
492 		switch ( freeval ) {
493 		case 1:
494 			ch_free( vtmp.bv_val );
495 			break;
496 
497 		case 2:
498 			ber_memfree_x( vtmp.bv_val, memctx );
499 			break;
500 		}
501 	}
502 
503 	if ( mapping != NULL ) {
504 		assert( mapping->m_dst_ad != NULL );
505 		*adp = mapping->m_dst_ad;
506 	}
507 
508 	return 0;
509 }
510 
511 static int
512 rwm_int_filter_map_rewrite(
513 	Operation		*op,
514 	dncookie		*dc,
515 	Filter			*f,
516 	struct berval		*fstr )
517 {
518 	int		i;
519 	Filter		*p;
520 	AttributeDescription *ad;
521 	struct berval	atmp,
522 			vtmp,
523 			*tmp;
524 	static struct berval
525 			/* better than nothing... */
526 			ber_bvfalse = BER_BVC( "(!(objectClass=*))" ),
527 			ber_bvtf_false = BER_BVC( "(|)" ),
528 			/* better than nothing... */
529 			ber_bvtrue = BER_BVC( "(objectClass=*)" ),
530 			ber_bvtf_true = BER_BVC( "(&)" ),
531 #if 0
532 			/* no longer needed; preserved for completeness */
533 			ber_bvundefined = BER_BVC( "(?=undefined)" ),
534 #endif
535 			ber_bverror = BER_BVC( "(?=error)" ),
536 			ber_bvunknown = BER_BVC( "(?=unknown)" ),
537 			ber_bvnone = BER_BVC( "(?=none)" );
538 	ber_len_t	len;
539 
540 	assert( fstr != NULL );
541 	BER_BVZERO( fstr );
542 
543 	if ( f == NULL ) {
544 		ber_dupbv_x( fstr, &ber_bvnone, op->o_tmpmemctx );
545 		return LDAP_OTHER;
546 	}
547 
548 #if 0
549 	/* ITS#6814: give the caller a chance to use undefined filters */
550 	if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
551 		goto computed;
552 	}
553 #endif
554 
555 	switch ( f->f_choice & SLAPD_FILTER_MASK ) {
556 	case LDAP_FILTER_EQUALITY:
557 		ad = f->f_av_desc;
558 		if ( map_attr_value( dc, &ad, &atmp,
559 			&f->f_av_value, &vtmp, RWM_MAP, op->o_tmpmemctx ) )
560 		{
561 			goto computed;
562 		}
563 
564 		fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(=)" );
565 		fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
566 
567 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
568 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
569 
570 		op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
571 		break;
572 
573 	case LDAP_FILTER_GE:
574 		ad = f->f_av_desc;
575 		if ( map_attr_value( dc, &ad, &atmp,
576 			&f->f_av_value, &vtmp, RWM_MAP, op->o_tmpmemctx ) )
577 		{
578 			goto computed;
579 		}
580 
581 		fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(>=)" );
582 		fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
583 
584 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
585 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
586 
587 		op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
588 		break;
589 
590 	case LDAP_FILTER_LE:
591 		ad = f->f_av_desc;
592 		if ( map_attr_value( dc, &ad, &atmp,
593 			&f->f_av_value, &vtmp, RWM_MAP, op->o_tmpmemctx ) )
594 		{
595 			goto computed;
596 		}
597 
598 		fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(<=)" );
599 		fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
600 
601 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
602 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
603 
604 		op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
605 		break;
606 
607 	case LDAP_FILTER_APPROX:
608 		ad = f->f_av_desc;
609 		if ( map_attr_value( dc, &ad, &atmp,
610 			&f->f_av_value, &vtmp, RWM_MAP, op->o_tmpmemctx ) )
611 		{
612 			goto computed;
613 		}
614 
615 		fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(~=)" );
616 		fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
617 
618 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
619 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
620 
621 		op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
622 		break;
623 
624 	case LDAP_FILTER_SUBSTRINGS:
625 		ad = f->f_sub_desc;
626 		if ( map_attr_value( dc, &ad, &atmp,
627 			NULL, NULL, RWM_MAP, op->o_tmpmemctx ) )
628 		{
629 			goto computed;
630 		}
631 
632 		/* cannot be a DN ... */
633 
634 		fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" );
635 		fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 128, op->o_tmpmemctx );
636 
637 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
638 			atmp.bv_val );
639 
640 		if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
641 			len = fstr->bv_len;
642 
643 			filter_escape_value_x( &f->f_sub_initial, &vtmp, op->o_tmpmemctx );
644 
645 			fstr->bv_len += vtmp.bv_len;
646 			fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1,
647 				op->o_tmpmemctx );
648 
649 			snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3,
650 				/* "(attr=" */ "%s*)",
651 				vtmp.bv_len ? vtmp.bv_val : "" );
652 
653 			op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
654 		}
655 
656 		if ( f->f_sub_any != NULL ) {
657 			for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
658 				len = fstr->bv_len;
659 				filter_escape_value_x( &f->f_sub_any[i], &vtmp,
660 					op->o_tmpmemctx );
661 
662 				fstr->bv_len += vtmp.bv_len + 1;
663 				fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1,
664 					op->o_tmpmemctx );
665 
666 				snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
667 					/* "(attr=[init]*[any*]" */ "%s*)",
668 					vtmp.bv_len ? vtmp.bv_val : "" );
669 				op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
670 			}
671 		}
672 
673 		if ( !BER_BVISNULL( &f->f_sub_final ) ) {
674 			len = fstr->bv_len;
675 
676 			filter_escape_value_x( &f->f_sub_final, &vtmp, op->o_tmpmemctx );
677 
678 			fstr->bv_len += vtmp.bv_len;
679 			fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1,
680 				op->o_tmpmemctx );
681 
682 			snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
683 				/* "(attr=[init*][any*]" */ "%s)",
684 				vtmp.bv_len ? vtmp.bv_val : "" );
685 
686 			op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
687 		}
688 
689 		break;
690 
691 	case LDAP_FILTER_PRESENT:
692 		ad = f->f_desc;
693 		if ( map_attr_value( dc, &ad, &atmp,
694 			NULL, NULL, RWM_MAP, op->o_tmpmemctx ) )
695 		{
696 			goto computed;
697 		}
698 
699 		fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" );
700 		fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
701 
702 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
703 			atmp.bv_val );
704 		break;
705 
706 	case LDAP_FILTER_AND:
707 	case LDAP_FILTER_OR:
708 	case LDAP_FILTER_NOT:
709 		fstr->bv_len = STRLENOF( "(%)" );
710 		fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 128, op->o_tmpmemctx );
711 
712 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
713 			f->f_choice == LDAP_FILTER_AND ? '&' :
714 			f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
715 
716 		for ( p = f->f_list; p != NULL; p = p->f_next ) {
717 			int	rc;
718 
719 			len = fstr->bv_len;
720 
721 			rc = rwm_int_filter_map_rewrite( op, dc, p, &vtmp );
722 			if ( rc != LDAP_SUCCESS ) {
723 				return rc;
724 			}
725 
726 			fstr->bv_len += vtmp.bv_len;
727 			fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1,
728 				op->o_tmpmemctx );
729 
730 			snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2,
731 				/*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" );
732 
733 			op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
734 		}
735 
736 		break;
737 
738 	case LDAP_FILTER_EXT: {
739 		if ( f->f_mr_desc ) {
740 			ad = f->f_mr_desc;
741 			if ( map_attr_value( dc, &ad, &atmp,
742 				&f->f_mr_value, &vtmp, RWM_MAP, op->o_tmpmemctx ) )
743 			{
744 				goto computed;
745 			}
746 
747 		} else {
748 			BER_BVSTR( &atmp, "" );
749 			filter_escape_value_x( &f->f_mr_value, &vtmp, op->o_tmpmemctx );
750 		}
751 
752 
753 		fstr->bv_len = atmp.bv_len +
754 			( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
755 			( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
756 			vtmp.bv_len + STRLENOF( "(:=)" );
757 		fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
758 
759 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
760 			atmp.bv_val,
761 			f->f_mr_dnattrs ? ":dn" : "",
762 			!BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
763 			!BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
764 			vtmp.bv_len ? vtmp.bv_val : "" );
765 		op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
766 		break;
767 	}
768 
769 	case -1:
770 computed:;
771 		filter_free_x( op, f, 0 );
772 		f->f_choice = SLAPD_FILTER_COMPUTED;
773 		f->f_result = SLAPD_COMPARE_UNDEFINED;
774 		/* fallthru */
775 
776 	case SLAPD_FILTER_COMPUTED:
777 		switch ( f->f_result ) {
778 		case LDAP_COMPARE_FALSE:
779 		/* FIXME: treat UNDEFINED as FALSE */
780 		case SLAPD_COMPARE_UNDEFINED:
781 			if ( dc->rwmap->rwm_flags & RWM_F_SUPPORT_T_F ) {
782 				tmp = &ber_bvtf_false;
783 				break;
784 			}
785 			tmp = &ber_bvfalse;
786 			break;
787 
788 		case LDAP_COMPARE_TRUE:
789 			if ( dc->rwmap->rwm_flags & RWM_F_SUPPORT_T_F ) {
790 				tmp = &ber_bvtf_true;
791 				break;
792 			}
793 			tmp = &ber_bvtrue;
794 			break;
795 
796 		default:
797 			tmp = &ber_bverror;
798 			break;
799 		}
800 
801 		ber_dupbv_x( fstr, tmp, op->o_tmpmemctx );
802 		break;
803 
804 	default:
805 		ber_dupbv_x( fstr, &ber_bvunknown, op->o_tmpmemctx );
806 		break;
807 	}
808 
809 	return LDAP_SUCCESS;
810 }
811 
812 int
813 rwm_filter_map_rewrite(
814 	Operation		*op,
815 	dncookie		*dc,
816 	Filter			*f,
817 	struct berval		*fstr )
818 {
819 	int		rc;
820 	dncookie 	fdc;
821 	struct berval	ftmp;
822 
823 	rc = rwm_int_filter_map_rewrite( op, dc, f, fstr );
824 
825 	if ( rc != 0 ) {
826 		return rc;
827 	}
828 
829 	fdc = *dc;
830 	ftmp = *fstr;
831 
832 	fdc.ctx = "searchFilter";
833 
834 	switch ( rewrite_session( fdc.rwmap->rwm_rw, fdc.ctx,
835 				( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : "" ),
836 				fdc.conn, &fstr->bv_val ) )
837 	{
838 	case REWRITE_REGEXEC_OK:
839 		if ( !BER_BVISNULL( fstr ) ) {
840 			fstr->bv_len = strlen( fstr->bv_val );
841 
842 		} else {
843 			*fstr = ftmp;
844 		}
845 
846 		Debug( LDAP_DEBUG_ARGS,
847 			"[rw] %s: \"%s\" -> \"%s\"\n",
848 			fdc.ctx, ftmp.bv_val, fstr->bv_val );
849 		if ( fstr->bv_val != ftmp.bv_val ) {
850 			ber_bvreplace_x( &ftmp, fstr, op->o_tmpmemctx );
851 			ch_free( fstr->bv_val );
852 			*fstr = ftmp;
853 		}
854 		rc = LDAP_SUCCESS;
855 		break;
856 
857  	case REWRITE_REGEXEC_UNWILLING:
858 		if ( fdc.rs ) {
859 			fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
860 			fdc.rs->sr_text = "Operation not allowed";
861 		}
862 		op->o_tmpfree( ftmp.bv_val, op->o_tmpmemctx );
863 		rc = LDAP_UNWILLING_TO_PERFORM;
864 		break;
865 
866 	case REWRITE_REGEXEC_ERR:
867 		if ( fdc.rs ) {
868 			fdc.rs->sr_err = LDAP_OTHER;
869 			fdc.rs->sr_text = "Rewrite error";
870 		}
871 		op->o_tmpfree( ftmp.bv_val, op->o_tmpmemctx );
872 		rc = LDAP_OTHER;
873 		break;
874 	}
875 
876 	return rc;
877 }
878 
879 /*
880  * I don't like this much, but we need two different
881  * functions because different heap managers may be
882  * in use in back-ldap/meta to reduce the amount of
883  * calls to malloc routines, and some of the free()
884  * routines may be macros with args
885  */
886 int
887 rwm_referral_rewrite(
888 	Operation		*op,
889 	SlapReply		*rs,
890 	void			*cookie,
891 	BerVarray		a_vals,
892 	BerVarray		*pa_nvals )
893 {
894 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
895 	struct ldaprwmap	*rwmap =
896 			(struct ldaprwmap *)on->on_bi.bi_private;
897 
898 	int			i, last;
899 
900 	dncookie		dc;
901 	struct berval		dn = BER_BVNULL,
902 				ndn = BER_BVNULL;
903 
904 	assert( a_vals != NULL );
905 
906 	/*
907 	 * Rewrite the dn if needed
908 	 */
909 	dc.rwmap = rwmap;
910 	dc.conn = op->o_conn;
911 	dc.rs = rs;
912 	dc.ctx = (char *)cookie;
913 
914 	for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
915 		;
916 	last--;
917 
918 	if ( pa_nvals != NULL ) {
919 		if ( *pa_nvals == NULL ) {
920 			*pa_nvals = ch_malloc( ( last + 2 ) * sizeof(struct berval) );
921 			memset( *pa_nvals, 0, ( last + 2 ) * sizeof(struct berval) );
922 		}
923 	}
924 
925 	for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
926 		struct berval	olddn = BER_BVNULL,
927 				oldval;
928 		int		rc;
929 		LDAPURLDesc	*ludp;
930 
931 		oldval = a_vals[i];
932 		rc = ldap_url_parse( oldval.bv_val, &ludp );
933 		if ( rc != LDAP_URL_SUCCESS ) {
934 			/* leave attr untouched if massage failed */
935 			if ( pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
936 				ber_dupbv( &(*pa_nvals)[i], &oldval );
937 			}
938 			continue;
939 		}
940 
941 		/* FIXME: URLs like "ldap:///dc=suffix" if passed
942 		 * thru ldap_url_parse() and ldap_url_desc2str()
943 		 * get rewritten as "ldap:///dc=suffix??base";
944 		 * we don't want this to occur... */
945 		if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
946 			ludp->lud_scope = LDAP_SCOPE_DEFAULT;
947 		}
948 
949 		ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
950 
951 		dn = olddn;
952 		if ( pa_nvals ) {
953 			ndn = olddn;
954 			rc = rwm_dn_massage_pretty_normalize( &dc, &olddn,
955 					&dn, &ndn );
956 		} else {
957 			rc = rwm_dn_massage_pretty( &dc, &olddn, &dn );
958 		}
959 
960 		switch ( rc ) {
961 		case LDAP_UNWILLING_TO_PERFORM:
962 			/*
963 			 * FIXME: need to check if it may be considered
964 			 * legal to trim values when adding/modifying;
965 			 * it should be when searching (e.g. ACLs).
966 			 */
967 			ch_free( a_vals[i].bv_val );
968 			if (last > i ) {
969 				a_vals[i] = a_vals[last];
970 				if ( pa_nvals ) {
971 					(*pa_nvals)[i] = (*pa_nvals)[last];
972 				}
973 			}
974 			BER_BVZERO( &a_vals[last] );
975 			if ( pa_nvals ) {
976 				BER_BVZERO( &(*pa_nvals)[last] );
977 			}
978 			last--;
979 			break;
980 
981 		case LDAP_SUCCESS:
982 			if ( !BER_BVISNULL( &dn ) && dn.bv_val != olddn.bv_val ) {
983 				char	*newurl;
984 
985 				ludp->lud_dn = dn.bv_val;
986 				newurl = ldap_url_desc2str( ludp );
987 				ludp->lud_dn = olddn.bv_val;
988 				ch_free( dn.bv_val );
989 				if ( newurl == NULL ) {
990 					/* FIXME: leave attr untouched
991 					 * even if ldap_url_desc2str failed...
992 					 */
993 					break;
994 				}
995 
996 				ber_str2bv( newurl, 0, 1, &a_vals[i] );
997 				ber_memfree( newurl );
998 
999 				if ( pa_nvals ) {
1000 					ludp->lud_dn = ndn.bv_val;
1001 					newurl = ldap_url_desc2str( ludp );
1002 					ludp->lud_dn = olddn.bv_val;
1003 					ch_free( ndn.bv_val );
1004 					if ( newurl == NULL ) {
1005 						/* FIXME: leave attr untouched
1006 						 * even if ldap_url_desc2str failed...
1007 						 */
1008 						ch_free( a_vals[i].bv_val );
1009 						a_vals[i] = oldval;
1010 						break;
1011 					}
1012 
1013 					if ( !BER_BVISNULL( &(*pa_nvals)[i] ) ) {
1014 						ch_free( (*pa_nvals)[i].bv_val );
1015 					}
1016 					ber_str2bv( newurl, 0, 1, &(*pa_nvals)[i] );
1017 					ber_memfree( newurl );
1018 				}
1019 
1020 				ch_free( oldval.bv_val );
1021 				ludp->lud_dn = olddn.bv_val;
1022 			}
1023 			break;
1024 
1025 		default:
1026 			/* leave attr untouched if massage failed */
1027 			if ( pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
1028 				ber_dupbv( &(*pa_nvals)[i], &a_vals[i] );
1029 			}
1030 			break;
1031 		}
1032 		ldap_free_urldesc( ludp );
1033 	}
1034 
1035 	return 0;
1036 }
1037 
1038 /*
1039  * I don't like this much, but we need two different
1040  * functions because different heap managers may be
1041  * in use in back-ldap/meta to reduce the amount of
1042  * calls to malloc routines, and some of the free()
1043  * routines may be macros with args
1044  */
1045 int
1046 rwm_dnattr_rewrite(
1047 	Operation		*op,
1048 	SlapReply		*rs,
1049 	void			*cookie,
1050 	BerVarray		a_vals,
1051 	BerVarray		*pa_nvals )
1052 {
1053 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
1054 	struct ldaprwmap	*rwmap =
1055 			(struct ldaprwmap *)on->on_bi.bi_private;
1056 
1057 	int			i, last;
1058 
1059 	dncookie		dc;
1060 	struct berval		dn = BER_BVNULL,
1061 				ndn = BER_BVNULL;
1062 	BerVarray		in;
1063 
1064 	if ( a_vals ) {
1065 		in = a_vals;
1066 
1067 	} else {
1068 		if ( pa_nvals == NULL || *pa_nvals == NULL ) {
1069 			return LDAP_OTHER;
1070 		}
1071 		in = *pa_nvals;
1072 	}
1073 
1074 	/*
1075 	 * Rewrite the dn if needed
1076 	 */
1077 	dc.rwmap = rwmap;
1078 	dc.conn = op->o_conn;
1079 	dc.rs = rs;
1080 	dc.ctx = (char *)cookie;
1081 
1082 	for ( last = 0; !BER_BVISNULL( &in[last] ); last++ );
1083 	last--;
1084 	if ( pa_nvals != NULL ) {
1085 		if ( *pa_nvals == NULL ) {
1086 			*pa_nvals = ch_malloc( ( last + 2 ) * sizeof(struct berval) );
1087 			memset( *pa_nvals, 0, ( last + 2 ) * sizeof(struct berval) );
1088 		}
1089 	}
1090 
1091 	for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
1092 		int		rc;
1093 
1094 		if ( a_vals ) {
1095 			dn = in[i];
1096 			if ( pa_nvals ) {
1097 				ndn = (*pa_nvals)[i];
1098 				rc = rwm_dn_massage_pretty_normalize( &dc, &in[i], &dn, &ndn );
1099 			} else {
1100 				rc = rwm_dn_massage_pretty( &dc, &in[i], &dn );
1101 			}
1102 		} else {
1103 			ndn = in[i];
1104 			rc = rwm_dn_massage_normalize( &dc, &in[i], &ndn );
1105 		}
1106 
1107 		switch ( rc ) {
1108 		case LDAP_UNWILLING_TO_PERFORM:
1109 			/*
1110 			 * FIXME: need to check if it may be considered
1111 			 * legal to trim values when adding/modifying;
1112 			 * it should be when searching (e.g. ACLs).
1113 			 */
1114 			ch_free( in[i].bv_val );
1115 			if (last > i ) {
1116 				in[i] = in[last];
1117 				if ( a_vals && pa_nvals ) {
1118 					(*pa_nvals)[i] = (*pa_nvals)[last];
1119 				}
1120 			}
1121 			BER_BVZERO( &in[last] );
1122 			if ( a_vals && pa_nvals ) {
1123 				BER_BVZERO( &(*pa_nvals)[last] );
1124 			}
1125 			last--;
1126 			break;
1127 
1128 		case LDAP_SUCCESS:
1129 			if ( a_vals ) {
1130 				if ( !BER_BVISNULL( &dn ) && dn.bv_val != a_vals[i].bv_val ) {
1131 					ch_free( a_vals[i].bv_val );
1132 					a_vals[i] = dn;
1133 
1134 					if ( pa_nvals ) {
1135 						if ( !BER_BVISNULL( &(*pa_nvals)[i] ) ) {
1136 							ch_free( (*pa_nvals)[i].bv_val );
1137 						}
1138 						(*pa_nvals)[i] = ndn;
1139 					}
1140 				}
1141 
1142 			} else {
1143 				if ( !BER_BVISNULL( &ndn ) && ndn.bv_val != (*pa_nvals)[i].bv_val ) {
1144 					ch_free( (*pa_nvals)[i].bv_val );
1145 					(*pa_nvals)[i] = ndn;
1146 				}
1147 			}
1148 			break;
1149 
1150 		default:
1151 			/* leave attr untouched if massage failed */
1152 			if ( a_vals && pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
1153 				dnNormalize( 0, NULL, NULL, &a_vals[i], &(*pa_nvals)[i], NULL );
1154 			}
1155 			break;
1156 		}
1157 	}
1158 
1159 	return 0;
1160 }
1161 
1162 int
1163 rwm_referral_result_rewrite(
1164 	dncookie		*dc,
1165 	BerVarray		a_vals )
1166 {
1167 	int		i, last;
1168 
1169 	for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ );
1170 	last--;
1171 
1172 	for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
1173 		struct berval	dn,
1174 				olddn = BER_BVNULL;
1175 		int		rc;
1176 		LDAPURLDesc	*ludp;
1177 
1178 		rc = ldap_url_parse( a_vals[i].bv_val, &ludp );
1179 		if ( rc != LDAP_URL_SUCCESS ) {
1180 			/* leave attr untouched if massage failed */
1181 			continue;
1182 		}
1183 
1184 		/* FIXME: URLs like "ldap:///dc=suffix" if passed
1185 		 * thru ldap_url_parse() and ldap_url_desc2str()
1186 		 * get rewritten as "ldap:///dc=suffix??base";
1187 		 * we don't want this to occur... */
1188 		if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
1189 			ludp->lud_scope = LDAP_SCOPE_DEFAULT;
1190 		}
1191 
1192 		ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
1193 
1194 		dn = olddn;
1195 		rc = rwm_dn_massage_pretty( dc, &olddn, &dn );
1196 		switch ( rc ) {
1197 		case LDAP_UNWILLING_TO_PERFORM:
1198 			/*
1199 			 * FIXME: need to check if it may be considered
1200 			 * legal to trim values when adding/modifying;
1201 			 * it should be when searching (e.g. ACLs).
1202 			 */
1203 			ch_free( a_vals[i].bv_val );
1204 			if ( last > i ) {
1205 				a_vals[i] = a_vals[last];
1206 			}
1207 			BER_BVZERO( &a_vals[last] );
1208 			last--;
1209 			i--;
1210 			break;
1211 
1212 		default:
1213 			/* leave attr untouched if massage failed */
1214 			if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val ) {
1215 				char	*newurl;
1216 
1217 				ludp->lud_dn = dn.bv_val;
1218 				newurl = ldap_url_desc2str( ludp );
1219 				if ( newurl == NULL ) {
1220 					/* FIXME: leave attr untouched
1221 					 * even if ldap_url_desc2str failed...
1222 					 */
1223 					break;
1224 				}
1225 
1226 				ch_free( a_vals[i].bv_val );
1227 				ber_str2bv( newurl, 0, 1, &a_vals[i] );
1228 				ber_memfree( newurl );
1229 				ludp->lud_dn = olddn.bv_val;
1230 			}
1231 			break;
1232 		}
1233 
1234 		ldap_free_urldesc( ludp );
1235 	}
1236 
1237 	return 0;
1238 }
1239 
1240 int
1241 rwm_dnattr_result_rewrite(
1242 	dncookie		*dc,
1243 	BerVarray		a_vals,
1244 	BerVarray		a_nvals )
1245 {
1246 	int		i, last;
1247 
1248 	for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ );
1249 	last--;
1250 
1251 	for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
1252 		struct berval	pdn, ndn = BER_BVNULL;
1253 		int		rc;
1254 
1255 		pdn = a_vals[i];
1256 		rc = rwm_dn_massage_pretty_normalize( dc, &a_vals[i], &pdn, &ndn );
1257 		switch ( rc ) {
1258 		case LDAP_UNWILLING_TO_PERFORM:
1259 			/*
1260 			 * FIXME: need to check if it may be considered
1261 			 * legal to trim values when adding/modifying;
1262 			 * it should be when searching (e.g. ACLs).
1263 			 */
1264 			assert( a_vals[i].bv_val != a_nvals[i].bv_val );
1265 			ch_free( a_vals[i].bv_val );
1266 			ch_free( a_nvals[i].bv_val );
1267 			if ( last > i ) {
1268 				a_vals[i] = a_vals[last];
1269 				a_nvals[i] = a_nvals[last];
1270 			}
1271 			BER_BVZERO( &a_vals[last] );
1272 			BER_BVZERO( &a_nvals[last] );
1273 			last--;
1274 			break;
1275 
1276 		default:
1277 			/* leave attr untouched if massage failed */
1278 			if ( !BER_BVISNULL( &pdn ) && a_vals[i].bv_val != pdn.bv_val ) {
1279 				ch_free( a_vals[i].bv_val );
1280 				a_vals[i] = pdn;
1281 			}
1282 			if ( !BER_BVISNULL( &ndn ) && a_nvals[i].bv_val != ndn.bv_val ) {
1283 				ch_free( a_nvals[i].bv_val );
1284 				a_nvals[i] = ndn;
1285 			}
1286 			break;
1287 		}
1288 	}
1289 
1290 	return 0;
1291 }
1292 
1293 void
1294 rwm_mapping_dst_free( void *v_mapping )
1295 {
1296 	struct ldapmapping *mapping = v_mapping;
1297 
1298 	if ( BER_BVISEMPTY( &mapping[0].m_dst ) ) {
1299 		rwm_mapping_free( &mapping[ -1 ] );
1300 	}
1301 }
1302 
1303 void
1304 rwm_mapping_free( void *v_mapping )
1305 {
1306 	struct ldapmapping *mapping = v_mapping;
1307 
1308 	if ( !BER_BVISNULL( &mapping[0].m_src ) ) {
1309 		ch_free( mapping[0].m_src.bv_val );
1310 	}
1311 
1312 	if ( mapping[0].m_flags & RWMMAP_F_FREE_SRC ) {
1313 		if ( mapping[0].m_flags & RWMMAP_F_IS_OC ) {
1314 			if ( mapping[0].m_src_oc ) {
1315 				ch_free( mapping[0].m_src_oc );
1316 			}
1317 
1318 		} else {
1319 			if ( mapping[0].m_src_ad ) {
1320 				ch_free( mapping[0].m_src_ad );
1321 			}
1322 		}
1323 	}
1324 
1325 	if ( !BER_BVISNULL( &mapping[0].m_dst ) ) {
1326 		ch_free( mapping[0].m_dst.bv_val );
1327 	}
1328 
1329 	if ( mapping[0].m_flags & RWMMAP_F_FREE_DST ) {
1330 		if ( mapping[0].m_flags & RWMMAP_F_IS_OC ) {
1331 			if ( mapping[0].m_dst_oc ) {
1332 				ch_free( mapping[0].m_dst_oc );
1333 			}
1334 
1335 		} else {
1336 			if ( mapping[0].m_dst_ad ) {
1337 				ch_free( mapping[0].m_dst_ad );
1338 			}
1339 		}
1340 	}
1341 
1342 	ch_free( mapping );
1343 
1344 }
1345 
1346 #endif /* SLAPD_OVER_RWM */
1347