]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/rwmmap.c
bd0af8c9418670972513882f594ac64e2abd9d52
[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-2010 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 ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
519                 goto computed;
520         }
521
522         switch ( f->f_choice & SLAPD_FILTER_MASK ) {
523         case LDAP_FILTER_EQUALITY:
524                 ad = f->f_av_desc;
525                 if ( map_attr_value( dc, &ad, &atmp,
526                         &f->f_av_value, &vtmp, RWM_MAP, op->o_tmpmemctx ) )
527                 {
528                         goto computed;
529                 }
530
531                 fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(=)" );
532                 fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
533
534                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
535                         atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
536
537                 op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
538                 break;
539
540         case LDAP_FILTER_GE:
541                 ad = f->f_av_desc;
542                 if ( map_attr_value( dc, &ad, &atmp,
543                         &f->f_av_value, &vtmp, RWM_MAP, op->o_tmpmemctx ) )
544                 {
545                         goto computed;
546                 }
547
548                 fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(>=)" );
549                 fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
550
551                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
552                         atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
553
554                 op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
555                 break;
556
557         case LDAP_FILTER_LE:
558                 ad = f->f_av_desc;
559                 if ( map_attr_value( dc, &ad, &atmp,
560                         &f->f_av_value, &vtmp, RWM_MAP, op->o_tmpmemctx ) )
561                 {
562                         goto computed;
563                 }
564
565                 fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(<=)" );
566                 fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
567
568                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
569                         atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
570
571                 op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
572                 break;
573
574         case LDAP_FILTER_APPROX:
575                 ad = f->f_av_desc;
576                 if ( map_attr_value( dc, &ad, &atmp,
577                         &f->f_av_value, &vtmp, RWM_MAP, op->o_tmpmemctx ) )
578                 {
579                         goto computed;
580                 }
581
582                 fstr->bv_len = atmp.bv_len + vtmp.bv_len + STRLENOF( "(~=)" );
583                 fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
584
585                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
586                         atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
587
588                 op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
589                 break;
590
591         case LDAP_FILTER_SUBSTRINGS:
592                 ad = f->f_sub_desc;
593                 if ( map_attr_value( dc, &ad, &atmp,
594                         NULL, NULL, RWM_MAP, op->o_tmpmemctx ) )
595                 {
596                         goto computed;
597                 }
598
599                 /* cannot be a DN ... */
600
601                 fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" );
602                 fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 128, op->o_tmpmemctx );
603
604                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
605                         atmp.bv_val );
606
607                 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
608                         len = fstr->bv_len;
609
610                         filter_escape_value_x( &f->f_sub_initial, &vtmp, op->o_tmpmemctx );
611
612                         fstr->bv_len += vtmp.bv_len;
613                         fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1,
614                                 op->o_tmpmemctx );
615
616                         snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3,
617                                 /* "(attr=" */ "%s*)",
618                                 vtmp.bv_len ? vtmp.bv_val : "" );
619
620                         op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
621                 }
622
623                 if ( f->f_sub_any != NULL ) {
624                         for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
625                                 len = fstr->bv_len;
626                                 filter_escape_value_x( &f->f_sub_any[i], &vtmp,
627                                         op->o_tmpmemctx );
628
629                                 fstr->bv_len += vtmp.bv_len + 1;
630                                 fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1,
631                                         op->o_tmpmemctx );
632
633                                 snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
634                                         /* "(attr=[init]*[any*]" */ "%s*)",
635                                         vtmp.bv_len ? vtmp.bv_val : "" );
636                                 op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
637                         }
638                 }
639
640                 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
641                         len = fstr->bv_len;
642
643                         filter_escape_value_x( &f->f_sub_final, &vtmp, op->o_tmpmemctx );
644
645                         fstr->bv_len += vtmp.bv_len;
646                         fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1,
647                                 op->o_tmpmemctx );
648
649                         snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
650                                 /* "(attr=[init*][any*]" */ "%s)",
651                                 vtmp.bv_len ? vtmp.bv_val : "" );
652
653                         op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
654                 }
655
656                 break;
657
658         case LDAP_FILTER_PRESENT:
659                 ad = f->f_desc;
660                 if ( map_attr_value( dc, &ad, &atmp,
661                         NULL, NULL, RWM_MAP, op->o_tmpmemctx ) )
662                 {
663                         goto computed;
664                 }
665
666                 fstr->bv_len = atmp.bv_len + STRLENOF( "(=*)" );
667                 fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
668
669                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
670                         atmp.bv_val );
671                 break;
672
673         case LDAP_FILTER_AND:
674         case LDAP_FILTER_OR:
675         case LDAP_FILTER_NOT:
676                 fstr->bv_len = STRLENOF( "(%)" );
677                 fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 128, op->o_tmpmemctx );
678
679                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
680                         f->f_choice == LDAP_FILTER_AND ? '&' :
681                         f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
682
683                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
684                         int     rc;
685
686                         len = fstr->bv_len;
687
688                         rc = rwm_int_filter_map_rewrite( op, dc, p, &vtmp );
689                         if ( rc != LDAP_SUCCESS ) {
690                                 return rc;
691                         }
692                         
693                         fstr->bv_len += vtmp.bv_len;
694                         fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1,
695                                 op->o_tmpmemctx );
696
697                         snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2, 
698                                 /*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" );
699
700                         op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
701                 }
702
703                 break;
704
705         case LDAP_FILTER_EXT: {
706                 if ( f->f_mr_desc ) {
707                         ad = f->f_mr_desc;
708                         if ( map_attr_value( dc, &ad, &atmp,
709                                 &f->f_mr_value, &vtmp, RWM_MAP, op->o_tmpmemctx ) )
710                         {
711                                 goto computed;
712                         }
713
714                 } else {
715                         BER_BVSTR( &atmp, "" );
716                         filter_escape_value_x( &f->f_mr_value, &vtmp, op->o_tmpmemctx );
717                 }
718                         
719
720                 fstr->bv_len = atmp.bv_len +
721                         ( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
722                         ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
723                         vtmp.bv_len + STRLENOF( "(:=)" );
724                 fstr->bv_val = op->o_tmpalloc( fstr->bv_len + 1, op->o_tmpmemctx );
725
726                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
727                         atmp.bv_val,
728                         f->f_mr_dnattrs ? ":dn" : "",
729                         !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
730                         !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
731                         vtmp.bv_len ? vtmp.bv_val : "" );
732                 op->o_tmpfree( vtmp.bv_val, op->o_tmpmemctx );
733                 break;
734         }
735
736         case -1:
737 computed:;
738                 filter_free_x( op, f, 0 );
739                 f->f_choice = SLAPD_FILTER_COMPUTED;
740                 f->f_result = SLAPD_COMPARE_UNDEFINED;
741                 /* fallthru */
742
743         case SLAPD_FILTER_COMPUTED:
744                 switch ( f->f_result ) {
745                 case LDAP_COMPARE_FALSE:
746                 /* FIXME: treat UNDEFINED as FALSE */
747                 case SLAPD_COMPARE_UNDEFINED:
748                         if ( dc->rwmap->rwm_flags & RWM_F_SUPPORT_T_F ) {
749                                 tmp = &ber_bvtf_false;
750                                 break;
751                         }
752                         tmp = &ber_bvfalse;
753                         break;
754
755                 case LDAP_COMPARE_TRUE:
756                         if ( dc->rwmap->rwm_flags & RWM_F_SUPPORT_T_F ) {
757                                 tmp = &ber_bvtf_true;
758                                 break;
759                         }
760                         tmp = &ber_bvtrue;
761                         break;
762                         
763                 default:
764                         tmp = &ber_bverror;
765                         break;
766                 }
767
768                 ber_dupbv_x( fstr, tmp, op->o_tmpmemctx );
769                 break;
770                 
771         default:
772                 ber_dupbv_x( fstr, &ber_bvunknown, op->o_tmpmemctx );
773                 break;
774         }
775
776         return LDAP_SUCCESS;
777 }
778
779 int
780 rwm_filter_map_rewrite(
781         Operation               *op,
782         dncookie                *dc,
783         Filter                  *f,
784         struct berval           *fstr )
785 {
786         int             rc;
787         dncookie        fdc;
788         struct berval   ftmp;
789
790         rc = rwm_int_filter_map_rewrite( op, dc, f, fstr );
791
792         if ( rc != 0 ) {
793                 return rc;
794         }
795
796         fdc = *dc;
797         ftmp = *fstr;
798
799         fdc.ctx = "searchFilter";
800
801         switch ( rewrite_session( fdc.rwmap->rwm_rw, fdc.ctx, 
802                                 ( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : "" ), 
803                                 fdc.conn, &fstr->bv_val ) )
804         {
805         case REWRITE_REGEXEC_OK:
806                 if ( !BER_BVISNULL( fstr ) ) {
807                         fstr->bv_len = strlen( fstr->bv_val );
808
809                 } else {
810                         *fstr = ftmp;
811                 }
812
813                 Debug( LDAP_DEBUG_ARGS,
814                         "[rw] %s: \"%s\" -> \"%s\"\n",
815                         fdc.ctx, ftmp.bv_val, fstr->bv_val );           
816                 if ( fstr->bv_val != ftmp.bv_val ) {
817                         ber_bvreplace_x( &ftmp, fstr, op->o_tmpmemctx );
818                         ch_free( fstr->bv_val );
819                         *fstr = ftmp;
820                 }
821                 rc = LDAP_SUCCESS;
822                 break;
823                 
824         case REWRITE_REGEXEC_UNWILLING:
825                 if ( fdc.rs ) {
826                         fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
827                         fdc.rs->sr_text = "Operation not allowed";
828                 }
829                 op->o_tmpfree( ftmp.bv_val, op->o_tmpmemctx );
830                 rc = LDAP_UNWILLING_TO_PERFORM;
831                 break;
832                 
833         case REWRITE_REGEXEC_ERR:
834                 if ( fdc.rs ) {
835                         fdc.rs->sr_err = LDAP_OTHER;
836                         fdc.rs->sr_text = "Rewrite error";
837                 }
838                 op->o_tmpfree( ftmp.bv_val, op->o_tmpmemctx );
839                 rc = LDAP_OTHER;
840                 break;
841         }
842
843         return rc;
844 }
845
846 /*
847  * I don't like this much, but we need two different
848  * functions because different heap managers may be
849  * in use in back-ldap/meta to reduce the amount of
850  * calls to malloc routines, and some of the free()
851  * routines may be macros with args
852  */
853 int
854 rwm_referral_rewrite(
855         Operation               *op,
856         SlapReply               *rs,
857         void                    *cookie,
858         BerVarray               a_vals,
859         BerVarray               *pa_nvals )
860 {
861         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
862         struct ldaprwmap        *rwmap = 
863                         (struct ldaprwmap *)on->on_bi.bi_private;
864
865         int                     i, last;
866
867         dncookie                dc;
868         struct berval           dn = BER_BVNULL,
869                                 ndn = BER_BVNULL;
870
871         assert( a_vals != NULL );
872
873         /*
874          * Rewrite the dn if needed
875          */
876         dc.rwmap = rwmap;
877         dc.conn = op->o_conn;
878         dc.rs = rs;
879         dc.ctx = (char *)cookie;
880
881         for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
882                 ;
883         last--;
884         
885         if ( pa_nvals != NULL ) {
886                 if ( *pa_nvals == NULL ) {
887                         *pa_nvals = ch_malloc( ( last + 2 ) * sizeof(struct berval) );
888                         memset( *pa_nvals, 0, ( last + 2 ) * sizeof(struct berval) );
889                 }
890         }
891
892         for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
893                 struct berval   olddn = BER_BVNULL,
894                                 oldval;
895                 int             rc;
896                 LDAPURLDesc     *ludp;
897
898                 oldval = a_vals[i];
899                 rc = ldap_url_parse( oldval.bv_val, &ludp );
900                 if ( rc != LDAP_URL_SUCCESS ) {
901                         /* leave attr untouched if massage failed */
902                         if ( pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
903                                 ber_dupbv( &(*pa_nvals)[i], &oldval );
904                         }
905                         continue;
906                 }
907
908                 /* FIXME: URLs like "ldap:///dc=suffix" if passed
909                  * thru ldap_url_parse() and ldap_url_desc2str() 
910                  * get rewritten as "ldap:///dc=suffix??base";
911                  * we don't want this to occur... */
912                 if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
913                         ludp->lud_scope = LDAP_SCOPE_DEFAULT;
914                 }
915
916                 ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
917
918                 dn = olddn;
919                 if ( pa_nvals ) {
920                         ndn = olddn;
921                         rc = rwm_dn_massage_pretty_normalize( &dc, &olddn,
922                                         &dn, &ndn );
923                 } else {
924                         rc = rwm_dn_massage_pretty( &dc, &olddn, &dn );
925                 }
926
927                 switch ( rc ) {
928                 case LDAP_UNWILLING_TO_PERFORM:
929                         /*
930                          * FIXME: need to check if it may be considered 
931                          * legal to trim values when adding/modifying;
932                          * it should be when searching (e.g. ACLs).
933                          */
934                         ch_free( a_vals[i].bv_val );
935                         if (last > i ) {
936                                 a_vals[i] = a_vals[last];
937                                 if ( pa_nvals ) {
938                                         (*pa_nvals)[i] = (*pa_nvals)[last];
939                                 }
940                         }
941                         BER_BVZERO( &a_vals[last] );
942                         if ( pa_nvals ) {
943                                 BER_BVZERO( &(*pa_nvals)[last] );
944                         }
945                         last--;
946                         break;
947                 
948                 case LDAP_SUCCESS:
949                         if ( !BER_BVISNULL( &dn ) && dn.bv_val != olddn.bv_val ) {
950                                 char    *newurl;
951
952                                 ludp->lud_dn = dn.bv_val;
953                                 newurl = ldap_url_desc2str( ludp );
954                                 ludp->lud_dn = olddn.bv_val;
955                                 ch_free( dn.bv_val );
956                                 if ( newurl == NULL ) {
957                                         /* FIXME: leave attr untouched
958                                          * even if ldap_url_desc2str failed...
959                                          */
960                                         break;
961                                 }
962
963                                 ber_str2bv( newurl, 0, 1, &a_vals[i] );
964                                 LDAP_FREE( newurl );
965
966                                 if ( pa_nvals ) {
967                                         ludp->lud_dn = ndn.bv_val;
968                                         newurl = ldap_url_desc2str( ludp );
969                                         ludp->lud_dn = olddn.bv_val;
970                                         ch_free( ndn.bv_val );
971                                         if ( newurl == NULL ) {
972                                                 /* FIXME: leave attr untouched
973                                                  * even if ldap_url_desc2str failed...
974                                                  */
975                                                 ch_free( a_vals[i].bv_val );
976                                                 a_vals[i] = oldval;
977                                                 break;
978                                         }
979
980                                         if ( !BER_BVISNULL( &(*pa_nvals)[i] ) ) {
981                                                 ch_free( (*pa_nvals)[i].bv_val );
982                                         }
983                                         ber_str2bv( newurl, 0, 1, &(*pa_nvals)[i] );
984                                         LDAP_FREE( newurl );
985                                 }
986
987                                 ch_free( oldval.bv_val );
988                                 ludp->lud_dn = olddn.bv_val;
989                         }
990                         break;
991
992                 default:
993                         /* leave attr untouched if massage failed */
994                         if ( pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
995                                 ber_dupbv( &(*pa_nvals)[i], &a_vals[i] );
996                         }
997                         break;
998                 }
999                 ldap_free_urldesc( ludp );
1000         }
1001         
1002         return 0;
1003 }
1004
1005 /*
1006  * I don't like this much, but we need two different
1007  * functions because different heap managers may be
1008  * in use in back-ldap/meta to reduce the amount of
1009  * calls to malloc routines, and some of the free()
1010  * routines may be macros with args
1011  */
1012 int
1013 rwm_dnattr_rewrite(
1014         Operation               *op,
1015         SlapReply               *rs,
1016         void                    *cookie,
1017         BerVarray               a_vals,
1018         BerVarray               *pa_nvals )
1019 {
1020         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1021         struct ldaprwmap        *rwmap = 
1022                         (struct ldaprwmap *)on->on_bi.bi_private;
1023
1024         int                     i, last;
1025
1026         dncookie                dc;
1027         struct berval           dn = BER_BVNULL,
1028                                 ndn = BER_BVNULL;
1029         BerVarray               in;
1030
1031         if ( a_vals ) {
1032                 in = a_vals;
1033
1034         } else {
1035                 if ( pa_nvals == NULL || *pa_nvals == NULL ) {
1036                         return LDAP_OTHER;
1037                 }
1038                 in = *pa_nvals;
1039         }
1040
1041         /*
1042          * Rewrite the dn if needed
1043          */
1044         dc.rwmap = rwmap;
1045         dc.conn = op->o_conn;
1046         dc.rs = rs;
1047         dc.ctx = (char *)cookie;
1048
1049         for ( last = 0; !BER_BVISNULL( &in[last] ); last++ );
1050         last--;
1051         if ( pa_nvals != NULL ) {
1052                 if ( *pa_nvals == NULL ) {
1053                         *pa_nvals = ch_malloc( ( last + 2 ) * sizeof(struct berval) );
1054                         memset( *pa_nvals, 0, ( last + 2 ) * sizeof(struct berval) );
1055                 }
1056         }
1057
1058         for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
1059                 int             rc;
1060
1061                 if ( a_vals ) {
1062                         dn = in[i];
1063                         if ( pa_nvals ) {
1064                                 ndn = (*pa_nvals)[i];
1065                                 rc = rwm_dn_massage_pretty_normalize( &dc, &in[i], &dn, &ndn );
1066                         } else {
1067                                 rc = rwm_dn_massage_pretty( &dc, &in[i], &dn );
1068                         }
1069                 } else {
1070                         ndn = in[i];
1071                         rc = rwm_dn_massage_normalize( &dc, &in[i], &ndn );
1072                 }
1073
1074                 switch ( rc ) {
1075                 case LDAP_UNWILLING_TO_PERFORM:
1076                         /*
1077                          * FIXME: need to check if it may be considered 
1078                          * legal to trim values when adding/modifying;
1079                          * it should be when searching (e.g. ACLs).
1080                          */
1081                         ch_free( in[i].bv_val );
1082                         if (last > i ) {
1083                                 in[i] = in[last];
1084                                 if ( a_vals && pa_nvals ) {
1085                                         (*pa_nvals)[i] = (*pa_nvals)[last];
1086                                 }
1087                         }
1088                         BER_BVZERO( &in[last] );
1089                         if ( a_vals && pa_nvals ) {
1090                                 BER_BVZERO( &(*pa_nvals)[last] );
1091                         }
1092                         last--;
1093                         break;
1094                 
1095                 case LDAP_SUCCESS:
1096                         if ( a_vals ) {
1097                                 if ( !BER_BVISNULL( &dn ) && dn.bv_val != a_vals[i].bv_val ) {
1098                                         ch_free( a_vals[i].bv_val );
1099                                         a_vals[i] = dn;
1100
1101                                         if ( pa_nvals ) {
1102                                                 if ( !BER_BVISNULL( &(*pa_nvals)[i] ) ) {
1103                                                         ch_free( (*pa_nvals)[i].bv_val );
1104                                                 }
1105                                                 (*pa_nvals)[i] = ndn;
1106                                         }
1107                                 }
1108                                 
1109                         } else {
1110                                 if ( !BER_BVISNULL( &ndn ) && ndn.bv_val != (*pa_nvals)[i].bv_val ) {
1111                                         ch_free( (*pa_nvals)[i].bv_val );
1112                                         (*pa_nvals)[i] = ndn;
1113                                 }
1114                         }
1115                         break;
1116
1117                 default:
1118                         /* leave attr untouched if massage failed */
1119                         if ( a_vals && pa_nvals && BER_BVISNULL( &(*pa_nvals)[i] ) ) {
1120                                 dnNormalize( 0, NULL, NULL, &a_vals[i], &(*pa_nvals)[i], NULL );
1121                         }
1122                         break;
1123                 }
1124         }
1125         
1126         return 0;
1127 }
1128
1129 int
1130 rwm_referral_result_rewrite(
1131         dncookie                *dc,
1132         BerVarray               a_vals )
1133 {
1134         int             i, last;
1135
1136         for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ );
1137         last--;
1138
1139         for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
1140                 struct berval   dn,
1141                                 olddn = BER_BVNULL;
1142                 int             rc;
1143                 LDAPURLDesc     *ludp;
1144
1145                 rc = ldap_url_parse( a_vals[i].bv_val, &ludp );
1146                 if ( rc != LDAP_URL_SUCCESS ) {
1147                         /* leave attr untouched if massage failed */
1148                         continue;
1149                 }
1150
1151                 /* FIXME: URLs like "ldap:///dc=suffix" if passed
1152                  * thru ldap_url_parse() and ldap_url_desc2str()
1153                  * get rewritten as "ldap:///dc=suffix??base";
1154                  * we don't want this to occur... */
1155                 if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
1156                         ludp->lud_scope = LDAP_SCOPE_DEFAULT;
1157                 }
1158
1159                 ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
1160
1161                 dn = olddn;
1162                 rc = rwm_dn_massage_pretty( dc, &olddn, &dn );
1163                 switch ( rc ) {
1164                 case LDAP_UNWILLING_TO_PERFORM:
1165                         /*
1166                          * FIXME: need to check if it may be considered 
1167                          * legal to trim values when adding/modifying;
1168                          * it should be when searching (e.g. ACLs).
1169                          */
1170                         ch_free( a_vals[i].bv_val );
1171                         if ( last > i ) {
1172                                 a_vals[i] = a_vals[last];
1173                         }
1174                         BER_BVZERO( &a_vals[last] );
1175                         last--;
1176                         i--;
1177                         break;
1178
1179                 default:
1180                         /* leave attr untouched if massage failed */
1181                         if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val ) {
1182                                 char    *newurl;
1183
1184                                 ludp->lud_dn = dn.bv_val;
1185                                 newurl = ldap_url_desc2str( ludp );
1186                                 if ( newurl == NULL ) {
1187                                         /* FIXME: leave attr untouched
1188                                          * even if ldap_url_desc2str failed...
1189                                          */
1190                                         break;
1191                                 }
1192
1193                                 ch_free( a_vals[i].bv_val );
1194                                 ber_str2bv( newurl, 0, 1, &a_vals[i] );
1195                                 LDAP_FREE( newurl );
1196                                 ludp->lud_dn = olddn.bv_val;
1197                         }
1198                         break;
1199                 }
1200
1201                 ldap_free_urldesc( ludp );
1202         }
1203
1204         return 0;
1205 }
1206
1207 int
1208 rwm_dnattr_result_rewrite(
1209         dncookie                *dc,
1210         BerVarray               a_vals,
1211         BerVarray               a_nvals )
1212 {
1213         int             i, last;
1214
1215         for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ );
1216         last--;
1217
1218         for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
1219                 struct berval   pdn, ndn = BER_BVNULL;
1220                 int             rc;
1221                 
1222                 pdn = a_vals[i];
1223                 rc = rwm_dn_massage_pretty_normalize( dc, &a_vals[i], &pdn, &ndn );
1224                 switch ( rc ) {
1225                 case LDAP_UNWILLING_TO_PERFORM:
1226                         /*
1227                          * FIXME: need to check if it may be considered 
1228                          * legal to trim values when adding/modifying;
1229                          * it should be when searching (e.g. ACLs).
1230                          */
1231                         assert( a_vals[i].bv_val != a_nvals[i].bv_val );
1232                         ch_free( a_vals[i].bv_val );
1233                         ch_free( a_nvals[i].bv_val );
1234                         if ( last > i ) {
1235                                 a_vals[i] = a_vals[last];
1236                                 a_nvals[i] = a_nvals[last];
1237                         }
1238                         BER_BVZERO( &a_vals[last] );
1239                         BER_BVZERO( &a_nvals[last] );
1240                         last--;
1241                         break;
1242
1243                 default:
1244                         /* leave attr untouched if massage failed */
1245                         if ( !BER_BVISNULL( &pdn ) && a_vals[i].bv_val != pdn.bv_val ) {
1246                                 ch_free( a_vals[i].bv_val );
1247                                 a_vals[i] = pdn;
1248                         }
1249                         if ( !BER_BVISNULL( &ndn ) && a_nvals[i].bv_val != ndn.bv_val ) {
1250                                 ch_free( a_nvals[i].bv_val );
1251                                 a_nvals[i] = ndn;
1252                         }
1253                         break;
1254                 }
1255         }
1256
1257         return 0;
1258 }
1259
1260 void
1261 rwm_mapping_dst_free( void *v_mapping )
1262 {
1263         struct ldapmapping *mapping = v_mapping;
1264
1265         if ( BER_BVISEMPTY( &mapping[0].m_dst ) ) {
1266                 rwm_mapping_free( &mapping[ -1 ] );
1267         }
1268 }
1269
1270 void
1271 rwm_mapping_free( void *v_mapping )
1272 {
1273         struct ldapmapping *mapping = v_mapping;
1274
1275         if ( !BER_BVISNULL( &mapping[0].m_src ) ) {
1276                 ch_free( mapping[0].m_src.bv_val );
1277         }
1278
1279         if ( mapping[0].m_flags & RWMMAP_F_FREE_SRC ) {
1280                 if ( mapping[0].m_flags & RWMMAP_F_IS_OC ) {
1281                         if ( mapping[0].m_src_oc ) {
1282                                 ch_free( mapping[0].m_src_oc );
1283                         }
1284
1285                 } else {
1286                         if ( mapping[0].m_src_ad ) {
1287                                 ch_free( mapping[0].m_src_ad );
1288                         }
1289                 }
1290         }
1291
1292         if ( !BER_BVISNULL( &mapping[0].m_dst ) ) {
1293                 ch_free( mapping[0].m_dst.bv_val );
1294         }
1295
1296         if ( mapping[0].m_flags & RWMMAP_F_FREE_DST ) {
1297                 if ( mapping[0].m_flags & RWMMAP_F_IS_OC ) {
1298                         if ( mapping[0].m_dst_oc ) {
1299                                 ch_free( mapping[0].m_dst_oc );
1300                         }
1301
1302                 } else {
1303                         if ( mapping[0].m_dst_ad ) {
1304                                 ch_free( mapping[0].m_dst_ad );
1305                         }
1306                 }
1307         }
1308
1309         ch_free( mapping );
1310
1311 }
1312
1313 #endif /* SLAPD_OVER_RWM */