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