Home | History | Annotate | Line # | Download | only in back-meta
      1 /*	$NetBSD: map.c,v 1.4 2025/09/05 21:16:28 christos Exp $	*/
      2 
      3 /* map.c - ldap backend mapping routines */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1998-2024 The OpenLDAP Foundation.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 /* ACKNOWLEDGEMENTS:
     19  * This work was initially developed by the Howard Chu for inclusion
     20  * in OpenLDAP Software and subsequently enhanced by Pierangelo
     21  * Masarati.
     22  */
     23 /* This is an altered version */
     24 /*
     25  * Copyright 1999, Howard Chu, All rights reserved. <hyc (at) highlandsun.com>
     26  *
     27  * Permission is granted to anyone to use this software for any purpose
     28  * on any computer system, and to alter it and redistribute it, subject
     29  * to the following restrictions:
     30  *
     31  * 1. The author is not responsible for the consequences of use of this
     32  *    software, no matter how awful, even if they arise from flaws in it.
     33  *
     34  * 2. The origin of this software must not be misrepresented, either by
     35  *    explicit claim or by omission.  Since few users ever read sources,
     36  *    credits should appear in the documentation.
     37  *
     38  * 3. Altered versions must be plainly marked as such, and must not be
     39  *    misrepresented as being the original software.  Since few users
     40  *    ever read sources, credits should appear in the documentation.
     41  *
     42  * 4. This notice may not be removed or altered.
     43  *
     44  *
     45  *
     46  * Copyright 2000, Pierangelo Masarati, All rights reserved. <ando (at) sys-net.it>
     47  *
     48  * This software is being modified by Pierangelo Masarati.
     49  * The previously reported conditions apply to the modified code as well.
     50  * Changes in the original code are highlighted where required.
     51  * Credits for the original code go to the author, Howard Chu.
     52  */
     53 
     54 #include <sys/cdefs.h>
     55 __RCSID("$NetBSD: map.c,v 1.4 2025/09/05 21:16:28 christos Exp $");
     56 
     57 #include "portable.h"
     58 
     59 #include <stdio.h>
     60 
     61 #include <ac/string.h>
     62 #include <ac/socket.h>
     63 
     64 #include "slap.h"
     65 #include "lutil.h"
     66 #include "../back-ldap/back-ldap.h"
     67 #include "back-meta.h"
     68 
     69 int
     70 mapping_cmp ( const void *c1, const void *c2 )
     71 {
     72 	struct ldapmapping *map1 = (struct ldapmapping *)c1;
     73 	struct ldapmapping *map2 = (struct ldapmapping *)c2;
     74 	int rc = map1->src.bv_len - map2->src.bv_len;
     75 	if (rc) return rc;
     76 	return ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) );
     77 }
     78 
     79 int
     80 mapping_dup ( void *c1, void *c2 )
     81 {
     82 	struct ldapmapping *map1 = (struct ldapmapping *)c1;
     83 	struct ldapmapping *map2 = (struct ldapmapping *)c2;
     84 
     85 	return ( ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) == 0 ) ? -1 : 0 );
     86 }
     87 
     88 void
     89 ldap_back_map_init ( struct ldapmap *lm, struct ldapmapping **m )
     90 {
     91 	struct ldapmapping *mapping;
     92 
     93 	assert( m != NULL );
     94 
     95 	*m = NULL;
     96 
     97 	mapping = (struct ldapmapping *)ch_calloc( 2,
     98 			sizeof( struct ldapmapping ) );
     99 	if ( mapping == NULL ) {
    100 		return;
    101 	}
    102 
    103 	ber_str2bv( "objectclass", STRLENOF("objectclass"), 1, &mapping[0].src);
    104 	ber_dupbv( &mapping[0].dst, &mapping[0].src );
    105 	mapping[1].src = mapping[0].src;
    106 	mapping[1].dst = mapping[0].dst;
    107 
    108 	ldap_avl_insert( &lm->map, (caddr_t)&mapping[0],
    109 			mapping_cmp, mapping_dup );
    110 	ldap_avl_insert( &lm->remap, (caddr_t)&mapping[1],
    111 			mapping_cmp, mapping_dup );
    112 	*m = mapping;
    113 }
    114 
    115 int
    116 ldap_back_mapping ( struct ldapmap *map, struct berval *s, struct ldapmapping **m,
    117 	int remap )
    118 {
    119 	Avlnode *tree;
    120 	struct ldapmapping fmapping;
    121 
    122 	assert( m != NULL );
    123 
    124 	/* let special attrnames slip through (ITS#5760) */
    125 	if ( bvmatch( s, slap_bv_no_attrs )
    126 		|| bvmatch( s, slap_bv_all_user_attrs )
    127 		|| bvmatch( s, slap_bv_all_operational_attrs ) )
    128 	{
    129 		*m = NULL;
    130 		return 0;
    131 	}
    132 
    133 	if ( remap == BACKLDAP_REMAP ) {
    134 		tree = map->remap;
    135 
    136 	} else {
    137 		tree = map->map;
    138 	}
    139 
    140 	fmapping.src = *s;
    141 	*m = (struct ldapmapping *)ldap_avl_find( tree, (caddr_t)&fmapping, mapping_cmp );
    142 	if ( *m == NULL ) {
    143 		return map->drop_missing;
    144 	}
    145 
    146 	return 0;
    147 }
    148 
    149 void
    150 ldap_back_map ( struct ldapmap *map, struct berval *s, struct berval *bv,
    151 	int remap )
    152 {
    153 	struct ldapmapping *mapping;
    154 	int drop_missing;
    155 
    156 	/* map->map may be NULL when mapping is configured,
    157 	 * but map->remap can't */
    158 	if ( map->remap == NULL ) {
    159 		*bv = *s;
    160 		return;
    161 	}
    162 
    163 	BER_BVZERO( bv );
    164 	drop_missing = ldap_back_mapping( map, s, &mapping, remap );
    165 	if ( mapping != NULL ) {
    166 		if ( !BER_BVISNULL( &mapping->dst ) ) {
    167 			*bv = mapping->dst;
    168 		}
    169 		return;
    170 	}
    171 
    172 	if ( !drop_missing ) {
    173 		*bv = *s;
    174 	}
    175 }
    176 
    177 int
    178 ldap_back_map_attrs(
    179 		Operation *op,
    180 		struct ldapmap *at_map,
    181 		AttributeName *an,
    182 		int remap,
    183 		char ***mapped_attrs )
    184 {
    185 	int i, x, j;
    186 	char **na;
    187 	struct berval mapped;
    188 
    189 	if ( an == NULL && op->o_bd->be_extra_anlist == NULL ) {
    190 		*mapped_attrs = NULL;
    191 		return LDAP_SUCCESS;
    192 	}
    193 
    194 	i = 0;
    195 	if ( an != NULL ) {
    196 		for ( ; !BER_BVISNULL( &an[i].an_name ); i++ )
    197 			/*  */ ;
    198 	}
    199 
    200 	x = 0;
    201 	if ( op->o_bd->be_extra_anlist != NULL ) {
    202 		for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ )
    203 			/*  */ ;
    204 	}
    205 
    206 	assert( i > 0 || x > 0 );
    207 
    208 	na = (char **)ber_memcalloc_x( i + x + 1, sizeof(char *), op->o_tmpmemctx );
    209 	if ( na == NULL ) {
    210 		*mapped_attrs = NULL;
    211 		return LDAP_NO_MEMORY;
    212 	}
    213 
    214 	j = 0;
    215 	if ( i > 0 ) {
    216 		for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
    217 			ldap_back_map( at_map, &an[i].an_name, &mapped, remap );
    218 			if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) {
    219 				na[j++] = mapped.bv_val;
    220 			}
    221 		}
    222 	}
    223 
    224 	if ( x > 0 ) {
    225 		for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) {
    226 			if ( op->o_bd->be_extra_anlist[x].an_desc &&
    227 				ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, an ) )
    228 			{
    229 				continue;
    230 			}
    231 
    232 			ldap_back_map( at_map, &op->o_bd->be_extra_anlist[x].an_name, &mapped, remap );
    233 			if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) {
    234 				na[j++] = mapped.bv_val;
    235 			}
    236 		}
    237 	}
    238 
    239 	if ( j == 0 && ( i > 0 || x > 0 ) ) {
    240 		na[j++] = LDAP_NO_ATTRS;
    241 	}
    242 	na[j] = NULL;
    243 
    244 	*mapped_attrs = na;
    245 
    246 	return LDAP_SUCCESS;
    247 }
    248 
    249 static int
    250 map_attr_value(
    251 		dncookie		*dc,
    252 		AttributeDescription 	*ad,
    253 		struct berval		*mapped_attr,
    254 		struct berval		*value,
    255 		struct berval		*mapped_value,
    256 		int			remap,
    257 		void			*memctx )
    258 {
    259 	struct berval		vtmp;
    260 	int			freeval = 0;
    261 
    262 	ldap_back_map( &dc->target->mt_rwmap.rwm_at, &ad->ad_cname, mapped_attr, remap );
    263 	if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
    264 #if 0
    265 		/*
    266 		 * FIXME: are we sure we need to search oc_map if at_map fails?
    267 		 */
    268 		ldap_back_map( &dc->target->mt_rwmap.rwm_oc, &ad->ad_cname, mapped_attr, remap );
    269 		if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
    270 			*mapped_attr = ad->ad_cname;
    271 		}
    272 #endif
    273 		if ( dc->target->mt_rwmap.rwm_at.drop_missing ) {
    274 			return -1;
    275 		}
    276 
    277 		*mapped_attr = ad->ad_cname;
    278 	}
    279 
    280 	if ( value == NULL ) {
    281 		return 0;
    282 	}
    283 
    284 	if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
    285 	{
    286 		dncookie fdc = *dc;
    287 
    288 		fdc.ctx = "searchFilterAttrDN";
    289 
    290 		switch ( ldap_back_dn_massage( &fdc, value, &vtmp ) ) {
    291 		case LDAP_SUCCESS:
    292 			if ( vtmp.bv_val != value->bv_val ) {
    293 				freeval = 1;
    294 			}
    295 			break;
    296 
    297 		case LDAP_UNWILLING_TO_PERFORM:
    298 			return -1;
    299 
    300 		case LDAP_OTHER:
    301 			return -1;
    302 		}
    303 
    304 	} else if ( ad->ad_type->sat_equality &&
    305 		ad->ad_type->sat_equality->smr_usage & SLAP_MR_MUTATION_NORMALIZER )
    306 	{
    307 		if ( ad->ad_type->sat_equality->smr_normalize(
    308 			(SLAP_MR_DENORMALIZE|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX),
    309 			NULL, NULL, value, &vtmp, memctx ) )
    310 		{
    311 			return -1;
    312 		}
    313 		freeval = 2;
    314 
    315 	} else if ( ad == slap_schema.si_ad_objectClass || ad == slap_schema.si_ad_structuralObjectClass ) {
    316 		ldap_back_map( &dc->target->mt_rwmap.rwm_oc, value, &vtmp, remap );
    317 		if ( BER_BVISNULL( &vtmp ) || BER_BVISEMPTY( &vtmp ) ) {
    318 			vtmp = *value;
    319 		}
    320 
    321 	} else {
    322 		vtmp = *value;
    323 	}
    324 
    325 	filter_escape_value_x( &vtmp, mapped_value, memctx );
    326 
    327 	switch ( freeval ) {
    328 	case 1:
    329 		ber_memfree( vtmp.bv_val );
    330 		break;
    331 	case 2:
    332 		ber_memfree_x( vtmp.bv_val, memctx );
    333 		break;
    334 	}
    335 
    336 	return 0;
    337 }
    338 
    339 static int
    340 ldap_back_int_filter_map_rewrite(
    341 		dncookie		*dc,
    342 		Filter			*f,
    343 		struct berval	*fstr,
    344 		int				remap,
    345 		void			*memctx )
    346 {
    347 	int		i;
    348 	Filter		*p;
    349 	struct berval	atmp,
    350 			vtmp,
    351 			*tmp;
    352 	static struct berval
    353 			/* better than nothing... */
    354 			ber_bvfalse = BER_BVC( "(!(objectClass=*))" ),
    355 			ber_bvtf_false = BER_BVC( "(|)" ),
    356 			/* better than nothing... */
    357 			ber_bvtrue = BER_BVC( "(objectClass=*)" ),
    358 			ber_bvtf_true = BER_BVC( "(&)" ),
    359 #if 0
    360 			/* no longer needed; preserved for completeness */
    361 			ber_bvundefined = BER_BVC( "(?=undefined)" ),
    362 #endif
    363 			ber_bverror = BER_BVC( "(?=error)" ),
    364 			ber_bvunknown = BER_BVC( "(?=unknown)" ),
    365 			ber_bvnone = BER_BVC( "(?=none)" );
    366 	ber_len_t	len;
    367 
    368 	assert( fstr != NULL );
    369 	BER_BVZERO( fstr );
    370 
    371 	if ( f == NULL ) {
    372 		ber_dupbv_x( fstr, &ber_bvnone, memctx );
    373 		return LDAP_OTHER;
    374 	}
    375 
    376 	switch ( ( f->f_choice & SLAPD_FILTER_MASK ) ) {
    377 	case LDAP_FILTER_EQUALITY:
    378 		if ( map_attr_value( dc, f->f_av_desc, &atmp,
    379 					&f->f_av_value, &vtmp, remap, memctx ) )
    380 		{
    381 			goto computed;
    382 		}
    383 
    384 		fstr->bv_len = atmp.bv_len + vtmp.bv_len
    385 			+ ( sizeof("(=)") - 1 );
    386 		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
    387 		if ( !fstr->bv_val ) {
    388 			ber_memfree_x( vtmp.bv_val, memctx );
    389 			return LDAP_NO_MEMORY;
    390 		}
    391 
    392 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
    393 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
    394 
    395 		ber_memfree_x( vtmp.bv_val, memctx );
    396 		break;
    397 
    398 	case LDAP_FILTER_GE:
    399 		if ( map_attr_value( dc, f->f_av_desc, &atmp,
    400 					&f->f_av_value, &vtmp, remap, memctx ) )
    401 		{
    402 			goto computed;
    403 		}
    404 
    405 		fstr->bv_len = atmp.bv_len + vtmp.bv_len
    406 			+ ( sizeof("(>=)") - 1 );
    407 		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
    408 		if ( !fstr->bv_val ) {
    409 			ber_memfree_x( vtmp.bv_val, memctx );
    410 			return LDAP_NO_MEMORY;
    411 		}
    412 
    413 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
    414 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
    415 
    416 		ber_memfree_x( vtmp.bv_val, memctx );
    417 		break;
    418 
    419 	case LDAP_FILTER_LE:
    420 		if ( map_attr_value( dc, f->f_av_desc, &atmp,
    421 					&f->f_av_value, &vtmp, remap, memctx ) )
    422 		{
    423 			goto computed;
    424 		}
    425 
    426 		fstr->bv_len = atmp.bv_len + vtmp.bv_len
    427 			+ ( sizeof("(<=)") - 1 );
    428 		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
    429 		if ( !fstr->bv_val ) {
    430 			ber_memfree_x( vtmp.bv_val, memctx );
    431 			return LDAP_NO_MEMORY;
    432 		}
    433 
    434 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
    435 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
    436 
    437 		ber_memfree_x( vtmp.bv_val, memctx );
    438 		break;
    439 
    440 	case LDAP_FILTER_APPROX:
    441 		if ( map_attr_value( dc, f->f_av_desc, &atmp,
    442 					&f->f_av_value, &vtmp, remap, memctx ) )
    443 		{
    444 			goto computed;
    445 		}
    446 
    447 		fstr->bv_len = atmp.bv_len + vtmp.bv_len
    448 			+ ( sizeof("(~=)") - 1 );
    449 		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
    450 		if ( !fstr->bv_val ) {
    451 			ber_memfree_x( vtmp.bv_val, memctx );
    452 			return LDAP_NO_MEMORY;
    453 		}
    454 
    455 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
    456 			atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
    457 
    458 		ber_memfree_x( vtmp.bv_val, memctx );
    459 		break;
    460 
    461 	case LDAP_FILTER_SUBSTRINGS:
    462 		if ( map_attr_value( dc, f->f_sub_desc, &atmp,
    463 					NULL, NULL, remap, memctx ) )
    464 		{
    465 			goto computed;
    466 		}
    467 
    468 		/* cannot be a DN ... */
    469 
    470 		fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) );
    471 		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128 ? */
    472 		if ( !fstr->bv_val ) {
    473 			return LDAP_NO_MEMORY;
    474 		}
    475 
    476 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
    477 			atmp.bv_val );
    478 
    479 		if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
    480 			char *tmp;
    481 
    482 			len = fstr->bv_len;
    483 
    484 			filter_escape_value_x( &f->f_sub_initial, &vtmp, memctx );
    485 
    486 			fstr->bv_len += vtmp.bv_len;
    487 			tmp = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
    488 			if ( !tmp ) {
    489 				ber_memfree_x( vtmp.bv_val, memctx );
    490 				return LDAP_NO_MEMORY;
    491 			}
    492 			fstr->bv_val = tmp;
    493 
    494 			snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3,
    495 				/* "(attr=" */ "%s*)",
    496 				vtmp.bv_len ? vtmp.bv_val : "" );
    497 
    498 			ber_memfree_x( vtmp.bv_val, memctx );
    499 		}
    500 
    501 		if ( f->f_sub_any != NULL ) {
    502 			for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
    503 				char *tmp;
    504 
    505 				len = fstr->bv_len;
    506 				filter_escape_value_x( &f->f_sub_any[i], &vtmp, memctx );
    507 
    508 				fstr->bv_len += vtmp.bv_len + 1;
    509 				tmp = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
    510 				if ( !tmp ) {
    511 					ber_memfree_x( vtmp.bv_val, memctx );
    512 					return LDAP_NO_MEMORY;
    513 				}
    514 				fstr->bv_val = tmp;
    515 
    516 				snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
    517 					/* "(attr=[init]*[any*]" */ "%s*)",
    518 					vtmp.bv_len ? vtmp.bv_val : "" );
    519 				ber_memfree_x( vtmp.bv_val, memctx );
    520 			}
    521 		}
    522 
    523 		if ( !BER_BVISNULL( &f->f_sub_final ) ) {
    524 			char *tmp;
    525 
    526 			len = fstr->bv_len;
    527 
    528 			filter_escape_value_x( &f->f_sub_final, &vtmp, memctx );
    529 
    530 			fstr->bv_len += vtmp.bv_len;
    531 			tmp = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
    532 			if ( !tmp ) {
    533 				ber_memfree_x( vtmp.bv_val, memctx );
    534 				return LDAP_NO_MEMORY;
    535 			}
    536 			fstr->bv_val = tmp;
    537 
    538 			snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
    539 				/* "(attr=[init*][any*]" */ "%s)",
    540 				vtmp.bv_len ? vtmp.bv_val : "" );
    541 
    542 			ber_memfree_x( vtmp.bv_val, memctx );
    543 		}
    544 
    545 		break;
    546 
    547 	case LDAP_FILTER_PRESENT:
    548 		if ( map_attr_value( dc, f->f_desc, &atmp,
    549 					NULL, NULL, remap, memctx ) )
    550 		{
    551 			goto computed;
    552 		}
    553 
    554 		fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) );
    555 		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
    556 		if ( !fstr->bv_val ) {
    557 			return LDAP_NO_MEMORY;
    558 		}
    559 
    560 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
    561 			atmp.bv_val );
    562 		break;
    563 
    564 	case LDAP_FILTER_AND:
    565 	case LDAP_FILTER_OR:
    566 	case LDAP_FILTER_NOT:
    567 		fstr->bv_len = STRLENOF( "(%)" );
    568 		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx );	/* FIXME: why 128? */
    569 
    570 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
    571 			f->f_choice == LDAP_FILTER_AND ? '&' :
    572 			f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
    573 
    574 		for ( p = f->f_list; p != NULL; p = p->f_next ) {
    575 			int	rc;
    576 
    577 			len = fstr->bv_len;
    578 
    579 			rc = ldap_back_int_filter_map_rewrite( dc, p, &vtmp, remap, memctx );
    580 			if ( rc != LDAP_SUCCESS ) {
    581 				return rc;
    582 			}
    583 
    584 			fstr->bv_len += vtmp.bv_len;
    585 			fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
    586 			if ( !fstr->bv_val ) {
    587 				ber_memfree_x( vtmp.bv_val, memctx );
    588 				return LDAP_NO_MEMORY;
    589 			}
    590 
    591 			snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2,
    592 				/*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" );
    593 
    594 			ber_memfree_x( vtmp.bv_val, memctx );
    595 		}
    596 
    597 		break;
    598 
    599 	case LDAP_FILTER_EXT:
    600 		if ( f->f_mr_desc ) {
    601 			if ( map_attr_value( dc, f->f_mr_desc, &atmp,
    602 						&f->f_mr_value, &vtmp, remap, memctx ) )
    603 			{
    604 				goto computed;
    605 			}
    606 
    607 		} else {
    608 			BER_BVSTR( &atmp, "" );
    609 			filter_escape_value_x( &f->f_mr_value, &vtmp, memctx );
    610 		}
    611 
    612 		/* FIXME: cleanup (less ?: operators...) */
    613 		fstr->bv_len = atmp.bv_len +
    614 			( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
    615 			( !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
    616 			vtmp.bv_len + ( STRLENOF( "(:=)" ) );
    617 		fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
    618 		if ( !fstr->bv_val ) {
    619 			ber_memfree_x( vtmp.bv_val, memctx );
    620 			return LDAP_NO_MEMORY;
    621 		}
    622 
    623 		snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
    624 			atmp.bv_val,
    625 			f->f_mr_dnattrs ? ":dn" : "",
    626 			!BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
    627 			!BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
    628 			vtmp.bv_len ? vtmp.bv_val : "" );
    629 		ber_memfree_x( vtmp.bv_val, memctx );
    630 		break;
    631 
    632 	case SLAPD_FILTER_COMPUTED:
    633 		switch ( f->f_result ) {
    634 		/* FIXME: treat UNDEFINED as FALSE */
    635 		case SLAPD_COMPARE_UNDEFINED:
    636 computed:;
    637 			if ( META_BACK_TGT_NOUNDEFFILTER( dc->target ) ) {
    638 				return LDAP_COMPARE_FALSE;
    639 			}
    640 			/* fallthru */
    641 
    642 		case LDAP_COMPARE_FALSE:
    643 			if ( META_BACK_TGT_T_F( dc->target ) ) {
    644 				tmp = &ber_bvtf_false;
    645 				break;
    646 			}
    647 			tmp = &ber_bvfalse;
    648 			break;
    649 
    650 		case LDAP_COMPARE_TRUE:
    651 			if ( META_BACK_TGT_T_F( dc->target ) ) {
    652 				tmp = &ber_bvtf_true;
    653 				break;
    654 			}
    655 
    656 			tmp = &ber_bvtrue;
    657 			break;
    658 
    659 		default:
    660 			tmp = &ber_bverror;
    661 			break;
    662 		}
    663 
    664 		ber_dupbv_x( fstr, tmp, memctx );
    665 		break;
    666 
    667 	default:
    668 		ber_dupbv_x( fstr, &ber_bvunknown, memctx );
    669 		break;
    670 	}
    671 
    672 	return 0;
    673 }
    674 
    675 int
    676 ldap_back_filter_map_rewrite(
    677 		dncookie		*dc,
    678 		Filter			*f,
    679 		struct berval	*fstr,
    680 		int				remap,
    681 		void			*memctx )
    682 {
    683 	int		rc;
    684 	dncookie	fdc;
    685 	struct berval	ftmp;
    686 	static char	*dmy = "";
    687 
    688 	rc = ldap_back_int_filter_map_rewrite( dc, f, fstr, remap, memctx );
    689 
    690 	if ( rc != LDAP_SUCCESS ) {
    691 		return rc;
    692 	}
    693 
    694 	fdc = *dc;
    695 	ftmp = *fstr;
    696 
    697 	fdc.ctx = "searchFilter";
    698 
    699 	switch ( rewrite_session( fdc.target->mt_rwmap.rwm_rw, fdc.ctx,
    700 				( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : dmy ),
    701 				fdc.conn, &fstr->bv_val ) )
    702 	{
    703 	case REWRITE_REGEXEC_OK:
    704 		if ( !BER_BVISNULL( fstr ) ) {
    705 			fstr->bv_len = strlen( fstr->bv_val );
    706 
    707 		} else {
    708 			*fstr = ftmp;
    709 		}
    710 		Debug( LDAP_DEBUG_ARGS,
    711 			"[rw] %s: \"%s\" -> \"%s\"\n",
    712 			fdc.ctx, BER_BVISNULL( &ftmp ) ? "" : ftmp.bv_val,
    713 			BER_BVISNULL( fstr ) ? "" : fstr->bv_val );
    714 		rc = LDAP_SUCCESS;
    715 		break;
    716 
    717  	case REWRITE_REGEXEC_UNWILLING:
    718 		if ( fdc.rs ) {
    719 			fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
    720 			fdc.rs->sr_text = "Operation not allowed";
    721 		}
    722 		rc = LDAP_UNWILLING_TO_PERFORM;
    723 		break;
    724 
    725 	case REWRITE_REGEXEC_ERR:
    726 		if ( fdc.rs ) {
    727 			fdc.rs->sr_err = LDAP_OTHER;
    728 			fdc.rs->sr_text = "Rewrite error";
    729 		}
    730 		rc = LDAP_OTHER;
    731 		break;
    732 	}
    733 
    734 	if ( fstr->bv_val == dmy ) {
    735 		BER_BVZERO( fstr );
    736 
    737 	} else if ( fstr->bv_val != ftmp.bv_val ) {
    738 		/* NOTE: need to realloc mapped filter on slab
    739 		 * and free the original one, until librewrite
    740 		 * becomes slab-aware
    741 		 */
    742 		ber_dupbv_x( &ftmp, fstr, memctx );
    743 		ch_free( fstr->bv_val );
    744 		*fstr = ftmp;
    745 	}
    746 
    747 	return rc;
    748 }
    749 
    750 int
    751 ldap_back_referral_result_rewrite(
    752 	dncookie		*dc,
    753 	BerVarray		a_vals,
    754 	void			*memctx
    755 )
    756 {
    757 	int		i, last;
    758 
    759 	assert( dc != NULL );
    760 	assert( a_vals != NULL );
    761 
    762 	for ( last = 0; !BER_BVISNULL( &a_vals[ last ] ); last++ )
    763 		;
    764 	last--;
    765 
    766 	for ( i = 0; !BER_BVISNULL( &a_vals[ i ] ); i++ ) {
    767 		struct berval	dn,
    768 				olddn = BER_BVNULL;
    769 		int		rc;
    770 		LDAPURLDesc	*ludp;
    771 
    772 		rc = ldap_url_parse( a_vals[ i ].bv_val, &ludp );
    773 		if ( rc != LDAP_URL_SUCCESS ) {
    774 			/* leave attr untouched if massage failed */
    775 			continue;
    776 		}
    777 
    778 		/* FIXME: URLs like "ldap:///dc=suffix" if passed
    779 		 * thru ldap_url_parse() and ldap_url_desc2str()
    780 		 * get rewritten as "ldap:///dc=suffix??base";
    781 		 * we don't want this to occur... */
    782 		if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
    783 			ludp->lud_scope = LDAP_SCOPE_DEFAULT;
    784 		}
    785 
    786 		ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
    787 
    788 		rc = ldap_back_dn_massage( dc, &olddn, &dn );
    789 		switch ( rc ) {
    790 		case LDAP_UNWILLING_TO_PERFORM:
    791 			/*
    792 			 * FIXME: need to check if it may be considered
    793 			 * legal to trim values when adding/modifying;
    794 			 * it should be when searching (e.g. ACLs).
    795 			 */
    796 			ber_memfree( a_vals[ i ].bv_val );
    797 			if ( last > i ) {
    798 				a_vals[ i ] = a_vals[ last ];
    799 			}
    800 			BER_BVZERO( &a_vals[ last ] );
    801 			last--;
    802 			i--;
    803 			break;
    804 
    805 		default:
    806 			/* leave attr untouched if massage failed */
    807 			if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val )
    808 			{
    809 				char	*newurl;
    810 
    811 				ludp->lud_dn = dn.bv_val;
    812 				newurl = ldap_url_desc2str( ludp );
    813 				free( dn.bv_val );
    814 				if ( newurl == NULL ) {
    815 					/* FIXME: leave attr untouched
    816 					 * even if ldap_url_desc2str failed...
    817 					 */
    818 					break;
    819 				}
    820 
    821 				ber_memfree_x( a_vals[ i ].bv_val, memctx );
    822 				ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], memctx );
    823 				ber_memfree( newurl );
    824 				ludp->lud_dn = olddn.bv_val;
    825 			}
    826 			break;
    827 		}
    828 
    829 		ldap_free_urldesc( ludp );
    830 	}
    831 
    832 	return 0;
    833 }
    834 
    835 /*
    836  * I don't like this much, but we need two different
    837  * functions because different heap managers may be
    838  * in use in back-ldap/meta to reduce the amount of
    839  * calls to malloc routines, and some of the free()
    840  * routines may be macros with args
    841  */
    842 int
    843 ldap_dnattr_rewrite(
    844 	dncookie		*dc,
    845 	BerVarray		a_vals
    846 )
    847 {
    848 	struct berval	bv;
    849 	int		i, last;
    850 
    851 	assert( a_vals != NULL );
    852 
    853 	for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
    854 		;
    855 	last--;
    856 
    857 	for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
    858 		switch ( ldap_back_dn_massage( dc, &a_vals[i], &bv ) ) {
    859 		case LDAP_UNWILLING_TO_PERFORM:
    860 			/*
    861 			 * FIXME: need to check if it may be considered
    862 			 * legal to trim values when adding/modifying;
    863 			 * it should be when searching (e.g. ACLs).
    864 			 */
    865 			ch_free( a_vals[i].bv_val );
    866 			if ( last > i ) {
    867 				a_vals[i] = a_vals[last];
    868 			}
    869 			BER_BVZERO( &a_vals[last] );
    870 			last--;
    871 			break;
    872 
    873 		default:
    874 			/* leave attr untouched if massage failed */
    875 			if ( !BER_BVISNULL( &bv ) && bv.bv_val != a_vals[i].bv_val ) {
    876 				ch_free( a_vals[i].bv_val );
    877 				a_vals[i] = bv;
    878 			}
    879 			break;
    880 		}
    881 	}
    882 
    883 	return 0;
    884 }
    885 
    886 int
    887 ldap_dnattr_result_rewrite(
    888 	dncookie		*dc,
    889 	BerVarray		a_vals
    890 )
    891 {
    892 	struct berval	bv;
    893 	int		i, last;
    894 
    895 	assert( a_vals != NULL );
    896 
    897 	for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
    898 		;
    899 	last--;
    900 
    901 	for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
    902 		switch ( ldap_back_dn_massage( dc, &a_vals[i], &bv ) ) {
    903 		case LDAP_UNWILLING_TO_PERFORM:
    904 			/*
    905 			 * FIXME: need to check if it may be considered
    906 			 * legal to trim values when adding/modifying;
    907 			 * it should be when searching (e.g. ACLs).
    908 			 */
    909 			ber_memfree( a_vals[i].bv_val );
    910 			if ( last > i ) {
    911 				a_vals[i] = a_vals[last];
    912 			}
    913 			BER_BVZERO( &a_vals[last] );
    914 			last--;
    915 			break;
    916 
    917 		default:
    918 			/* leave attr untouched if massage failed */
    919 			if ( !BER_BVISNULL( &bv ) && a_vals[i].bv_val != bv.bv_val ) {
    920 				ber_memfree( a_vals[i].bv_val );
    921 				a_vals[i] = bv;
    922 			}
    923 			break;
    924 		}
    925 	}
    926 
    927 	return 0;
    928 }
    929 
    930