xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/overlays/rwmmap.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: rwmmap.c,v 1.3 2021/08/14 16:15:02 christos 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-2021 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.3 2021/08/14 16:15:02 christos 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
rwm_mapping_cmp(const void * c1,const void * c2)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
rwm_mapping_dup(void * c1,void * c2)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
rwm_map_init(struct ldapmap * lm,struct ldapmapping ** m)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 	ldap_avl_insert( &lm->map, (caddr_t)&mapping[0],
108 			rwm_mapping_cmp, rwm_mapping_dup );
109 	ldap_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
rwm_mapping(struct ldapmap * map,struct berval * s,struct ldapmapping ** m,int remap)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 *)ldap_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
rwm_map(struct ldapmap * map,struct berval * s,struct berval * bv,int remap)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
rwm_map_attrnames(Operation * op,struct ldapmap * at_map,struct ldapmap * oc_map,AttributeName * an,AttributeName ** anp,int remap)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
map_attr_value(dncookie * dc,AttributeDescription ** adp,struct berval * mapped_attr,struct berval * value,struct berval * mapped_value,int remap,void * memctx)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
rwm_int_filter_map_rewrite(Operation * op,dncookie * dc,Filter * f,struct berval * fstr)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, ftmp;
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 		f = &ftmp;
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
rwm_filter_map_rewrite(Operation * op,dncookie * dc,Filter * f,struct berval * fstr)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
rwm_referral_rewrite(Operation * op,SlapReply * rs,void * cookie,BerVarray a_vals,BerVarray * pa_nvals)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
rwm_dnattr_rewrite(Operation * op,SlapReply * rs,void * cookie,BerVarray a_vals,BerVarray * pa_nvals)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
rwm_referral_result_rewrite(dncookie * dc,BerVarray a_vals)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
rwm_dnattr_result_rewrite(dncookie * dc,BerVarray a_vals,BerVarray a_nvals)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
rwm_mapping_dst_free(void * v_mapping)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
rwm_mapping_free(void * v_mapping)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