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