]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/rwmmap.c
cleanup rwm overlay; init/destroy session cookie; strip (optional) leading 'rwm-...
[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-2004 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         if ( rc ) {
46                 return rc;
47         }
48         return strcasecmp( map1->m_src.bv_val, map2->m_src.bv_val );
49 }
50
51 int
52 rwm_mapping_dup( void *c1, void *c2 )
53 {
54         struct ldapmapping *map1 = (struct ldapmapping *)c1;
55         struct ldapmapping *map2 = (struct ldapmapping *)c2;
56         int rc = map1->m_src.bv_len - map2->m_src.bv_len;
57
58         if ( rc ) {
59                 return 0;
60         }
61
62         return ( ( strcasecmp( map1->m_src.bv_val, map2->m_src.bv_val ) == 0 ) ? -1 : 0 );
63 }
64
65 void
66 rwm_map_init( struct ldapmap *lm, struct ldapmapping **m )
67 {
68         struct ldapmapping *mapping;
69
70         assert( m );
71
72         *m = NULL;
73         
74         mapping = (struct ldapmapping *)ch_calloc( 2, 
75                         sizeof( struct ldapmapping ) );
76         if ( mapping == NULL ) {
77                 return;
78         }
79
80         ber_str2bv( "objectClass", sizeof("objectClass") - 1, 1,
81                         &mapping->m_src);
82         ber_dupbv( &mapping->m_dst, &mapping->m_src );
83         mapping[1].m_src = mapping->m_src;
84         mapping[1].m_dst = mapping->m_dst;
85
86         avl_insert( &lm->map, (caddr_t)mapping, 
87                         rwm_mapping_cmp, rwm_mapping_dup );
88         avl_insert( &lm->remap, (caddr_t)&mapping[1], 
89                         rwm_mapping_cmp, rwm_mapping_dup );
90         *m = mapping;
91 }
92
93 void
94 rwm_map( struct ldapmap *map, struct berval *s, struct berval *bv, int remap )
95 {
96         Avlnode *tree;
97         struct ldapmapping *mapping, fmapping;
98
99         if (remap == RWM_REMAP) {
100                 tree = map->remap;
101         } else {
102                 tree = map->map;
103         }
104
105         bv->bv_len = 0;
106         bv->bv_val = NULL;
107         fmapping.m_src = *s;
108         mapping = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping,
109                         rwm_mapping_cmp );
110         if ( mapping != NULL ) {
111                 if ( mapping->m_dst.bv_val ) {
112                         *bv = mapping->m_dst;
113                 }
114                 return;
115         }
116
117         if ( !map->drop_missing ) {
118                 *bv = *s;
119         }
120
121         return;
122 }
123
124 int
125 rwm_map_attrs(
126                 struct ldapmap *at_map,
127                 AttributeName *an,
128                 int remap,
129                 char ***mapped_attrs
130 )
131 {
132         int i, j;
133         char **na;
134         struct berval mapped;
135
136         if ( an == NULL ) {
137                 *mapped_attrs = NULL;
138                 return LDAP_SUCCESS;
139         }
140
141         for ( i = 0; an[i].an_name.bv_val; i++ ) {
142                 /*  */
143         }
144
145         na = (char **)ch_calloc( i + 1, sizeof( char * ) );
146         if (na == NULL) {
147                 *mapped_attrs = NULL;
148                 return LDAP_NO_MEMORY;
149         }
150
151         for ( i = j = 0; an[i].an_name.bv_val; i++ ) {
152                 rwm_map( at_map, &an[i].an_name, &mapped, remap );
153                 if ( mapped.bv_val != NULL && mapped.bv_val != '\0' ) {
154                         na[j++] = mapped.bv_val;
155                 }
156         }
157         if ( j == 0 && i != 0 ) {
158                 na[j++] = LDAP_NO_ATTRS;
159         }
160         na[j] = NULL;
161
162         *mapped_attrs = na;
163         return LDAP_SUCCESS;
164 }
165
166 static int
167 map_attr_value(
168                 dncookie                *dc,
169                 AttributeDescription    *ad,
170                 struct berval           *mapped_attr,
171                 struct berval           *value,
172                 struct berval           *mapped_value,
173                 int                     remap )
174 {
175         struct berval           vtmp;
176         int                     freeval = 0;
177
178         rwm_map( &dc->rwmap->rwm_at, &ad->ad_cname, mapped_attr, remap );
179         if ( mapped_attr->bv_val == NULL || mapped_attr->bv_val[0] == '\0') {
180                 /*
181                  * FIXME: are we sure we need to search oc_map if at_map fails?
182                  */
183                 rwm_map( &dc->rwmap->rwm_oc, &ad->ad_cname, mapped_attr,
184                                 remap );
185                 if ( mapped_attr->bv_val == NULL
186                                 || mapped_attr->bv_val[0] == '\0' )
187                 {
188                         *mapped_attr = ad->ad_cname;
189                 }
190         }
191
192         if ( value == NULL ) {
193                 return 0;
194         }
195
196         if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
197         {
198                 dncookie fdc = *dc;
199
200 #ifdef ENABLE_REWRITE
201                 fdc.ctx = "searchFilterAttrDN";
202 #endif
203
204                 switch ( rwm_dn_massage( &fdc, value, &vtmp ) ) {
205                 case LDAP_SUCCESS:
206                         if ( vtmp.bv_val != value->bv_val ) {
207                                 freeval = 1;
208                         }
209                         break;
210                 
211                 case LDAP_UNWILLING_TO_PERFORM:
212                         return -1;
213
214                 case LDAP_OTHER:
215                         return -1;
216                 }
217
218         } else if ( ad == slap_schema.si_ad_objectClass
219                         || ad == slap_schema.si_ad_structuralObjectClass )
220         {
221                 rwm_map( &dc->rwmap->rwm_oc, value, &vtmp, remap );
222                 if ( vtmp.bv_val == NULL || vtmp.bv_val[0] == '\0' ) {
223                         vtmp = *value;
224                 }
225                 
226         } else {
227                 vtmp = *value;
228         }
229
230         filter_escape_value( &vtmp, mapped_value );
231
232         if ( freeval ) {
233                 ber_memfree( vtmp.bv_val );
234         }
235         
236         return 0;
237 }
238
239 static int
240 rwm_int_filter_map_rewrite(
241                 dncookie                *dc,
242                 Filter                  *f,
243                 struct berval           *fstr,
244                 int                     remap )
245 {
246         int             i;
247         Filter          *p;
248         struct berval   atmp,
249                         vtmp,
250                         tmp;
251         static struct berval
252                         ber_bvfalse = BER_BVC( "(?=false)" ),
253                         ber_bvtrue = BER_BVC( "(?=true)" ),
254                         ber_bvundefined = BER_BVC( "(?=undefined)" ),
255                         ber_bverror = BER_BVC( "(?=error)" ),
256                         ber_bvunknown = BER_BVC( "(?=unknown)" ),
257                         ber_bvnone = BER_BVC( "(?=none)" );
258         ber_len_t       len;
259
260         if ( f == NULL ) {
261                 ber_dupbv( fstr, &ber_bvnone );
262                 return -1;
263         }
264
265         switch ( f->f_choice ) {
266         case LDAP_FILTER_EQUALITY:
267                 if ( map_attr_value( dc, f->f_av_desc, &atmp,
268                                         &f->f_av_value, &vtmp, remap ) )
269                 {
270                         return -1;
271                 }
272
273                 fstr->bv_len = atmp.bv_len + vtmp.bv_len
274                         + ( sizeof( "(=)" ) - 1 );
275                 fstr->bv_val = malloc( fstr->bv_len + 1 );
276
277                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
278                         atmp.bv_val, vtmp.bv_val );
279
280                 ber_memfree( vtmp.bv_val );
281                 break;
282
283         case LDAP_FILTER_GE:
284                 if ( map_attr_value( dc, f->f_av_desc, &atmp,
285                                         &f->f_av_value, &vtmp, remap ) )
286                 {
287                         return -1;
288                 }
289
290                 fstr->bv_len = atmp.bv_len + vtmp.bv_len
291                         + ( sizeof( "(>=)" ) - 1 );
292                 fstr->bv_val = malloc( fstr->bv_len + 1 );
293
294                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
295                         atmp.bv_val, vtmp.bv_val );
296
297                 ber_memfree( vtmp.bv_val );
298                 break;
299
300         case LDAP_FILTER_LE:
301                 if ( map_attr_value( dc, f->f_av_desc, &atmp,
302                                         &f->f_av_value, &vtmp, remap ) )
303                 {
304                         return -1;
305                 }
306
307                 fstr->bv_len = atmp.bv_len + vtmp.bv_len
308                         + ( sizeof( "(<=)" ) - 1 );
309                 fstr->bv_val = malloc( fstr->bv_len + 1 );
310
311                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
312                         atmp.bv_val, vtmp.bv_val );
313
314                 ber_memfree( vtmp.bv_val );
315                 break;
316
317         case LDAP_FILTER_APPROX:
318                 if ( map_attr_value( dc, f->f_av_desc, &atmp,
319                                         &f->f_av_value, &vtmp, remap ) )
320                 {
321                         return -1;
322                 }
323
324                 fstr->bv_len = atmp.bv_len + vtmp.bv_len
325                         + ( sizeof( "(~=)" ) - 1 );
326                 fstr->bv_val = malloc( fstr->bv_len + 1 );
327
328                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
329                         atmp.bv_val, vtmp.bv_val );
330
331                 ber_memfree( vtmp.bv_val );
332                 break;
333
334         case LDAP_FILTER_SUBSTRINGS:
335                 if ( map_attr_value( dc, f->f_sub_desc, &atmp,
336                                         NULL, NULL, remap ) )
337                 {
338                         return -1;
339                 }
340
341                 /* cannot be a DN ... */
342
343                 fstr->bv_len = atmp.bv_len + ( sizeof( "(=*)" ) - 1 );
344                 fstr->bv_val = malloc( fstr->bv_len + 128 );
345
346                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
347                         atmp.bv_val );
348
349                 if ( f->f_sub_initial.bv_val != NULL ) {
350                         len = fstr->bv_len;
351
352                         filter_escape_value( &f->f_sub_initial, &vtmp );
353
354                         fstr->bv_len += vtmp.bv_len;
355                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
356
357                         snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3,
358                                 /* "(attr=" */ "%s*)",
359                                 vtmp.bv_val );
360
361                         ber_memfree( vtmp.bv_val );
362                 }
363
364                 if ( f->f_sub_any != NULL ) {
365                         for ( i = 0; f->f_sub_any[i].bv_val != NULL; i++ ) {
366                                 len = fstr->bv_len;
367                                 filter_escape_value( &f->f_sub_any[i], &vtmp );
368
369                                 fstr->bv_len += vtmp.bv_len + 1;
370                                 fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
371
372                                 snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
373                                         /* "(attr=[init]*[any*]" */ "%s*)",
374                                         vtmp.bv_val );
375                                 ber_memfree( vtmp.bv_val );
376                         }
377                 }
378
379                 if ( f->f_sub_final.bv_val != NULL ) {
380                         len = fstr->bv_len;
381
382                         filter_escape_value( &f->f_sub_final, &vtmp );
383
384                         fstr->bv_len += vtmp.bv_len;
385                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
386
387                         snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
388                                 /* "(attr=[init*][any*]" */ "%s)",
389                                 vtmp.bv_val );
390
391                         ber_memfree( vtmp.bv_val );
392                 }
393
394                 break;
395
396         case LDAP_FILTER_PRESENT:
397                 if ( map_attr_value( dc, f->f_desc, &atmp,
398                                         NULL, NULL, remap ) )
399                 {
400                         return -1;
401                 }
402
403                 fstr->bv_len = atmp.bv_len + ( sizeof( "(=*)" ) - 1 );
404                 fstr->bv_val = malloc( fstr->bv_len + 1 );
405
406                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
407                         atmp.bv_val );
408                 break;
409
410         case LDAP_FILTER_AND:
411         case LDAP_FILTER_OR:
412         case LDAP_FILTER_NOT:
413                 fstr->bv_len = sizeof( "(%)" ) - 1;
414                 fstr->bv_val = malloc( fstr->bv_len + 128 );
415
416                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
417                         f->f_choice == LDAP_FILTER_AND ? '&' :
418                         f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
419
420                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
421                         len = fstr->bv_len;
422
423                         if ( rwm_int_filter_map_rewrite( dc, p, &vtmp, remap ) )
424                         {
425                                 return -1;
426                         }
427                         
428                         fstr->bv_len += vtmp.bv_len;
429                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
430
431                         snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2, 
432                                 /*"("*/ "%s)", vtmp.bv_val );
433
434                         ch_free( vtmp.bv_val );
435                 }
436
437                 break;
438
439         case LDAP_FILTER_EXT: {
440                 if ( f->f_mr_desc ) {
441                         if ( map_attr_value( dc, f->f_mr_desc, &atmp,
442                                                 &f->f_mr_value, &vtmp, remap ) )
443                         {
444                                 return -1;
445                         }
446
447                 } else {
448                         atmp.bv_len = 0;
449                         atmp.bv_val = "";
450                         
451                         filter_escape_value( &f->f_mr_value, &vtmp );
452                 }
453                         
454
455                 fstr->bv_len = atmp.bv_len +
456                         ( f->f_mr_dnattrs ? sizeof( ":dn" ) - 1 : 0 ) +
457                         ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
458                         vtmp.bv_len + ( sizeof( "(:=)" ) - 1 );
459                 fstr->bv_val = malloc( fstr->bv_len + 1 );
460
461                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
462                         atmp.bv_val,
463                         f->f_mr_dnattrs ? ":dn" : "",
464                         f->f_mr_rule_text.bv_len ? ":" : "",
465                         f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
466                         vtmp.bv_val );
467                 ber_memfree( vtmp.bv_val );
468                 } break;
469
470         case SLAPD_FILTER_COMPUTED:
471                 switch ( f->f_result ) {
472                 case LDAP_COMPARE_FALSE:
473                         tmp = ber_bvfalse;
474                         break;
475
476                 case LDAP_COMPARE_TRUE:
477                         tmp = ber_bvtrue;
478                         break;
479                         
480                 case SLAPD_COMPARE_UNDEFINED:
481                         tmp = ber_bvundefined;
482                         break;
483                         
484                 default:
485                         tmp = ber_bverror;
486                         break;
487                 }
488
489                 ber_dupbv( fstr, &tmp );
490                 break;
491                 
492         default:
493                 ber_dupbv( fstr, &ber_bvunknown );
494                 break;
495         }
496
497         return 0;
498 }
499
500 int
501 rwm_filter_map_rewrite(
502                 dncookie                *dc,
503                 Filter                  *f,
504                 struct berval           *fstr,
505                 int                     remap )
506 {
507         int             rc;
508         dncookie        fdc;
509         struct berval   ftmp;
510
511         rc = rwm_int_filter_map_rewrite( dc, f, fstr, remap );
512
513 #ifdef ENABLE_REWRITE
514         if ( rc != LDAP_SUCCESS ) {
515                 return rc;
516         }
517
518         fdc = *dc;
519         ftmp = *fstr;
520
521         fdc.ctx = "searchFilter";
522
523         switch ( rewrite_session( fdc.rwmap->rwm_rw, fdc.ctx, 
524                                 ( ftmp.bv_len ? ftmp.bv_val : "" ), 
525                                 fdc.conn, &fstr->bv_val )) {
526         case REWRITE_REGEXEC_OK:
527                 if ( fstr->bv_val != NULL ) {
528                         fstr->bv_len = strlen( fstr->bv_val );
529                         free( ftmp.bv_val );
530                 } else {
531                         *fstr = ftmp;
532                 }
533
534 #ifdef NEW_LOGGING
535                 LDAP_LOG( BACK_LDAP, DETAIL1, 
536                         "[rw] %s: \"%s\" -> \"%s\"\n",
537                         dc->ctx, ftmp.bv_val, fstr->bv_val );           
538 #else /* !NEW_LOGGING */
539                 Debug( LDAP_DEBUG_ARGS,
540                         "[rw] %s: \"%s\" -> \"%s\"\n",
541                         dc->ctx, ftmp.bv_val, fstr->bv_val );           
542 #endif /* !NEW_LOGGING */
543                 rc = LDAP_SUCCESS;
544                 break;
545                 
546         case REWRITE_REGEXEC_UNWILLING:
547                 if ( fdc.rs ) {
548                         fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
549                         fdc.rs->sr_text = "Operation not allowed";
550                 }
551                 rc = LDAP_UNWILLING_TO_PERFORM;
552                 break;
553                 
554         case REWRITE_REGEXEC_ERR:
555                 if ( fdc.rs ) {
556                         fdc.rs->sr_err = LDAP_OTHER;
557                         fdc.rs->sr_text = "Rewrite error";
558                 }
559                 rc = LDAP_OTHER;
560                 break;
561         }
562
563 #endif /* ENABLE_REWRITE */
564         return rc;
565 }
566
567 /*
568  * I don't like this much, but we need two different
569  * functions because different heap managers may be
570  * in use in back-ldap/meta to reduce the amount of
571  * calls to malloc routines, and some of the free()
572  * routines may be macros with args
573  */
574 int
575 rwm_dnattr_rewrite(
576         Operation               *op,
577         SlapReply               *rs,
578         void                    *cookie,
579         BerVarray               a_vals
580         )
581 {
582         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
583         struct ldaprwmap        *rwmap = 
584                         (struct ldaprwmap *)on->on_bi.bi_private;
585
586         struct berval           bv;
587         int                     i, last;
588
589         dncookie                dc;
590
591         /*
592          * Rewrite the bind dn if needed
593          */
594         dc.rwmap = rwmap;
595 #ifdef ENABLE_REWRITE
596         dc.conn = op->o_conn;
597         dc.rs = rs;
598         dc.ctx = (char *)cookie;
599 #else
600         dc.tofrom = ((int *)cookie)[0];
601         dc.normalized = 0;
602 #endif
603
604         for ( last = 0; a_vals[last].bv_val != NULL; last++ );
605         last--;
606
607         for ( i = 0; a_vals[i].bv_val != NULL; i++ ) {
608                 switch ( rwm_dn_massage( &dc, &a_vals[i], &bv ) ) {
609                 case LDAP_UNWILLING_TO_PERFORM:
610                         /*
611                          * FIXME: need to check if it may be considered 
612                          * legal to trim values when adding/modifying;
613                          * it should be when searching (e.g. ACLs).
614                          */
615                         ch_free( a_vals[i].bv_val );
616                         if (last > i ) {
617                                 a_vals[i] = a_vals[last];
618                         }
619                         a_vals[last].bv_len = 0;
620                         a_vals[last].bv_val = NULL;
621                         last--;
622                         break;
623
624                 default:
625                         /* leave attr untouched if massage failed */
626                         if ( bv.bv_val && bv.bv_val != a_vals[i].bv_val ) {
627                                 ch_free( a_vals[i].bv_val );
628                                 a_vals[i] = bv;
629                         }
630                         break;
631                 }
632         }
633         
634         return 0;
635 }
636
637 int
638 rwm_dnattr_result_rewrite(
639         dncookie                *dc,
640         BerVarray               a_vals
641 )
642 {
643         struct berval   bv;
644         int             i, last;
645
646         for ( last = 0; a_vals[last].bv_val; last++ );
647         last--;
648
649         for ( i = 0; a_vals[i].bv_val; i++ ) {
650                 switch ( rwm_dn_massage( dc, &a_vals[i], &bv ) ) {
651                 case LDAP_UNWILLING_TO_PERFORM:
652                         /*
653                          * FIXME: need to check if it may be considered 
654                          * legal to trim values when adding/modifying;
655                          * it should be when searching (e.g. ACLs).
656                          */
657                         LBER_FREE( &a_vals[i].bv_val );
658                         if ( last > i ) {
659                                 a_vals[i] = a_vals[last];
660                         }
661                         a_vals[last].bv_val = NULL;
662                         a_vals[last].bv_len = 0;
663                         last--;
664                         break;
665
666                 default:
667                         /* leave attr untouched if massage failed */
668                         if ( bv.bv_val && a_vals[i].bv_val != bv.bv_val ) {
669                                 LBER_FREE( a_vals[i].bv_val );
670                                 a_vals[i] = bv;
671                         }
672                         break;
673                 }
674         }
675
676         return 0;
677 }
678
679 void
680 rwm_mapping_free( void *v_mapping )
681 {
682         struct ldapmapping *mapping = v_mapping;
683
684         if ( mapping[0].m_src.bv_val ) {
685                 ch_free( mapping[0].m_src.bv_val );
686         }
687
688         if ( mapping[0].m_flags & RWMMAP_F_FREE_SRC ) {
689                 if ( mapping[0].m_flags & RWMMAP_F_IS_OC ) {
690                         if ( mapping[0].m_src_oc ) {
691                                 ch_free( mapping[0].m_src_oc );
692                         }
693
694                 } else {
695                         if ( mapping[0].m_src_ad ) {
696                                 ch_free( mapping[0].m_src_ad );
697                         }
698                 }
699         }
700
701         if ( mapping[0].m_dst.bv_val ) {
702                 ch_free( mapping[0].m_dst.bv_val );
703         }
704
705         if ( mapping[0].m_flags & RWMMAP_F_FREE_DST ) {
706                 if ( mapping[0].m_flags & RWMMAP_F_IS_OC ) {
707                         if ( mapping[0].m_dst_oc ) {
708                                 ch_free( mapping[0].m_dst_oc );
709                         }
710
711                 } else {
712                         if ( mapping[0].m_dst_ad ) {
713                                 ch_free( mapping[0].m_dst_ad );
714                         }
715                 }
716         }
717
718         ch_free( mapping );
719
720 }
721
722 #endif /* SLAPD_OVER_RWM */