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