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