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