Home | History | Annotate | Line # | Download | only in overlays
rwmmap.c revision 1.1.1.2
      1 /*	$NetBSD: rwmmap.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
      2 
      3 /* rwmmap.c - rewrite/mapping routines */
      4 /* OpenLDAP: pkg/ldap/servers/slapd/overlays/rwmmap.c,v 1.31.2.12 2009/02/17 19:14:42 quanah Exp */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1999-2009 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 	struct ldapmap	*at_map,
    185 	struct ldapmap	*oc_map,
    186 	AttributeName	*an,
    187 	AttributeName	**anp,
    188 	int		remap )
    189 {
    190 	int		i, j;
    191 
    192 	assert( anp != NULL );
    193 
    194 	*anp = NULL;
    195 
    196 	if ( an == NULL ) {
    197 		return LDAP_SUCCESS;
    198 	}
    199 
    200 	for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ )
    201 		/* just count */ ;
    202 	*anp = ch_malloc( ( i + 1 )* sizeof( AttributeName ) );
    203 	if ( *anp == NULL ) {
    204 		return LDAP_NO_MEMORY;
    205 	}
    206 
    207 	for ( i = 0, j = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
    208 		struct ldapmapping	*m;
    209 		int			at_drop_missing = 0,
    210 					oc_drop_missing = 0;
    211 
    212 		if ( an[i].an_desc ) {
    213 			if ( !at_map ) {
    214 				/* FIXME: better leave as is? */
    215 				continue;
    216 			}
    217 
    218 			at_drop_missing = rwm_mapping( at_map, &an[i].an_name, &m, remap );
    219 			if ( at_drop_missing || ( m && BER_BVISNULL( &m->m_dst ) ) ) {
    220 				continue;
    221 			}
    222 
    223 			if ( !m ) {
    224 				(*anp)[j] = an[i];
    225 				j++;
    226 				continue;
    227 			}
    228 
    229 			(*anp)[j] = an[i];
    230 			if ( remap == RWM_MAP ) {
    231 				(*anp)[j].an_name = m->m_dst;
    232 				(*anp)[j].an_desc = m->m_dst_ad;
    233 			} else {
    234 				(*anp)[j].an_name = m->m_src;
    235 				(*anp)[j].an_desc = m->m_src_ad;
    236 
    237 			}
    238 
    239 			j++;
    240 			continue;
    241 
    242 		} else if ( an[i].an_oc ) {
    243 			if ( !oc_map ) {
    244 				/* FIXME: better leave as is? */
    245 				continue;
    246 			}
    247 
    248 			oc_drop_missing = rwm_mapping( oc_map, &an[i].an_name, &m, remap );
    249 
    250 			if ( oc_drop_missing || ( m && BER_BVISNULL( &m->m_dst ) ) ) {
    251 				continue;
    252 			}
    253 
    254 			if ( !m ) {
    255 				(*anp)[j] = an[i];
    256 				j++;
    257 				continue;
    258 			}
    259 
    260 			(*anp)[j] = an[i];
    261 			if ( remap == RWM_MAP ) {
    262 				(*anp)[j].an_name = m->m_dst;
    263 				(*anp)[j].an_oc = m->m_dst_oc;
    264 			} else {
    265 				(*anp)[j].an_name = m->m_src;
    266 				(*anp)[j].an_oc = m->m_src_oc;
    267 			}
    268 
    269 		} else {
    270 			at_drop_missing = rwm_mapping( at_map, &an[i].an_name, &m, remap );
    271 
    272 			if ( at_drop_missing || !m ) {
    273 				oc_drop_missing = rwm_mapping( oc_map, &an[i].an_name, &m, remap );
    274 
    275 				/* if both at_map and oc_map required to drop missing,
    276 				 * then do it */
    277 				if ( oc_drop_missing && at_drop_missing ) {
    278 					continue;
    279 				}
    280 
    281 				/* if no oc_map mapping was found and at_map required
    282 				 * to drop missing, then do it; otherwise, at_map wins
    283 				 * and an is considered an attr and is left unchanged */
    284 				if ( !m ) {
    285 					if ( at_drop_missing ) {
    286 						continue;
    287 					}
    288 					(*anp)[j] = an[i];
    289 					j++;
    290 					continue;
    291 				}
    292 
    293 				if ( BER_BVISNULL( &m->m_dst ) ) {
    294 					continue;
    295 				}
    296 
    297 				(*anp)[j] = an[i];
    298 				if ( remap == RWM_MAP ) {
    299 					(*anp)[j].an_name = m->m_dst;
    300 					(*anp)[j].an_oc = m->m_dst_oc;
    301 				} else {
    302 					(*anp)[j].an_name = m->m_src;
    303 					(*anp)[j].an_oc = m->m_src_oc;
    304 				}
    305 				j++;
    306 				continue;
    307 			}
    308 
    309 			if ( !BER_BVISNULL( &m->m_dst ) ) {
    310 				(*anp)[j] = an[i];
    311 				if ( remap == RWM_MAP ) {
    312 					(*anp)[j].an_name = m->m_dst;
    313 					(*anp)[j].an_desc = m->m_dst_ad;
    314 				} else {
    315 					(*anp)[j].an_name = m->m_src;
    316 					(*anp)[j].an_desc = m->m_src_ad;
    317 				}
    318 				j++;
    319 				continue;
    320 			}
    321 		}
    322 	}
    323 
    324 	if ( j == 0 && i != 0 ) {
    325 		memset( &(*anp)[0], 0, sizeof( AttributeName ) );
    326 		(*anp)[0].an_name = *slap_bv_no_attrs;
    327 		j = 1;
    328 	}
    329 	memset( &(*anp)[j], 0, sizeof( AttributeName ) );
    330 
    331 	return LDAP_SUCCESS;
    332 }
    333 
    334 int
    335 rwm_map_attrs(
    336 	struct ldapmap	*at_map,
    337 	AttributeName	*an,
    338 	int		remap,
    339 	char		***mapped_attrs )
    340 {
    341 	int i, j;
    342 	char **na;
    343 
    344 	if ( an == NULL ) {
    345 		*mapped_attrs = NULL;
    346 		return LDAP_SUCCESS;
    347 	}
    348 
    349 	for ( i = 0; !BER_BVISNULL( &an[ i ].an_name ); i++ )
    350 		/* count'em */ ;
    351 
    352 	na = (char **)ch_calloc( i + 1, sizeof( char * ) );
    353 	if ( na == NULL ) {
    354 		*mapped_attrs = NULL;
    355 		return LDAP_NO_MEMORY;
    356 	}
    357 
    358 	for ( i = j = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
    359 		struct ldapmapping	*mapping;
    360 
    361 		if ( rwm_mapping( at_map, &an[i].an_name, &mapping, remap ) ) {
    362 			continue;
    363 		}
    364 
    365 		if ( !mapping ) {
    366 			na[ j++ ] = an[ i ].an_name.bv_val;
    367 
    368 		} else if ( !BER_BVISNULL( &mapping->m_dst ) ) {
    369 			na[ j++ ] = mapping->m_dst.bv_val;
    370 		}
    371 	}
    372 
    373 	if ( j == 0 && i != 0 ) {
    374 		na[ j++ ] = LDAP_NO_ATTRS;
    375 	}
    376 
    377 	na[ j ] = NULL;
    378 
    379 	*mapped_attrs = na;
    380 
    381 	return LDAP_SUCCESS;
    382 }
    383 
    384 static int
    385 map_attr_value(
    386 	dncookie		*dc,
    387 	AttributeDescription 	**adp,
    388 	struct berval		*mapped_attr,
    389 	struct berval		*value,
    390 	struct berval		*mapped_value,
    391 	int			remap )
    392 {
    393 	struct berval		vtmp = BER_BVNULL;
    394 	int			freeval = 0;
    395 	AttributeDescription	*ad = *adp;
    396 	struct ldapmapping	*mapping = NULL;
    397 
    398 	rwm_mapping( &dc->rwmap->rwm_at, &ad->ad_cname, &mapping, remap );
    399 	if ( mapping == NULL ) {
    400 		if ( dc->rwmap->rwm_at.drop_missing ) {
    401 			return -1;
    402 		}
    403 
    404 		*mapped_attr = ad->ad_cname;
    405 
    406 	} else {
    407 		*mapped_attr = mapping->m_dst;
    408 	}
    409 
    410 	if ( value != NULL ) {
    411 		assert( mapped_value != NULL );
    412 
    413 		if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
    414 				|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
    415 		{
    416 			dncookie 	fdc = *dc;
    417 			int		rc;
    418 
    419 			fdc.ctx = "searchFilterAttrDN";
    420 
    421 			vtmp = *value;
    422 			rc = rwm_dn_massage_normalize( &fdc, value, &vtmp );
    423 			switch ( rc ) {
    424 			case LDAP_SUCCESS:
    425 				if ( vtmp.bv_val != value->bv_val ) {
    426 					freeval = 1;
    427 				}
    428 				break;
    429 
    430 			case LDAP_UNWILLING_TO_PERFORM:
    431 			case LDAP_OTHER:
    432 			default:
    433 				return -1;
    434 			}
    435 
    436 		} else if ( ad->ad_type->sat_equality->smr_usage & SLAP_MR_MUTATION_NORMALIZER ) {
    437 			if ( ad->ad_type->sat_equality->smr_normalize(
    438 				(SLAP_MR_DENORMALIZE|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX),
    439 				NULL, NULL, value, &vtmp, NULL ) )
    440 			{
    441 				return -1;
    442 			}
    443 			freeval = 1;
    444 
    445 		} else if ( ad == slap_schema.si_ad_objectClass
    446 				|| ad == slap_schema.si_ad_structuralObjectClass )
    447 		{
    448 			rwm_map( &dc->rwmap->rwm_oc, value, &vtmp, remap );
    449 			if ( BER_BVISNULL( &vtmp ) || BER_BVISEMPTY( &vtmp ) ) {
    450 				vtmp = *value;
    451 			}
    452 
    453 		} else {
    454 			vtmp = *value;
    455 		}
    456 
    457 		filter_escape_value( &vtmp, mapped_value );
    458 
    459 		if ( freeval ) {
    460 			ch_free( vtmp.bv_val );
    461 		}
    462 	}
    463 
    464 	if ( mapping != NULL ) {
    465 		assert( mapping->m_dst_ad != NULL );
    466 		*adp = mapping->m_dst_ad;
    467 	}
    468 
    469 	return 0;
    470 }
    471 
    472 static int
    473 rwm_int_filter_map_rewrite(
    474 	Operation		*op,
    475 	dncookie		*dc,
    476 	Filter			*f,
    477 	struct berval		*fstr )
    478 {
    479 	int		i;
    480 	Filter		*p;
    481 	AttributeDescription *ad;
    482 	struct berval	atmp,
    483 			vtmp,
    484 			*tmp;
    485 	static struct berval
    486 			/* better than nothing... */
    487 			ber_bvfalse = BER_BVC( "(!(objectClass=*))" ),
    488 			ber_bvtf_false = BER_BVC( "(|)" ),
    489 			/* better than nothing... */
    490 			ber_bvtrue = BER_BVC( "(objectClass=*)" ),
    491 			ber_bvtf_true = BER_BVC( "(&)" ),
    492 #if 0
    493 			/* no longer needed; preserved for completeness */
    494 			ber_bvundefined = BER_BVC( "(?=undefined)" ),
    495 #endif
    496 			ber_bverror = BER_BVC( "(?=error)" ),
    497 			ber_bvunknown = BER_BVC( "(?=unknown)" ),
    498 			ber_bvnone = BER_BVC( "(?=none)" );
    499 	ber_len_t	len;
    500 
    501 	assert( fstr != NULL );
    502 	BER_BVZERO( fstr );
    503 
    504 	if ( f == NULL ) {
    505 		ber_dupbv( fstr, &ber_bvnone );
    506 		return LDAP_OTHER;
    507 	}
    508 
    509 	if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
    510 		goto computed;
    511 	}
    512 
    513 	switch ( f->f_choice & SLAPD_FILTER_MASK ) {
    514 	case LDAP_FILTER_EQUALITY:
    515 		ad = f->f_av_desc;
    516 		if ( map_attr_value( dc, &ad, &atmp,
    517 					&f->f_av_value, &vtmp, RWM_MAP ) )
    518 		{
    519 			goto computed;
    520 		}
    521 
    522 		fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(=)" );
    523 		fstr->bv_val = ch_malloc( fstr->bv_len + 1 );
    524 
    525 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
    526 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
    527 
    528 		ch_free( vtmp.bv_val );
    529 		break;
    530 
    531 	case LDAP_FILTER_GE:
    532 		ad = f->f_av_desc;
    533 		if ( map_attr_value( dc, &ad, &atmp,
    534 					&f->f_av_value, &vtmp, RWM_MAP ) )
    535 		{
    536 			goto computed;
    537 		}
    538 
    539 		fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(>=)" );
    540 		fstr->bv_val = ch_malloc( fstr->bv_len + 1 );
    541 
    542 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
    543 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
    544 
    545 		ch_free( vtmp.bv_val );
    546 		break;
    547 
    548 	case LDAP_FILTER_LE:
    549 		ad = f->f_av_desc;
    550 		if ( map_attr_value( dc, &ad, &atmp,
    551 					&f->f_av_value, &vtmp, RWM_MAP ) )
    552 		{
    553 			goto computed;
    554 		}
    555 
    556 		fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(<=)" );
    557 		fstr->bv_val = ch_malloc( fstr->bv_len + 1 );
    558 
    559 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
    560 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
    561 
    562 		ch_free( vtmp.bv_val );
    563 		break;
    564 
    565 	case LDAP_FILTER_APPROX:
    566 		ad = f->f_av_desc;
    567 		if ( map_attr_value( dc, &ad, &atmp,
    568 					&f->f_av_value, &vtmp, RWM_MAP ) )
    569 		{
    570 			goto computed;
    571 		}
    572 
    573 		fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(~=)" );
    574 		fstr->bv_val = ch_malloc( fstr->bv_len + 1 );
    575 
    576 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
    577 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
    578 
    579 		ch_free( vtmp.bv_val );
    580 		break;
    581 
    582 	case LDAP_FILTER_SUBSTRINGS:
    583 		ad = f->f_sub_desc;
    584 		if ( map_attr_value( dc, &ad, &atmp,
    585 					NULL, NULL, RWM_MAP ) )
    586 		{
    587 			goto computed;
    588 		}
    589 
    590 		/* cannot be a DN ... */
    591 
    592 		fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" );
    593 		fstr->bv_val = ch_malloc( fstr->bv_len + 128 );
    594 
    595 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
    596 			atmp.bv_val );
    597 
    598 		if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
    599 			len = fstr->bv_len;
    600 
    601 			filter_escape_value( &f->f_sub_initial, &vtmp );
    602 
    603 			fstr->bv_len += vtmp.bv_len;
    604 			fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
    605 
    606 			snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3,
    607 				/* "(attr=" */ "%s*)",
    608 				vtmp.bv_len ? vtmp.bv_val : "" );
    609 
    610 			ch_free( vtmp.bv_val );
    611 		}
    612 
    613 		if ( f->f_sub_any != NULL ) {
    614 			for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
    615 				len = fstr->bv_len;
    616 				filter_escape_value( &f->f_sub_any[i], &vtmp );
    617 
    618 				fstr->bv_len += vtmp.bv_len + 1;
    619 				fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
    620 
    621 				snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
    622 					/* "(attr=[init]*[any*]" */ "%s*)",
    623 					vtmp.bv_len ? vtmp.bv_val : "" );
    624 				ch_free( vtmp.bv_val );
    625 			}
    626 		}
    627 
    628 		if ( !BER_BVISNULL( &f->f_sub_final ) ) {
    629 			len = fstr->bv_len;
    630 
    631 			filter_escape_value( &f->f_sub_final, &vtmp );
    632 
    633 			fstr->bv_len += vtmp.bv_len;
    634 			fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
    635 
    636 			snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
    637 				/* "(attr=[init*][any*]" */ "%s)",
    638 				vtmp.bv_len ? vtmp.bv_val : "" );
    639 
    640 			ch_free( vtmp.bv_val );
    641 		}
    642 
    643 		break;
    644 
    645 	case LDAP_FILTER_PRESENT:
    646 		ad = f->f_desc;
    647 		if ( map_attr_value( dc, &ad, &atmp,
    648 					NULL, NULL, RWM_MAP ) )
    649 		{
    650 			goto computed;
    651 		}
    652 
    653 		fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" );
    654 		fstr->bv_val = ch_malloc( fstr->bv_len + 1 );
    655 
    656 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
    657 			atmp.bv_val );
    658 		break;
    659 
    660 	case LDAP_FILTER_AND:
    661 	case LDAP_FILTER_OR:
    662 	case LDAP_FILTER_NOT:
    663 		fstr->bv_len = STRLENOF( "(%)" );
    664 		fstr->bv_val = ch_malloc( fstr->bv_len + 128 );
    665 
    666 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
    667 			f->f_choice == LDAP_FILTER_AND ? '&' :
    668 			f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
    669 
    670 		for ( p = f->f_list; p != NULL; p = p->f_next ) {
    671 			int	rc;
    672 
    673 			len = fstr->bv_len;
    674 
    675 			rc = rwm_int_filter_map_rewrite( op, dc, p, &vtmp );
    676 			if ( rc != LDAP_SUCCESS ) {
    677 				return rc;
    678 			}
    679 
    680 			fstr->bv_len += vtmp.bv_len;
    681 			fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
    682 
    683 			snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2,
    684 				/*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" );
    685 
    686 			ch_free( vtmp.bv_val );
    687 		}
    688 
    689 		break;
    690 
    691 	case LDAP_FILTER_EXT: {
    692 		if ( f->f_mr_desc ) {
    693 			ad = f->f_mr_desc;
    694 			if ( map_attr_value( dc, &ad, &atmp,
    695 						&f->f_mr_value, &vtmp, RWM_MAP ) )
    696 			{
    697 				goto computed;
    698 			}
    699 
    700 		} else {
    701 			BER_BVSTR( &atmp, "" );
    702 			filter_escape_value( &f->f_mr_value, &vtmp );
    703 		}
    704 
    705 
    706 		fstr->bv_len = atmp.bv_len +
    707 			( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
    708 			( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
    709 			vtmp.bv_len + STRLENOF( "(:=)" );
    710 		fstr->bv_val = ch_malloc( fstr->bv_len + 1 );
    711 
    712 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
    713 			atmp.bv_val,
    714 			f->f_mr_dnattrs ? ":dn" : "",
    715 			!BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
    716 			!BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
    717 			vtmp.bv_len ? vtmp.bv_val : "" );
    718 		ch_free( vtmp.bv_val );
    719 		break;
    720 	}
    721 
    722 	case -1:
    723 computed:;
    724 		filter_free_x( op, f, 0 );
    725 		f->f_choice = SLAPD_FILTER_COMPUTED;
    726 		f->f_result = SLAPD_COMPARE_UNDEFINED;
    727 		/* fallthru */
    728 
    729 	case SLAPD_FILTER_COMPUTED:
    730 		switch ( f->f_result ) {
    731 		case LDAP_COMPARE_FALSE:
    732 		/* FIXME: treat UNDEFINED as FALSE */
    733 		case SLAPD_COMPARE_UNDEFINED:
    734 			if ( dc->rwmap->rwm_flags & RWM_F_SUPPORT_T_F ) {
    735 				tmp = &ber_bvtf_false;
    736 				break;
    737 			}
    738 			tmp = &ber_bvfalse;
    739 			break;
    740 
    741 		case LDAP_COMPARE_TRUE:
    742 			if ( dc->rwmap->rwm_flags & RWM_F_SUPPORT_T_F ) {
    743 				tmp = &ber_bvtf_true;
    744 				break;
    745 			}
    746 			tmp = &ber_bvtrue;
    747 			break;
    748 
    749 		default:
    750 			tmp = &ber_bverror;
    751 			break;
    752 		}
    753 
    754 		ber_dupbv( fstr, tmp );
    755 		break;
    756 
    757 	default:
    758 		ber_dupbv( fstr, &ber_bvunknown );
    759 		break;
    760 	}
    761 
    762 	return LDAP_SUCCESS;
    763 }
    764 
    765 int
    766 rwm_filter_map_rewrite(
    767 	Operation		*op,
    768 	dncookie		*dc,
    769 	Filter			*f,
    770 	struct berval		*fstr )
    771 {
    772 	int		rc;
    773 	dncookie 	fdc;
    774 	struct berval	ftmp;
    775 
    776 	rc = rwm_int_filter_map_rewrite( op, dc, f, fstr );
    777 
    778 	if ( rc != 0 ) {
    779 		return rc;
    780 	}
    781 
    782 	fdc = *dc;
    783 	ftmp = *fstr;
    784 
    785 	fdc.ctx = "searchFilter";
    786 
    787 	switch ( rewrite_session( fdc.rwmap->rwm_rw, fdc.ctx,
    788 				( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : "" ),
    789 				fdc.conn, &fstr->bv_val ) )
    790 	{
    791 	case REWRITE_REGEXEC_OK:
    792 		if ( !BER_BVISNULL( fstr ) ) {
    793 			fstr->bv_len = strlen( fstr->bv_val );
    794 			if ( fstr->bv_val != ftmp.bv_val ) {
    795 				ch_free( ftmp.bv_val );
    796 			}
    797 
    798 		} else {
    799 			*fstr = ftmp;
    800 		}
    801 
    802 		Debug( LDAP_DEBUG_ARGS,
    803 			"[rw] %s: \"%s\" -> \"%s\"\n",
    804 			fdc.ctx, ftmp.bv_val, fstr->bv_val );
    805 		rc = LDAP_SUCCESS;
    806 		break;
    807 
    808  	case REWRITE_REGEXEC_UNWILLING:
    809 		if ( fdc.rs ) {
    810 			fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
    811 			fdc.rs->sr_text = "Operation not allowed";
    812 		}
    813 		rc = LDAP_UNWILLING_TO_PERFORM;
    814 		break;
    815 
    816 	case REWRITE_REGEXEC_ERR:
    817 		if ( fdc.rs ) {
    818 			fdc.rs->sr_err = LDAP_OTHER;
    819 			fdc.rs->sr_text = "Rewrite error";
    820 		}
    821 		rc = LDAP_OTHER;
    822 		break;
    823 	}
    824 
    825 	return rc;
    826 }
    827 
    828 /*
    829  * I don't like this much, but we need two different
    830  * functions because different heap managers may be
    831  * in use in back-ldap/meta to reduce the amount of
    832  * calls to malloc routines, and some of the free()
    833  * routines may be macros with args
    834  */
    835 int
    836 rwm_referral_rewrite(
    837 	Operation		*op,
    838 	SlapReply		*rs,
    839 	void			*cookie,
    840 	BerVarray		a_vals,
    841 	BerVarray		*pa_nvals )
    842 {
    843 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    844 	struct ldaprwmap	*rwmap =
    845 			(struct ldaprwmap *)on->on_bi.bi_private;
    846 
    847 	int			i, last;
    848 
    849 	dncookie		dc;
    850 	struct berval		dn = BER_BVNULL,
    851 				ndn = BER_BVNULL;
    852 
    853 	assert( a_vals != NULL );
    854 
    855 	/*
    856 	 * Rewrite the dn if needed
    857 	 */
    858 	dc.rwmap = rwmap;
    859 	dc.conn = op->o_conn;
    860 	dc.rs = rs;
    861 	dc.ctx = (char *)cookie;
    862 
    863 	for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
    864 		;
    865 	last--;
    866 
    867 	if ( pa_nvals != NULL ) {
    868 		if ( *pa_nvals == NULL ) {
    869 			*pa_nvals = ch_malloc( ( last + 2 ) * sizeof(struct berval) );
    870 			memset( *pa_nvals, 0, ( last + 2 ) * sizeof(struct berval) );
    871 		}
    872 	}
    873 
    874 	for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
    875 		struct berval	olddn = BER_BVNULL,
    876 				oldval;
    877 		int		rc;
    878 		LDAPURLDesc	*ludp;
    879 
    880 		oldval = a_vals[i];
    881 		rc = ldap_url_parse( oldval.bv_val, &ludp );
    882 		if ( rc != LDAP_URL_SUCCESS ) {
    883 			/* leave attr untouched if massage failed */
    884 			if ( pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
    885 				ber_dupbv( &(*pa_nvals)[i], &oldval );
    886 			}
    887 			continue;
    888 		}
    889 
    890 		/* FIXME: URLs like "ldap:///dc=suffix" if passed
    891 		 * thru ldap_url_parse() and ldap_url_desc2str()
    892 		 * get rewritten as "ldap:///dc=suffix??base";
    893 		 * we don't want this to occur... */
    894 		if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
    895 			ludp->lud_scope = LDAP_SCOPE_DEFAULT;
    896 		}
    897 
    898 		ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
    899 
    900 		dn = olddn;
    901 		if ( pa_nvals ) {
    902 			ndn = olddn;
    903 			rc = rwm_dn_massage_pretty_normalize( &dc, &olddn,
    904 					&dn, &ndn );
    905 		} else {
    906 			rc = rwm_dn_massage_pretty( &dc, &olddn, &dn );
    907 		}
    908 
    909 		switch ( rc ) {
    910 		case LDAP_UNWILLING_TO_PERFORM:
    911 			/*
    912 			 * FIXME: need to check if it may be considered
    913 			 * legal to trim values when adding/modifying;
    914 			 * it should be when searching (e.g. ACLs).
    915 			 */
    916 			ch_free( a_vals[i].bv_val );
    917 			if (last > i ) {
    918 				a_vals[i] = a_vals[last];
    919 				if ( pa_nvals ) {
    920 					(*pa_nvals)[i] = (*pa_nvals)[last];
    921 				}
    922 			}
    923 			BER_BVZERO( &a_vals[last] );
    924 			if ( pa_nvals ) {
    925 				BER_BVZERO( &(*pa_nvals)[last] );
    926 			}
    927 			last--;
    928 			break;
    929 
    930 		case LDAP_SUCCESS:
    931 			if ( !BER_BVISNULL( &dn ) && dn.bv_val != olddn.bv_val ) {
    932 				char	*newurl;
    933 
    934 				ludp->lud_dn = dn.bv_val;
    935 				newurl = ldap_url_desc2str( ludp );
    936 				ludp->lud_dn = olddn.bv_val;
    937 				ch_free( dn.bv_val );
    938 				if ( newurl == NULL ) {
    939 					/* FIXME: leave attr untouched
    940 					 * even if ldap_url_desc2str failed...
    941 					 */
    942 					break;
    943 				}
    944 
    945 				ber_str2bv( newurl, 0, 1, &a_vals[i] );
    946 				LDAP_FREE( newurl );
    947 
    948 				if ( pa_nvals ) {
    949 					ludp->lud_dn = ndn.bv_val;
    950 					newurl = ldap_url_desc2str( ludp );
    951 					ludp->lud_dn = olddn.bv_val;
    952 					ch_free( ndn.bv_val );
    953 					if ( newurl == NULL ) {
    954 						/* FIXME: leave attr untouched
    955 						 * even if ldap_url_desc2str failed...
    956 						 */
    957 						ch_free( a_vals[i].bv_val );
    958 						a_vals[i] = oldval;
    959 						break;
    960 					}
    961 
    962 					if ( !BER_BVISNULL( &(*pa_nvals)[i] ) ) {
    963 						ch_free( (*pa_nvals)[i].bv_val );
    964 					}
    965 					ber_str2bv( newurl, 0, 1, &(*pa_nvals)[i] );
    966 					LDAP_FREE( newurl );
    967 				}
    968 
    969 				ch_free( oldval.bv_val );
    970 				ludp->lud_dn = olddn.bv_val;
    971 			}
    972 			break;
    973 
    974 		default:
    975 			/* leave attr untouched if massage failed */
    976 			if ( pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
    977 				ber_dupbv( &(*pa_nvals)[i], &a_vals[i] );
    978 			}
    979 			break;
    980 		}
    981 		ldap_free_urldesc( ludp );
    982 	}
    983 
    984 	return 0;
    985 }
    986 
    987 /*
    988  * I don't like this much, but we need two different
    989  * functions because different heap managers may be
    990  * in use in back-ldap/meta to reduce the amount of
    991  * calls to malloc routines, and some of the free()
    992  * routines may be macros with args
    993  */
    994 int
    995 rwm_dnattr_rewrite(
    996 	Operation		*op,
    997 	SlapReply		*rs,
    998 	void			*cookie,
    999 	BerVarray		a_vals,
   1000 	BerVarray		*pa_nvals )
   1001 {
   1002 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
   1003 	struct ldaprwmap	*rwmap =
   1004 			(struct ldaprwmap *)on->on_bi.bi_private;
   1005 
   1006 	int			i, last;
   1007 
   1008 	dncookie		dc;
   1009 	struct berval		dn = BER_BVNULL,
   1010 				ndn = BER_BVNULL;
   1011 	BerVarray		in;
   1012 
   1013 	if ( a_vals ) {
   1014 		in = a_vals;
   1015 
   1016 	} else {
   1017 		if ( pa_nvals == NULL || *pa_nvals == NULL ) {
   1018 			return LDAP_OTHER;
   1019 		}
   1020 		in = *pa_nvals;
   1021 	}
   1022 
   1023 	/*
   1024 	 * Rewrite the dn if needed
   1025 	 */
   1026 	dc.rwmap = rwmap;
   1027 	dc.conn = op->o_conn;
   1028 	dc.rs = rs;
   1029 	dc.ctx = (char *)cookie;
   1030 
   1031 	for ( last = 0; !BER_BVISNULL( &in[last] ); last++ );
   1032 	last--;
   1033 	if ( pa_nvals != NULL ) {
   1034 		if ( *pa_nvals == NULL ) {
   1035 			*pa_nvals = ch_malloc( ( last + 2 ) * sizeof(struct berval) );
   1036 			memset( *pa_nvals, 0, ( last + 2 ) * sizeof(struct berval) );
   1037 		}
   1038 	}
   1039 
   1040 	for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
   1041 		int		rc;
   1042 
   1043 		if ( a_vals ) {
   1044 			dn = in[i];
   1045 			if ( pa_nvals ) {
   1046 				ndn = (*pa_nvals)[i];
   1047 				rc = rwm_dn_massage_pretty_normalize( &dc, &in[i], &dn, &ndn );
   1048 			} else {
   1049 				rc = rwm_dn_massage_pretty( &dc, &in[i], &dn );
   1050 			}
   1051 		} else {
   1052 			ndn = in[i];
   1053 			rc = rwm_dn_massage_normalize( &dc, &in[i], &ndn );
   1054 		}
   1055 
   1056 		switch ( rc ) {
   1057 		case LDAP_UNWILLING_TO_PERFORM:
   1058 			/*
   1059 			 * FIXME: need to check if it may be considered
   1060 			 * legal to trim values when adding/modifying;
   1061 			 * it should be when searching (e.g. ACLs).
   1062 			 */
   1063 			ch_free( in[i].bv_val );
   1064 			if (last > i ) {
   1065 				in[i] = in[last];
   1066 				if ( a_vals && pa_nvals ) {
   1067 					(*pa_nvals)[i] = (*pa_nvals)[last];
   1068 				}
   1069 			}
   1070 			BER_BVZERO( &in[last] );
   1071 			if ( a_vals && pa_nvals ) {
   1072 				BER_BVZERO( &(*pa_nvals)[last] );
   1073 			}
   1074 			last--;
   1075 			break;
   1076 
   1077 		case LDAP_SUCCESS:
   1078 			if ( a_vals ) {
   1079 				if ( !BER_BVISNULL( &dn ) && dn.bv_val != a_vals[i].bv_val ) {
   1080 					ch_free( a_vals[i].bv_val );
   1081 					a_vals[i] = dn;
   1082 
   1083 					if ( pa_nvals ) {
   1084 						if ( !BER_BVISNULL( &(*pa_nvals)[i] ) ) {
   1085 							ch_free( (*pa_nvals)[i].bv_val );
   1086 						}
   1087 						(*pa_nvals)[i] = ndn;
   1088 					}
   1089 				}
   1090 
   1091 			} else {
   1092 				if ( !BER_BVISNULL( &ndn ) && ndn.bv_val != (*pa_nvals)[i].bv_val ) {
   1093 					ch_free( (*pa_nvals)[i].bv_val );
   1094 					(*pa_nvals)[i] = ndn;
   1095 				}
   1096 			}
   1097 			break;
   1098 
   1099 		default:
   1100 			/* leave attr untouched if massage failed */
   1101 			if ( a_vals && pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
   1102 				dnNormalize( 0, NULL, NULL, &a_vals[i], &(*pa_nvals)[i], NULL );
   1103 			}
   1104 			break;
   1105 		}
   1106 	}
   1107 
   1108 	return 0;
   1109 }
   1110 
   1111 int
   1112 rwm_referral_result_rewrite(
   1113 	dncookie		*dc,
   1114 	BerVarray		a_vals )
   1115 {
   1116 	int		i, last;
   1117 
   1118 	for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ );
   1119 	last--;
   1120 
   1121 	for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
   1122 		struct berval	dn,
   1123 				olddn = BER_BVNULL;
   1124 		int		rc;
   1125 		LDAPURLDesc	*ludp;
   1126 
   1127 		rc = ldap_url_parse( a_vals[i].bv_val, &ludp );
   1128 		if ( rc != LDAP_URL_SUCCESS ) {
   1129 			/* leave attr untouched if massage failed */
   1130 			continue;
   1131 		}
   1132 
   1133 		/* FIXME: URLs like "ldap:///dc=suffix" if passed
   1134 		 * thru ldap_url_parse() and ldap_url_desc2str()
   1135 		 * get rewritten as "ldap:///dc=suffix??base";
   1136 		 * we don't want this to occur... */
   1137 		if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
   1138 			ludp->lud_scope = LDAP_SCOPE_DEFAULT;
   1139 		}
   1140 
   1141 		ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
   1142 
   1143 		dn = olddn;
   1144 		rc = rwm_dn_massage_pretty( dc, &olddn, &dn );
   1145 		switch ( rc ) {
   1146 		case LDAP_UNWILLING_TO_PERFORM:
   1147 			/*
   1148 			 * FIXME: need to check if it may be considered
   1149 			 * legal to trim values when adding/modifying;
   1150 			 * it should be when searching (e.g. ACLs).
   1151 			 */
   1152 			ch_free( a_vals[i].bv_val );
   1153 			if ( last > i ) {
   1154 				a_vals[i] = a_vals[last];
   1155 			}
   1156 			BER_BVZERO( &a_vals[last] );
   1157 			last--;
   1158 			i--;
   1159 			break;
   1160 
   1161 		default:
   1162 			/* leave attr untouched if massage failed */
   1163 			if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val ) {
   1164 				char	*newurl;
   1165 
   1166 				ludp->lud_dn = dn.bv_val;
   1167 				newurl = ldap_url_desc2str( ludp );
   1168 				if ( newurl == NULL ) {
   1169 					/* FIXME: leave attr untouched
   1170 					 * even if ldap_url_desc2str failed...
   1171 					 */
   1172 					break;
   1173 				}
   1174 
   1175 				ch_free( a_vals[i].bv_val );
   1176 				ber_str2bv( newurl, 0, 1, &a_vals[i] );
   1177 				LDAP_FREE( newurl );
   1178 				ludp->lud_dn = olddn.bv_val;
   1179 			}
   1180 			break;
   1181 		}
   1182 
   1183 		ldap_free_urldesc( ludp );
   1184 	}
   1185 
   1186 	return 0;
   1187 }
   1188 
   1189 int
   1190 rwm_dnattr_result_rewrite(
   1191 	dncookie		*dc,
   1192 	BerVarray		a_vals,
   1193 	BerVarray		a_nvals )
   1194 {
   1195 	int		i, last;
   1196 
   1197 	for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ );
   1198 	last--;
   1199 
   1200 	for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
   1201 		struct berval	pdn, ndn = BER_BVNULL;
   1202 		int		rc;
   1203 
   1204 		pdn = a_vals[i];
   1205 		rc = rwm_dn_massage_pretty_normalize( dc, &a_vals[i], &pdn, &ndn );
   1206 		switch ( rc ) {
   1207 		case LDAP_UNWILLING_TO_PERFORM:
   1208 			/*
   1209 			 * FIXME: need to check if it may be considered
   1210 			 * legal to trim values when adding/modifying;
   1211 			 * it should be when searching (e.g. ACLs).
   1212 			 */
   1213 			assert( a_vals[i].bv_val != a_nvals[i].bv_val );
   1214 			ch_free( a_vals[i].bv_val );
   1215 			ch_free( a_nvals[i].bv_val );
   1216 			if ( last > i ) {
   1217 				a_vals[i] = a_vals[last];
   1218 				a_nvals[i] = a_nvals[last];
   1219 			}
   1220 			BER_BVZERO( &a_vals[last] );
   1221 			BER_BVZERO( &a_nvals[last] );
   1222 			last--;
   1223 			break;
   1224 
   1225 		default:
   1226 			/* leave attr untouched if massage failed */
   1227 			if ( !BER_BVISNULL( &pdn ) && a_vals[i].bv_val != pdn.bv_val ) {
   1228 				ch_free( a_vals[i].bv_val );
   1229 				a_vals[i] = pdn;
   1230 			}
   1231 			if ( !BER_BVISNULL( &ndn ) && a_nvals[i].bv_val != ndn.bv_val ) {
   1232 				ch_free( a_nvals[i].bv_val );
   1233 				a_nvals[i] = ndn;
   1234 			}
   1235 			break;
   1236 		}
   1237 	}
   1238 
   1239 	return 0;
   1240 }
   1241 
   1242 void
   1243 rwm_mapping_dst_free( void *v_mapping )
   1244 {
   1245 	struct ldapmapping *mapping = v_mapping;
   1246 
   1247 	if ( BER_BVISEMPTY( &mapping[0].m_dst ) ) {
   1248 		rwm_mapping_free( &mapping[ -1 ] );
   1249 	}
   1250 }
   1251 
   1252 void
   1253 rwm_mapping_free( void *v_mapping )
   1254 {
   1255 	struct ldapmapping *mapping = v_mapping;
   1256 
   1257 	if ( !BER_BVISNULL( &mapping[0].m_src ) ) {
   1258 		ch_free( mapping[0].m_src.bv_val );
   1259 	}
   1260 
   1261 	if ( mapping[0].m_flags & RWMMAP_F_FREE_SRC ) {
   1262 		if ( mapping[0].m_flags & RWMMAP_F_IS_OC ) {
   1263 			if ( mapping[0].m_src_oc ) {
   1264 				ch_free( mapping[0].m_src_oc );
   1265 			}
   1266 
   1267 		} else {
   1268 			if ( mapping[0].m_src_ad ) {
   1269 				ch_free( mapping[0].m_src_ad );
   1270 			}
   1271 		}
   1272 	}
   1273 
   1274 	if ( !BER_BVISNULL( &mapping[0].m_dst ) ) {
   1275 		ch_free( mapping[0].m_dst.bv_val );
   1276 	}
   1277 
   1278 	if ( mapping[0].m_flags & RWMMAP_F_FREE_DST ) {
   1279 		if ( mapping[0].m_flags & RWMMAP_F_IS_OC ) {
   1280 			if ( mapping[0].m_dst_oc ) {
   1281 				ch_free( mapping[0].m_dst_oc );
   1282 			}
   1283 
   1284 		} else {
   1285 			if ( mapping[0].m_dst_ad ) {
   1286 				ch_free( mapping[0].m_dst_ad );
   1287 			}
   1288 		}
   1289 	}
   1290 
   1291 	ch_free( mapping );
   1292 
   1293 }
   1294 
   1295 #endif /* SLAPD_OVER_RWM */
   1296