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