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