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