]> git.sur5r.net Git - openldap/blob - servers/slapd/back-asyncmeta/map.c
Happy New Year
[openldap] / servers / slapd / back-asyncmeta / map.c
1 /* map.c - ldap backend mapping routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2016-2018 The OpenLDAP Foundation.
6  * Portions Copyright 2016 Symas Corporation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17
18 /* ACKNOWLEDGEMENTS:
19  * This work was developed by Symas Corporation
20  * based on back-meta module for inclusion in OpenLDAP Software.
21  * This work was sponsored by Ericsson. */
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 2016, Symas Corporation
47  *
48  * This is based on the back-meta/map.c version by Pierangelo Masarati.
49  * The previously reported conditions apply to the modified code as well.
50  * Changes in the original code are highlighted where required.
51  * Credits for the original code go to the author, Howard Chu.
52  */
53
54 #include "portable.h"
55
56 #include <stdio.h>
57
58 #include <ac/string.h>
59 #include <ac/socket.h>
60
61 #include "slap.h"
62 #include "lutil.h"
63 #include "../back-ldap/back-ldap.h"
64 #include "back-asyncmeta.h"
65
66 int
67 asyncmeta_mapping_cmp ( const void *c1, const void *c2 )
68 {
69         struct ldapmapping *map1 = (struct ldapmapping *)c1;
70         struct ldapmapping *map2 = (struct ldapmapping *)c2;
71         int rc = map1->src.bv_len - map2->src.bv_len;
72         if (rc) return rc;
73         return ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) );
74 }
75
76 int
77 asyncmeta_mapping_dup ( void *c1, void *c2 )
78 {
79         struct ldapmapping *map1 = (struct ldapmapping *)c1;
80         struct ldapmapping *map2 = (struct ldapmapping *)c2;
81
82         return ( ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) == 0 ) ? -1 : 0 );
83 }
84
85 void
86 asyncmeta_map_init ( struct ldapmap *lm, struct ldapmapping **m )
87 {
88         struct ldapmapping *mapping;
89
90         assert( m != NULL );
91
92         *m = NULL;
93
94         mapping = (struct ldapmapping *)ch_calloc( 2,
95                         sizeof( struct ldapmapping ) );
96         if ( mapping == NULL ) {
97                 return;
98         }
99
100         ber_str2bv( "objectclass", STRLENOF("objectclass"), 1, &mapping[0].src);
101         ber_dupbv( &mapping[0].dst, &mapping[0].src );
102         mapping[1].src = mapping[0].src;
103         mapping[1].dst = mapping[0].dst;
104
105         avl_insert( &lm->map, (caddr_t)&mapping[0],
106                         asyncmeta_mapping_cmp, asyncmeta_mapping_dup );
107         avl_insert( &lm->remap, (caddr_t)&mapping[1],
108                         asyncmeta_mapping_cmp, asyncmeta_mapping_dup );
109         *m = mapping;
110 }
111
112 int
113 asyncmeta_mapping ( struct ldapmap *map, struct berval *s, struct ldapmapping **m,
114         int remap )
115 {
116         Avlnode *tree;
117         struct ldapmapping fmapping;
118
119         assert( m != NULL );
120
121         /* let special attrnames slip through (ITS#5760) */
122         if ( bvmatch( s, slap_bv_no_attrs )
123                 || bvmatch( s, slap_bv_all_user_attrs )
124                 || bvmatch( s, slap_bv_all_operational_attrs ) )
125         {
126                 *m = NULL;
127                 return 0;
128         }
129
130         if ( remap == BACKLDAP_REMAP ) {
131                 tree = map->remap;
132
133         } else {
134                 tree = map->map;
135         }
136
137         fmapping.src = *s;
138         *m = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping, asyncmeta_mapping_cmp );
139         if ( *m == NULL ) {
140                 return map->drop_missing;
141         }
142
143         return 0;
144 }
145
146 void
147 asyncmeta_map ( struct ldapmap *map, struct berval *s, struct berval *bv,
148         int remap )
149 {
150         struct ldapmapping *mapping;
151         int drop_missing;
152
153         /* map->map may be NULL when mapping is configured,
154          * but map->remap can't */
155         if ( map->remap == NULL ) {
156                 *bv = *s;
157                 return;
158         }
159
160         BER_BVZERO( bv );
161         drop_missing = asyncmeta_mapping( map, s, &mapping, remap );
162         if ( mapping != NULL ) {
163                 if ( !BER_BVISNULL( &mapping->dst ) ) {
164                         *bv = mapping->dst;
165                 }
166                 return;
167         }
168
169         if ( !drop_missing ) {
170                 *bv = *s;
171         }
172 }
173
174 int
175 asyncmeta_map_attrs(
176                 Operation *op,
177                 struct ldapmap *at_map,
178                 AttributeName *an,
179                 int remap,
180                 char ***mapped_attrs )
181 {
182         int i, x, j;
183         char **na;
184         struct berval mapped;
185
186         if ( an == NULL && op->o_bd->be_extra_anlist == NULL ) {
187                 *mapped_attrs = NULL;
188                 return LDAP_SUCCESS;
189         }
190
191         i = 0;
192         if ( an != NULL ) {
193                 for ( ; !BER_BVISNULL( &an[i].an_name ); i++ )
194                         /*  */ ;
195         }
196
197         x = 0;
198         if ( op->o_bd->be_extra_anlist != NULL ) {
199                 for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ )
200                         /*  */ ;
201         }
202
203         assert( i > 0 || x > 0 );
204
205         na = (char **)ber_memcalloc_x( i + x + 1, sizeof(char *), op->o_tmpmemctx );
206         if ( na == NULL ) {
207                 *mapped_attrs = NULL;
208                 return LDAP_NO_MEMORY;
209         }
210
211         j = 0;
212         if ( i > 0 ) {
213                 for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
214                         asyncmeta_map( at_map, &an[i].an_name, &mapped, remap );
215                         if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) {
216                                 na[j++] = mapped.bv_val;
217                         }
218                 }
219         }
220
221         if ( x > 0 ) {
222                 for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) {
223                         if ( op->o_bd->be_extra_anlist[x].an_desc &&
224                                 ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, an ) )
225                         {
226                                 continue;
227                         }
228
229                         asyncmeta_map( at_map, &op->o_bd->be_extra_anlist[x].an_name, &mapped, remap );
230                         if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) {
231                                 na[j++] = mapped.bv_val;
232                         }
233                 }
234         }
235
236         if ( j == 0 && ( i > 0 || x > 0 ) ) {
237                 na[j++] = LDAP_NO_ATTRS;
238         }
239         na[j] = NULL;
240
241         *mapped_attrs = na;
242
243         return LDAP_SUCCESS;
244 }
245
246 static int
247 map_attr_value(
248                 a_dncookie              *dc,
249                 AttributeDescription    *ad,
250                 struct berval           *mapped_attr,
251                 struct berval           *value,
252                 struct berval           *mapped_value,
253                 int                     remap,
254                 void                    *memctx )
255 {
256         struct berval           vtmp;
257         int                     freeval = 0;
258
259         asyncmeta_map( &dc->target->mt_rwmap.rwm_at, &ad->ad_cname, mapped_attr, remap );
260         if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
261 #if 0
262                 /*
263                  * FIXME: are we sure we need to search oc_map if at_map fails?
264                  */
265                 asyncmeta_map( &dc->target->mt_rwmap.rwm_oc, &ad->ad_cname, mapped_attr, remap );
266                 if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
267                         *mapped_attr = ad->ad_cname;
268                 }
269 #endif
270                 if ( dc->target->mt_rwmap.rwm_at.drop_missing ) {
271                         return -1;
272                 }
273
274                 *mapped_attr = ad->ad_cname;
275         }
276
277         if ( value == NULL ) {
278                 return 0;
279         }
280
281         if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
282         {
283                 a_dncookie fdc = *dc;
284
285                 fdc.ctx = "searchFilterAttrDN";
286
287                 switch ( asyncmeta_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                 asyncmeta_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
336 static int
337 asyncmeta_int_filter_map_rewrite(
338                 a_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 = asyncmeta_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:
582 computed:;
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
621 int
622 asyncmeta_filter_map_rewrite(
623                 a_dncookie              *dc,
624                 Filter                  *f,
625                 struct berval   *fstr,
626                 int                             remap,
627                 void                    *memctx )
628 {
629         int             rc;
630         a_dncookie      fdc;
631         struct berval   ftmp;
632         static char     *dmy = "";
633
634         rc = asyncmeta_int_filter_map_rewrite( dc, f, fstr, remap, memctx );
635
636         if ( rc != LDAP_SUCCESS ) {
637                 return rc;
638         }
639
640         fdc = *dc;
641         ftmp = *fstr;
642
643         fdc.ctx = "searchFilter";
644
645         switch ( rewrite_session( fdc.target->mt_rwmap.rwm_rw, fdc.ctx,
646                                 ( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : dmy ),
647                                 fdc.conn, &fstr->bv_val ) )
648         {
649         case REWRITE_REGEXEC_OK:
650                 if ( !BER_BVISNULL( fstr ) ) {
651                         fstr->bv_len = strlen( fstr->bv_val );
652
653                 } else {
654                         *fstr = ftmp;
655                 }
656                 Debug( LDAP_DEBUG_ARGS,
657                         "[rw] %s: \"%s\" -> \"%s\"\n",
658                         fdc.ctx, BER_BVISNULL( &ftmp ) ? "" : ftmp.bv_val,
659                         BER_BVISNULL( fstr ) ? "" : fstr->bv_val );
660                 rc = LDAP_SUCCESS;
661                 break;
662
663         case REWRITE_REGEXEC_UNWILLING:
664                 if ( fdc.rs ) {
665                         fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
666                         fdc.rs->sr_text = "Operation not allowed";
667                 }
668                 rc = LDAP_UNWILLING_TO_PERFORM;
669                 break;
670
671         case REWRITE_REGEXEC_ERR:
672                 if ( fdc.rs ) {
673                         fdc.rs->sr_err = LDAP_OTHER;
674                         fdc.rs->sr_text = "Rewrite error";
675                 }
676                 rc = LDAP_OTHER;
677                 break;
678         }
679
680         if ( fstr->bv_val == dmy ) {
681                 BER_BVZERO( fstr );
682
683         } else if ( fstr->bv_val != ftmp.bv_val ) {
684                 /* NOTE: need to realloc mapped filter on slab
685                  * and free the original one, until librewrite
686                  * becomes slab-aware
687                  */
688                 ber_dupbv_x( &ftmp, fstr, memctx );
689                 ch_free( fstr->bv_val );
690                 *fstr = ftmp;
691         }
692
693         return rc;
694 }
695
696 int
697 asyncmeta_referral_result_rewrite(
698         a_dncookie              *dc,
699         BerVarray               a_vals,
700         void                    *memctx
701 )
702 {
703         int             i, last;
704
705         assert( dc != NULL );
706         assert( a_vals != NULL );
707
708         for ( last = 0; !BER_BVISNULL( &a_vals[ last ] ); last++ )
709                 ;
710         last--;
711
712         for ( i = 0; !BER_BVISNULL( &a_vals[ i ] ); i++ ) {
713                 struct berval   dn,
714                                 olddn = BER_BVNULL;
715                 int             rc;
716                 LDAPURLDesc     *ludp;
717
718                 rc = ldap_url_parse( a_vals[ i ].bv_val, &ludp );
719                 if ( rc != LDAP_URL_SUCCESS ) {
720                         /* leave attr untouched if massage failed */
721                         continue;
722                 }
723
724                 /* FIXME: URLs like "ldap:///dc=suffix" if passed
725                  * thru ldap_url_parse() and ldap_url_desc2str()
726                  * get rewritten as "ldap:///dc=suffix??base";
727                  * we don't want this to occur... */
728                 if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
729                         ludp->lud_scope = LDAP_SCOPE_DEFAULT;
730                 }
731
732                 ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
733
734                 rc = asyncmeta_dn_massage( dc, &olddn, &dn );
735                 switch ( rc ) {
736                 case LDAP_UNWILLING_TO_PERFORM:
737                         /*
738                          * FIXME: need to check if it may be considered
739                          * legal to trim values when adding/modifying;
740                          * it should be when searching (e.g. ACLs).
741                          */
742                         ber_memfree( a_vals[ i ].bv_val );
743                         if ( last > i ) {
744                                 a_vals[ i ] = a_vals[ last ];
745                         }
746                         BER_BVZERO( &a_vals[ last ] );
747                         last--;
748                         i--;
749                         break;
750
751                 default:
752                         /* leave attr untouched if massage failed */
753                         if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val )
754                         {
755                                 char    *newurl;
756
757                                 ludp->lud_dn = dn.bv_val;
758                                 newurl = ldap_url_desc2str( ludp );
759                                 free( dn.bv_val );
760                                 if ( newurl == NULL ) {
761                                         /* FIXME: leave attr untouched
762                                          * even if ldap_url_desc2str failed...
763                                          */
764                                         break;
765                                 }
766
767                                 ber_memfree_x( a_vals[ i ].bv_val, memctx );
768                                 ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], memctx );
769                                 ber_memfree( newurl );
770                                 ludp->lud_dn = olddn.bv_val;
771                         }
772                         break;
773                 }
774
775                 ldap_free_urldesc( ludp );
776         }
777
778         return 0;
779 }
780
781 /*
782  * I don't like this much, but we need two different
783  * functions because different heap managers may be
784  * in use in back-ldap/meta to reduce the amount of
785  * calls to malloc routines, and some of the free()
786  * routines may be macros with args
787  */
788 int
789 asyncmeta_dnattr_rewrite(
790         a_dncookie              *dc,
791         BerVarray               a_vals
792 )
793 {
794         struct berval   bv;
795         int             i, last;
796
797         assert( a_vals != NULL );
798
799         for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
800                 ;
801         last--;
802
803         for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
804                 switch ( asyncmeta_dn_massage( dc, &a_vals[i], &bv ) ) {
805                 case LDAP_UNWILLING_TO_PERFORM:
806                         /*
807                          * FIXME: need to check if it may be considered
808                          * legal to trim values when adding/modifying;
809                          * it should be when searching (e.g. ACLs).
810                          */
811                         ch_free( a_vals[i].bv_val );
812                         if ( last > i ) {
813                                 a_vals[i] = a_vals[last];
814                         }
815                         BER_BVZERO( &a_vals[last] );
816                         last--;
817                         break;
818
819                 default:
820                         /* leave attr untouched if massage failed */
821                         if ( !BER_BVISNULL( &bv ) && bv.bv_val != a_vals[i].bv_val ) {
822                                 ch_free( a_vals[i].bv_val );
823                                 a_vals[i] = bv;
824                         }
825                         break;
826                 }
827         }
828
829         return 0;
830 }
831
832 int
833 asyncmeta_dnattr_result_rewrite(
834         a_dncookie              *dc,
835         BerVarray               a_vals
836 )
837 {
838         struct berval   bv;
839         int             i, last;
840
841         assert( a_vals != NULL );
842
843         for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
844                 ;
845         last--;
846
847         for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
848                 switch ( asyncmeta_dn_massage( dc, &a_vals[i], &bv ) ) {
849                 case LDAP_UNWILLING_TO_PERFORM:
850                         /*
851                          * FIXME: need to check if it may be considered
852                          * legal to trim values when adding/modifying;
853                          * it should be when searching (e.g. ACLs).
854                          */
855                         ber_memfree( a_vals[i].bv_val );
856                         if ( last > i ) {
857                                 a_vals[i] = a_vals[last];
858                         }
859                         BER_BVZERO( &a_vals[last] );
860                         last--;
861                         break;
862
863                 default:
864                         /* leave attr untouched if massage failed */
865                         if ( !BER_BVISNULL( &bv ) && a_vals[i].bv_val != bv.bv_val ) {
866                                 ber_memfree( a_vals[i].bv_val );
867                                 a_vals[i] = bv;
868                         }
869                         break;
870                 }
871         }
872
873         return 0;
874 }