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