]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/rwm.c
Use be_shadow_update, not be_isupdate
[openldap] / servers / slapd / overlays / rwm.c
1 /* rwm.c - rewrite/remap operations */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2005 The OpenLDAP Foundation.
6  * Portions Copyright 2003 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17
18 #include "portable.h"
19
20 #ifdef SLAPD_OVER_RWM
21
22 #include <stdio.h>
23
24 #include <ac/string.h>
25
26 #include "slap.h"
27 #include "rwm.h"
28
29 static int
30 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie )
31 {
32         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
33         struct ldaprwmap        *rwmap = 
34                         (struct ldaprwmap *)on->on_bi.bi_private;
35
36         struct berval           dn = BER_BVNULL,
37                                 ndn = BER_BVNULL;
38         int                     rc = 0;
39         dncookie                dc;
40
41         /*
42          * Rewrite the dn if needed
43          */
44         dc.rwmap = rwmap;
45 #ifdef ENABLE_REWRITE
46         dc.conn = op->o_conn;
47         dc.rs = rs;
48         dc.ctx = (char *)cookie;
49 #else /* ! ENABLE_REWRITE */
50         dc.tofrom = ((int *)cookie)[0];
51         dc.normalized = 0;
52 #endif /* ! ENABLE_REWRITE */
53
54         /* NOTE: in those cases where only the ndn is available,
55          * and the caller sets op->o_req_dn = op->o_req_ndn,
56          * only rewrite the op->o_req_ndn and use it as 
57          * op->o_req_dn as well */
58         ndn = op->o_req_ndn;
59         if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
60                 dn = op->o_req_dn;
61                 rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
62         } else {
63                 rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
64         }
65
66         if ( rc != LDAP_SUCCESS ) {
67                 return rc;
68         }
69
70         if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
71                         || ndn.bv_val == op->o_req_ndn.bv_val )
72         {
73                 return LDAP_SUCCESS;
74         }
75
76         op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
77         op->o_req_ndn = ndn;
78         if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
79                 op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
80                 op->o_req_dn = dn;
81         } else {
82                 op->o_req_dn = ndn;
83         }
84
85         return LDAP_SUCCESS;
86 }
87
88 static int
89 rwm_op_add( Operation *op, SlapReply *rs )
90 {
91         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
92         struct ldaprwmap        *rwmap = 
93                         (struct ldaprwmap *)on->on_bi.bi_private;
94
95         int                     rc,
96                                 i;
97         Attribute               **ap = NULL;
98         char                    *olddn = op->o_req_dn.bv_val;
99         int                     isupdate;
100
101 #ifdef ENABLE_REWRITE
102         rc = rwm_op_dn_massage( op, rs, "addDN" );
103 #else /* ! ENABLE_REWRITE */
104         rc = 1;
105         rc = rwm_op_dn_massage( op, rs, &rc );
106 #endif /* ! ENABLE_REWRITE */
107         if ( rc != LDAP_SUCCESS ) {
108                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
109                 send_ldap_error( op, rs, rc, "addDN massage error" );
110                 return -1;
111         }
112
113         if ( olddn != op->o_req_dn.bv_val ) {
114                 ch_free( op->ora_e->e_name.bv_val );
115                 ch_free( op->ora_e->e_nname.bv_val );
116
117                 ber_dupbv( &op->ora_e->e_name, &op->o_req_dn );
118                 ber_dupbv( &op->ora_e->e_nname, &op->o_req_ndn );
119         }
120
121         /* Count number of attributes in entry */ 
122         isupdate = be_shadow_update( op );
123         for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
124                 struct berval   mapped;
125                 Attribute       *a;
126
127                 if ( !isupdate && (*ap)->a_desc->ad_type->sat_no_user_mod ) {
128                         goto next_attr;
129                 }
130
131                 rwm_map( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
132                                 &mapped, RWM_MAP );
133                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
134                         goto cleanup_attr;
135                 }
136
137                 if ( (*ap)->a_desc->ad_type->sat_syntax
138                                 == slap_schema.si_syn_distinguishedName )
139                 {
140                         /*
141                          * FIXME: rewrite could fail; in this case
142                          * the operation should give up, right?
143                          */
144 #ifdef ENABLE_REWRITE
145                         rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
146                                         (*ap)->a_vals,
147                                         (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
148 #else /* ! ENABLE_REWRITE */
149                         rc = 1;
150                         rc = rwm_dnattr_rewrite( op, rs, &rc, (*ap)->a_vals,
151                                         (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
152 #endif /* ! ENABLE_REWRITE */
153                         if ( rc ) {
154                                 goto cleanup_attr;
155                         }
156
157                 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
158 #ifdef ENABLE_REWRITE
159                         rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
160                                         (*ap)->a_vals,
161                                         (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
162 #else /* ! ENABLE_REWRITE */
163                         rc = 1;
164                         rc = rwm_referral_rewrite( op, rs, &rc, (*ap)->a_vals,
165                                         (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
166 #endif /* ! ENABLE_REWRITE */
167                         if ( rc != LDAP_SUCCESS ) {
168                                 goto cleanup_attr;
169                         }
170                 }
171
172
173 next_attr:;
174                 ap = &(*ap)->a_next;
175                 continue;
176
177 cleanup_attr:;
178                 /* FIXME: leaking attribute/values? */
179                 a = *ap;
180
181                 *ap = (*ap)->a_next;
182                 attr_free( a );
183         }
184
185         /* TODO: map attribute types, values of DN-valued attributes ... */
186         return SLAP_CB_CONTINUE;
187 }
188
189 static int
190 rwm_op_bind( Operation *op, SlapReply *rs )
191 {
192         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
193         struct ldaprwmap        *rwmap = 
194                         (struct ldaprwmap *)on->on_bi.bi_private;
195         int                     rc;
196
197 #ifdef ENABLE_REWRITE
198         ( void )rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
199         ( void )rewrite_session_init( rwmap->rwm_rw, op->o_conn );
200
201         rc = rwm_op_dn_massage( op, rs, "bindDN" );
202 #else /* ! ENABLE_REWRITE */
203         rc = 1;
204         rc = rwm_op_dn_massage( op, rs, &rc );
205 #endif /* ! ENABLE_REWRITE */
206         if ( rc != LDAP_SUCCESS ) {
207                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
208                 send_ldap_error( op, rs, rc, "bindDN massage error" );
209                 return -1;
210         }
211
212         return SLAP_CB_CONTINUE;
213 }
214
215 static int
216 rwm_op_unbind( Operation *op, SlapReply *rs )
217 {
218         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
219         struct ldaprwmap        *rwmap = 
220                         (struct ldaprwmap *)on->on_bi.bi_private;
221
222 #ifdef ENABLE_REWRITE
223         rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
224 #endif /* ENABLE_REWRITE */
225
226         return SLAP_CB_CONTINUE;
227 }
228
229 static int
230 rwm_op_compare( Operation *op, SlapReply *rs )
231 {
232         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
233         struct ldaprwmap        *rwmap = 
234                         (struct ldaprwmap *)on->on_bi.bi_private;
235
236         int                     rc;
237         struct berval           mapped_at = BER_BVNULL,
238                                 mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
239
240 #ifdef ENABLE_REWRITE
241         rc = rwm_op_dn_massage( op, rs, "compareDN" );
242 #else /* ! ENABLE_REWRITE */
243         rc = 1;
244         rc = rwm_op_dn_massage( op, rs, &rc );
245 #endif /* ! ENABLE_REWRITE */
246         if ( rc != LDAP_SUCCESS ) {
247                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
248                 send_ldap_error( op, rs, rc, "compareDN massage error" );
249                 return -1;
250         }
251
252         /* if the attribute is an objectClass, try to remap its value */
253         if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
254                         || op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
255         {
256                 rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
257                                 &mapped_vals[0], RWM_MAP );
258                 if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
259                 {
260                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
261                         send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
262                         return -1;
263
264                 } else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
265                         free( op->orc_ava->aa_value.bv_val );
266                         op->orc_ava->aa_value = mapped_vals[0];
267                 }
268                 mapped_at = op->orc_ava->aa_desc->ad_cname;
269
270         } else {
271                 struct ldapmapping      *mapping = NULL;
272                 AttributeDescription    *ad = op->orc_ava->aa_desc;
273
274                 ( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
275                                 &mapping, RWM_MAP );
276                 if ( mapping == NULL ) {
277                         if ( rwmap->rwm_at.drop_missing ) {
278                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
279                                 send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
280                                 return -1;
281                         }
282
283                 } else {
284                         ad = mapping->m_dst_ad;
285                 }
286
287                 if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
288                 {
289                         struct berval   *mapped_valsp[2];
290                         
291                         mapped_valsp[0] = &mapped_vals[0];
292                         mapped_valsp[1] = &mapped_vals[1];
293
294                         mapped_vals[0] = op->orc_ava->aa_value;
295
296 #ifdef ENABLE_REWRITE
297                         rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
298 #else /* ! ENABLE_REWRITE */
299                         rc = 1;
300                         rc = rwm_dnattr_rewrite( op, rs, &rc, NULL, mapped_valsp );
301 #endif /* ! ENABLE_REWRITE */
302
303                         if ( rc != LDAP_SUCCESS ) {
304                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
305                                 send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
306                                 return -1;
307                         }
308
309                         op->orc_ava->aa_value = mapped_vals[0];
310                 }
311                 op->orc_ava->aa_desc = ad;
312         }
313
314         return SLAP_CB_CONTINUE;
315 }
316
317 static int
318 rwm_op_delete( Operation *op, SlapReply *rs )
319 {
320         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
321         int                     rc;
322
323 #ifdef ENABLE_REWRITE
324         rc = rwm_op_dn_massage( op, rs, "deleteDN" );
325 #else /* ! ENABLE_REWRITE */
326         rc = 1;
327         rc = rwm_op_dn_massage( op, rs, &rc );
328 #endif /* ! ENABLE_REWRITE */
329         if ( rc != LDAP_SUCCESS ) {
330                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
331                 send_ldap_error( op, rs, rc, "deleteDN massage error" );
332                 return -1;
333         }
334
335         return SLAP_CB_CONTINUE;
336 }
337
338 static int
339 rwm_op_modify( Operation *op, SlapReply *rs )
340 {
341         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
342         struct ldaprwmap        *rwmap = 
343                         (struct ldaprwmap *)on->on_bi.bi_private;
344
345         int                     isupdate;
346         Modifications           **mlp;
347         int                     rc;
348
349 #ifdef ENABLE_REWRITE
350         rc = rwm_op_dn_massage( op, rs, "modifyDN" );
351 #else /* ! ENABLE_REWRITE */
352         rc = 1;
353         rc = rwm_op_dn_massage( op, rs, &rc );
354 #endif /* ! ENABLE_REWRITE */
355         if ( rc != LDAP_SUCCESS ) {
356                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
357                 send_ldap_error( op, rs, rc, "modifyDN massage error" );
358                 return -1;
359         }
360
361         isupdate = be_shadow_update( op );
362         for ( mlp = &op->oq_modify.rs_modlist; *mlp; ) {
363                 int             is_oc = 0;
364                 Modifications   *ml;
365
366                 if ( !isupdate && (*mlp)->sml_desc->ad_type->sat_no_user_mod  ) {
367                         goto next_mod;
368                 }
369
370                 if ( (*mlp)->sml_desc == slap_schema.si_ad_objectClass 
371                                 || (*mlp)->sml_desc == slap_schema.si_ad_structuralObjectClass ) {
372                         is_oc = 1;
373
374                 } else {
375                         struct ldapmapping      *m;
376                         int                     drop_missing;
377
378                         drop_missing = rwm_mapping( &rwmap->rwm_at, &(*mlp)->sml_desc->ad_cname, &m, RWM_MAP );
379                         if ( drop_missing || ( m != NULL && BER_BVISNULL( &m->m_dst ) ) )
380                         {
381                                 goto cleanup_mod;
382                         }
383
384                         if ( m ) {
385                                 /* use new attribute description */
386                                 assert( m->m_dst_ad );
387                                 (*mlp)->sml_desc = m->m_dst_ad;
388                         }
389                 }
390
391                 if ( (*mlp)->sml_values != NULL ) {
392                         if ( is_oc ) {
393                                 int     last, j;
394
395                                 for ( last = 0; !BER_BVISNULL( &(*mlp)->sml_values[last] ); last++ )
396                                         /* count values */ ;
397                                 last--;
398
399                                 for ( j = 0; !BER_BVISNULL( &(*mlp)->sml_values[j] ); j++ ) {
400                                         struct berval   mapped = BER_BVNULL;
401
402                                         rwm_map( &rwmap->rwm_oc,
403                                                         &(*mlp)->sml_values[j],
404                                                         &mapped, RWM_MAP );
405                                         if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
406                                                 /* FIXME: we allow to remove objectClasses as well;
407                                                  * if the resulting entry is inconsistent, that's
408                                                  * the relayed database's business...
409                                                  */
410 #if 0
411                                                 goto cleanup_mod;
412 #endif
413                                                 if ( last > j ) {
414                                                         (*mlp)->sml_values[j] = (*mlp)->sml_values[last];
415                                                         BER_BVZERO( &(*mlp)->sml_values[last] );
416                                                 }
417                                                 last--;
418
419                                         } else {
420                                                 ch_free( (*mlp)->sml_values[j].bv_val );
421                                                 ber_dupbv( &(*mlp)->sml_values[j], &mapped );
422                                         }
423                                 }
424
425                         } else {
426                                 if ( (*mlp)->sml_desc->ad_type->sat_syntax ==
427                                                 slap_schema.si_syn_distinguishedName )
428                                 {
429 #ifdef ENABLE_REWRITE
430                                         rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
431                                                         (*mlp)->sml_values,
432                                                         (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL );
433 #else /* ! ENABLE_REWRITE */
434                                         rc = 1;
435                                         rc = rwm_dnattr_rewrite( op, rs, &rc, 
436                                                         (*mlp)->sml_values,
437                                                         (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL );
438 #endif /* ! ENABLE_REWRITE */
439
440                                 } else if ( (*mlp)->sml_desc == slap_schema.si_ad_ref ) {
441 #ifdef ENABLE_REWRITE
442                                         rc = rwm_referral_rewrite( op, rs,
443                                                         "referralAttrDN",
444                                                         (*mlp)->sml_values,
445                                                         (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL );
446 #else /* ! ENABLE_REWRITE */
447                                         rc = 1;
448                                         rc = rwm_referral_rewrite( op, rs, &rc,
449                                                         (*mlp)->sml_values,
450                                                         (*mlp)->sml_nvalues ? &(*mlp)->sml_nvalues : NULL );
451 #endif /* ! ENABLE_REWRITE */
452                                         if ( rc != LDAP_SUCCESS ) {
453                                                 goto cleanup_mod;
454                                         }
455                                 }
456
457                                 if ( rc != LDAP_SUCCESS ) {
458                                         goto cleanup_mod;
459                                 }
460                         }
461                 }
462
463 next_mod:;
464                 mlp = &(*mlp)->sml_next;
465                 continue;
466
467 cleanup_mod:;
468                 ml = *mlp;
469                 *mlp = (*mlp)->sml_next;
470                 slap_mod_free( &ml->sml_mod, 0 );
471                 free( ml );
472         }
473
474         /* TODO: rewrite attribute types, values of DN-valued attributes ... */
475         return SLAP_CB_CONTINUE;
476 }
477
478 static int
479 rwm_op_modrdn( Operation *op, SlapReply *rs )
480 {
481         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
482         struct ldaprwmap        *rwmap = 
483                         (struct ldaprwmap *)on->on_bi.bi_private;
484         
485         int                     rc;
486
487         if ( op->orr_newSup ) {
488                 dncookie        dc;
489                 struct berval   nnewSup = BER_BVNULL;
490                 struct berval   newSup = BER_BVNULL;
491
492                 /*
493                  * Rewrite the new superior, if defined and required
494                  */
495                 dc.rwmap = rwmap;
496 #ifdef ENABLE_REWRITE
497                 dc.conn = op->o_conn;
498                 dc.rs = rs;
499                 dc.ctx = "newSuperiorDN";
500 #else /* ! ENABLE_REWRITE */
501                 dc.tofrom = 0;
502                 dc.normalized = 0;
503 #endif /* ! ENABLE_REWRITE */
504                 newSup = *op->orr_newSup;
505                 nnewSup = *op->orr_nnewSup;
506                 rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
507                 if ( rc != LDAP_SUCCESS ) {
508                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
509                         send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
510                         return -1;
511                 }
512
513                 if ( op->orr_newSup->bv_val != newSup.bv_val ) {
514                         op->o_tmpfree( op->orr_newSup->bv_val, op->o_tmpmemctx );
515                         op->o_tmpfree( op->orr_nnewSup->bv_val, op->o_tmpmemctx );
516                         *op->orr_newSup = newSup;
517                         *op->orr_nnewSup = nnewSup;
518                 }
519         }
520
521         /*
522          * Rewrite the dn, if needed
523          */
524 #ifdef ENABLE_REWRITE
525         rc = rwm_op_dn_massage( op, rs, "renameDN" );
526 #else /* ! ENABLE_REWRITE */
527         rc = 1;
528         rc = rwm_op_dn_massage( op, rs, &rc );
529 #endif /* ! ENABLE_REWRITE */
530         if ( rc != LDAP_SUCCESS ) {
531                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
532                 send_ldap_error( op, rs, rc, "renameDN massage error" );
533                 return -1;
534         }
535
536         /* TODO: rewrite newRDN, attribute types, 
537          * values of DN-valued attributes ... */
538         return SLAP_CB_CONTINUE;
539 }
540
541 static int
542 rwm_swap_attrs( Operation *op, SlapReply *rs )
543 {
544         slap_callback   *cb = op->o_callback;
545         AttributeName   *an = (AttributeName *)cb->sc_private;
546
547         rs->sr_attrs = an;
548         
549         return SLAP_CB_CONTINUE;
550 }
551
552 static int rwm_freeself( Operation *op, SlapReply *rs )
553 {
554         if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_RESULT ) {
555                 assert( op->o_callback );
556
557                 op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
558                 op->o_callback = NULL;
559         }
560
561         return SLAP_CB_CONTINUE;
562 }
563
564 static int
565 rwm_op_search( Operation *op, SlapReply *rs )
566 {
567         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
568         struct ldaprwmap        *rwmap = 
569                         (struct ldaprwmap *)on->on_bi.bi_private;
570
571         int                     rc;
572         dncookie                dc;
573
574         struct berval           fstr = BER_BVNULL;
575         Filter                  *f = NULL;
576
577         slap_callback           *cb;
578         AttributeName           *an = NULL;
579
580         char                    *text = NULL;
581
582 #ifdef ENABLE_REWRITE
583         rc = rwm_op_dn_massage( op, rs, "searchDN" );
584 #else /* ! ENABLE_REWRITE */
585         rc = 1;
586         rc = rwm_op_dn_massage( op, rs, &rc );
587 #endif /* ! ENABLE_REWRITE */
588         if ( rc != LDAP_SUCCESS ) {
589                 text = "searchDN massage error";
590                 goto error_return;
591         }
592
593         /*
594          * Rewrite the dn if needed
595          */
596         dc.rwmap = rwmap;
597 #ifdef ENABLE_REWRITE
598         dc.conn = op->o_conn;
599         dc.rs = rs;
600         dc.ctx = "searchFilterAttrDN";
601 #else /* ! ENABLE_REWRITE */
602         dc.tofrom = 0;
603         dc.normalized = 0;
604 #endif /* ! ENABLE_REWRITE */
605
606         rc = rwm_filter_map_rewrite( &dc, op->ors_filter, &fstr );
607         if ( rc != LDAP_SUCCESS ) {
608                 text = "searchFilter/searchFilterAttrDN massage error";
609                 goto error_return;
610         }
611
612         f = str2filter_x( op, fstr.bv_val );
613
614         if ( f == NULL ) {
615                 text = "massaged filter parse error";
616                 goto error_return;
617         }
618
619         if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
620                 ch_free( op->ors_filterstr.bv_val );
621         }
622
623         if( op->ors_filter ) {
624                 filter_free_x( op, op->ors_filter );
625         }
626
627         op->ors_filter = f;
628         op->ors_filterstr = fstr;
629
630         rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
631                         op->ors_attrs, &an, RWM_MAP );
632         if ( rc != LDAP_SUCCESS ) {
633                 text = "attribute list mapping error";
634                 goto error_return;
635         }
636
637         cb = (slap_callback *) op->o_tmpcalloc( sizeof( slap_callback ),
638                         1, op->o_tmpmemctx );
639         if ( cb == NULL ) {
640                 rc = LDAP_NO_MEMORY;
641                 goto error_return;
642         }
643
644         cb->sc_response = rwm_swap_attrs;
645         cb->sc_cleanup = rwm_freeself;
646         cb->sc_private = (void *)op->ors_attrs;
647         cb->sc_next = op->o_callback;
648
649         op->o_callback = cb;
650         op->ors_attrs = an;
651
652         return SLAP_CB_CONTINUE;
653
654 error_return:;
655         if ( an != NULL ) {
656                 ch_free( an );
657         }
658
659         if ( f != NULL ) {
660                 filter_free_x( op, f );
661         }
662
663         if ( !BER_BVISNULL( &fstr ) ) {
664                 ch_free( fstr.bv_val );
665         }
666
667         op->o_bd->bd_info = (BackendInfo *)on->on_info;
668         send_ldap_error( op, rs, rc, text );
669
670         return -1;
671
672 }
673
674 static int
675 rwm_extended( Operation *op, SlapReply *rs )
676 {
677         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
678         int                     rc;
679
680 #ifdef ENABLE_REWRITE
681         rc = rwm_op_dn_massage( op, rs, "extendedDN" );
682 #else /* ! ENABLE_REWRITE */
683         rc = 1;
684         rc = rwm_op_dn_massage( op, rs, &rc );
685 #endif /* ! ENABLE_REWRITE */
686         if ( rc != LDAP_SUCCESS ) {
687                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
688                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
689                 return -1;
690         }
691
692         /* TODO: rewrite/map extended data ? ... */
693         return SLAP_CB_CONTINUE;
694 }
695
696 static int
697 rwm_matched( Operation *op, SlapReply *rs )
698 {
699         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
700         struct ldaprwmap        *rwmap = 
701                         (struct ldaprwmap *)on->on_bi.bi_private;
702
703         struct berval           dn, mdn;
704         dncookie                dc;
705         int                     rc;
706
707         if ( rs->sr_matched == NULL ) {
708                 return SLAP_CB_CONTINUE;
709         }
710
711         dc.rwmap = rwmap;
712 #ifdef ENABLE_REWRITE
713         dc.conn = op->o_conn;
714         dc.rs = rs;
715         dc.ctx = "matchedDN";
716 #else /* ! ENABLE_REWRITE */
717         dc.tofrom = 0;
718         dc.normalized = 0;
719 #endif /* ! ENABLE_REWRITE */
720         ber_str2bv( rs->sr_matched, 0, 0, &dn );
721         mdn = dn;
722         rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
723         if ( rc != LDAP_SUCCESS ) {
724                 rs->sr_err = rc;
725                 rs->sr_text = "Rewrite error";
726                 return 1;
727         }
728
729         if ( mdn.bv_val != dn.bv_val ) {
730                 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
731                         ch_free( (void *)rs->sr_matched );
732
733                 } else {
734                         rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
735                 }
736                 rs->sr_matched = mdn.bv_val;
737         }
738         
739         return SLAP_CB_CONTINUE;
740 }
741
742 static int
743 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first )
744 {
745         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
746         struct ldaprwmap        *rwmap = 
747                         (struct ldaprwmap *)on->on_bi.bi_private;
748
749         dncookie                dc;
750         int                     rc;
751         Attribute               **ap;
752         int                     isupdate;
753
754         /*
755          * Rewrite the dn attrs, if needed
756          */
757         dc.rwmap = rwmap;
758 #ifdef ENABLE_REWRITE
759         dc.conn = op->o_conn;
760         dc.rs = NULL; 
761 #else /* ! ENABLE_REWRITE */
762         dc.tofrom = 0;
763         dc.normalized = 0;
764 #endif /* ! ENABLE_REWRITE */
765
766         /* FIXME: the entries are in the remote mapping form;
767          * so we need to select those attributes we are willing
768          * to return, and remap them accordingly */
769
770         /* FIXME: in principle, one could map an attribute
771          * on top of another, which already exists.
772          * As such, in the end there might exist more than
773          * one instance of an attribute.
774          * We should at least check if this occurs, and issue
775          * an error (because multiple instances of attrs in 
776          * response are not valid), or merge the values (what
777          * about duplicate values?) */
778         isupdate = be_shadow_update( op );
779         for ( ap = a_first; *ap; ) {
780                 struct ldapmapping      *m;
781                 int                     drop_missing;
782                 int                     last;
783                 Attribute               *a;
784
785                 if ( SLAP_OPATTRS( rs->sr_attr_flags ) && is_at_operational( (*ap)->a_desc->ad_type ) )
786                 {
787                         /* go on */ ;
788                         
789                 } else if ( op->ors_attrs != NULL && 
790                                 !SLAP_USERATTRS( rs->sr_attr_flags ) && 
791                                 !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
792                 {
793                         goto cleanup_attr;
794                 }
795
796                 if ( !isupdate && (*ap)->a_desc->ad_type->sat_no_user_mod 
797                         && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
798                 {
799                         goto next_attr;
800                 }
801
802                 drop_missing = rwm_mapping( &rwmap->rwm_at,
803                                 &(*ap)->a_desc->ad_cname, &m, RWM_REMAP );
804                 if ( drop_missing || ( m != NULL && BER_BVISEMPTY( &m->m_dst ) ) ) {
805                         goto cleanup_attr;
806                 }
807
808                 for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ )
809                         /* just count */ ;
810
811                 if ( last == 0 ) {
812                         /* empty? for now, we leave it in place */
813                         goto next_attr;
814                 }
815                 last--;
816
817                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
818                                 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
819                 {
820                         struct berval   *bv;
821                         
822                         for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
823                                 struct berval   mapped;
824
825                                 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
826                                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
827                                         ch_free( bv[0].bv_val );
828                                         BER_BVZERO( &bv[0] );
829                                         if ( &(*ap)->a_vals[last] > &bv[0] ) {
830                                                 bv[0] = (*ap)->a_vals[last];
831                                                 BER_BVZERO( &(*ap)->a_vals[last] );
832                                         }
833                                         last--;
834                                         bv--;
835
836                                 } else if ( mapped.bv_val != bv[0].bv_val ) {
837                                         /*
838                                          * FIXME: after LBER_FREEing
839                                          * the value is replaced by
840                                          * ch_alloc'ed memory
841                                          */
842                                         ch_free( bv[0].bv_val );
843                                         ber_dupbv( &bv[0], &mapped );
844                                 }
845                         }
846
847                 /*
848                  * It is necessary to try to rewrite attributes with
849                  * dn syntax because they might be used in ACLs as
850                  * members of groups; since ACLs are applied to the
851                  * rewritten stuff, no dn-based subject clause could
852                  * be used at the ldap backend side (see
853                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
854                  * The problem can be overcome by moving the dn-based
855                  * ACLs to the target directory server, and letting
856                  * everything pass thru the ldap backend. */
857                 /* FIXME: handle distinguishedName-like syntaxes, like
858                  * nameAndOptionalUID */
859                 } else if ( (*ap)->a_desc->ad_type->sat_syntax ==
860                                 slap_schema.si_syn_distinguishedName )
861                 {
862 #ifdef ENABLE_REWRITE
863                         dc.ctx = "searchAttrDN";
864 #endif /* ENABLE_REWRITE */
865                         rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
866                         if ( rc != LDAP_SUCCESS ) {
867                                 goto cleanup_attr;
868                         }
869
870                 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
871 #ifdef ENABLE_REWRITE
872                         dc.ctx = "searchAttrDN";
873 #endif /* ENABLE_REWRITE */
874                         rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
875                         if ( rc != LDAP_SUCCESS ) {
876                                 goto cleanup_attr;
877                         }
878                 }
879
880                 if ( m != NULL ) {
881                         /* rewrite the attribute description */
882                         assert( m->m_dst_ad );
883                         (*ap)->a_desc = m->m_dst_ad;
884                 }
885
886 next_attr:;
887                 ap = &(*ap)->a_next;
888                 continue;
889
890 cleanup_attr:;
891                 a = *ap;
892                 *ap = (*ap)->a_next;
893
894                 attr_free( a );
895         }
896
897         return 0;
898 }
899
900 static int
901 rwm_send_entry( Operation *op, SlapReply *rs )
902 {
903         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
904         struct ldaprwmap        *rwmap = 
905                         (struct ldaprwmap *)on->on_bi.bi_private;
906
907         Entry                   *e = NULL;
908         int                     flags;
909         struct berval           dn = BER_BVNULL,
910                                 ndn = BER_BVNULL;
911         dncookie                dc;
912         int                     rc;
913
914         assert( rs->sr_entry );
915
916         /*
917          * Rewrite the dn of the result, if needed
918          */
919         dc.rwmap = rwmap;
920 #ifdef ENABLE_REWRITE
921         dc.conn = op->o_conn;
922         dc.rs = NULL; 
923         dc.ctx = "searchEntryDN";
924 #else /* ! ENABLE_REWRITE */
925         dc.tofrom = 0;
926         dc.normalized = 0;
927 #endif /* ! ENABLE_REWRITE */
928
929         e = rs->sr_entry;
930         flags = rs->sr_flags;
931         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
932                 /* FIXME: all we need to duplicate are:
933                  * - dn
934                  * - ndn
935                  * - attributes that are requested
936                  * - no values if attrsonly is set
937                  */
938
939                 e = entry_dup( e );
940                 if ( e == NULL ) {
941                         rc = LDAP_NO_MEMORY;
942                         goto fail;
943                 }
944
945                 flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
946         }
947
948         /*
949          * Note: this may fail if the target host(s) schema differs
950          * from the one known to the meta, and a DN with unknown
951          * attributes is returned.
952          */
953         dn = e->e_name;
954         ndn = e->e_nname;
955         rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
956         if ( rc != LDAP_SUCCESS ) {
957                 rc = 1;
958                 goto fail;
959         }
960
961         if ( e->e_name.bv_val != dn.bv_val ) {
962                 ch_free( e->e_name.bv_val );
963                 ch_free( e->e_nname.bv_val );
964
965                 e->e_name = dn;
966                 e->e_nname = ndn;
967         }
968
969         /* TODO: map entry attribute types, objectclasses 
970          * and dn-valued attribute values */
971
972         /* FIXME: the entries are in the remote mapping form;
973          * so we need to select those attributes we are willing
974          * to return, and remap them accordingly */
975         (void)rwm_attrs( op, rs, &e->e_attrs );
976
977         rs->sr_entry = e;
978         rs->sr_flags = flags;
979
980         return SLAP_CB_CONTINUE;
981
982 fail:;
983         if ( !BER_BVISNULL( &dn ) ) {
984                 ch_free( dn.bv_val );
985         }
986
987         if ( !BER_BVISNULL( &ndn ) ) {
988                 ch_free( ndn.bv_val );
989         }
990
991         if ( e != NULL && e != rs->sr_entry ) {
992                 entry_free( e );
993         }
994
995         return rc;
996 }
997
998 static int
999 rwm_operational( Operation *op, SlapReply *rs )
1000 {
1001         /* FIXME: the entries are in the remote mapping form;
1002          * so we need to select those attributes we are willing
1003          * to return, and remap them accordingly */
1004         if ( rs->sr_operational_attrs ) {
1005                 rwm_attrs( op, rs, &rs->sr_operational_attrs );
1006         }
1007
1008         return SLAP_CB_CONTINUE;
1009 }
1010
1011 #if 0
1012 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1013  * rewritten for subsequent operations; fine for plain suffixmassage,
1014  * but destroys everything else */
1015 static int
1016 rwm_chk_referrals( Operation *op, SlapReply *rs )
1017 {
1018         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1019         int                     rc;
1020
1021 #ifdef ENABLE_REWRITE
1022         rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1023 #else /* ! ENABLE_REWRITE */
1024         rc = 1;
1025         rc = rwm_op_dn_massage( op, rs, &rc );
1026 #endif /* ! ENABLE_REWRITE */
1027         if ( rc != LDAP_SUCCESS ) {
1028                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1029                 send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1030                 return -1;
1031         }
1032
1033         return SLAP_CB_CONTINUE;
1034 }
1035 #endif
1036
1037 static int
1038 rwm_rw_config(
1039     BackendDB   *be,
1040     const char  *fname,
1041     int         lineno,
1042     int         argc,
1043     char        **argv
1044 )
1045 {
1046 #ifdef ENABLE_REWRITE
1047         slap_overinst           *on = (slap_overinst *) be->bd_info;
1048         struct ldaprwmap        *rwmap = 
1049                         (struct ldaprwmap *)on->on_bi.bi_private;
1050
1051         return rewrite_parse( rwmap->rwm_rw,
1052                                 fname, lineno, argc, argv );
1053
1054 #else /* !ENABLE_REWRITE */
1055         fprintf( stderr, "%s: line %d: rewrite capabilities "
1056                         "are not enabled\n", fname, lineno );
1057 #endif /* !ENABLE_REWRITE */
1058                 
1059         return 0;
1060 }
1061
1062 static int
1063 rwm_suffixmassage_config(
1064     BackendDB   *be,
1065     const char  *fname,
1066     int         lineno,
1067     int         argc,
1068     char        **argv
1069 )
1070 {
1071         slap_overinst           *on = (slap_overinst *) be->bd_info;
1072         struct ldaprwmap        *rwmap = 
1073                         (struct ldaprwmap *)on->on_bi.bi_private;
1074
1075         struct berval           bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1076         int                     massaged;
1077 #ifdef ENABLE_REWRITE
1078         int                     rc;
1079 #endif /* ENABLE_REWRITE */
1080                 
1081         /*
1082          * syntax:
1083          * 
1084          *      suffixmassage [<suffix>] <massaged suffix>
1085          *
1086          * the [<suffix>] field must be defined as a valid suffix
1087          * for the current database;
1088          * the <massaged suffix> shouldn't have already been
1089          * defined as a valid suffix for the current server
1090          */
1091         if ( argc == 2 ) {
1092                 if ( be->be_suffix == NULL ) {
1093                         fprintf( stderr, "%s: line %d: "
1094                                        " \"suffixMassage [<suffix>]"
1095                                        " <massaged suffix>\" without "
1096                                        "<suffix> part requires database "
1097                                        "suffix be defined first.\n",
1098                                 fname, lineno );
1099                         return 1;
1100                 }
1101                 bvnc = be->be_suffix[ 0 ];
1102                 massaged = 1;
1103
1104         } else if ( argc == 3 ) {
1105                 ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1106                 massaged = 2;
1107
1108         } else  {
1109                 fprintf( stderr, "%s: line %d: syntax is"
1110                                " \"suffixMassage [<suffix>]"
1111                                " <massaged suffix>\"\n",
1112                         fname, lineno );
1113                 return 1;
1114         }
1115
1116         if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1117                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1118                         fname, lineno, bvnc.bv_val );
1119                 return 1;
1120         }
1121
1122         ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1123         if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1124                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1125                                 fname, lineno, brnc.bv_val );
1126                 free( nvnc.bv_val );
1127                 free( pvnc.bv_val );
1128                 return 1;
1129         }
1130
1131 #ifdef ENABLE_REWRITE
1132         /*
1133          * The suffix massaging is emulated 
1134          * by means of the rewrite capabilities
1135          */
1136         rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1137                         &pvnc, &nvnc, &prnc, &nrnc );
1138         free( nvnc.bv_val );
1139         free( pvnc.bv_val );
1140         free( nrnc.bv_val );
1141         free( prnc.bv_val );
1142
1143         return( rc );
1144
1145 #else /* !ENABLE_REWRITE */
1146         ber_bvarray_add( &rwmap->rwm_suffix_massage, &pvnc );
1147         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nvnc );
1148                 
1149         ber_bvarray_add( &rwmap->rwm_suffix_massage, &prnc );
1150         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nrnc );
1151 #endif /* !ENABLE_REWRITE */
1152
1153         return 0;
1154 }
1155
1156 static int
1157 rwm_m_config(
1158     BackendDB   *be,
1159     const char  *fname,
1160     int         lineno,
1161     int         argc,
1162     char        **argv
1163 )
1164 {
1165         slap_overinst           *on = (slap_overinst *) be->bd_info;
1166         struct ldaprwmap        *rwmap = 
1167                         (struct ldaprwmap *)on->on_bi.bi_private;
1168
1169         /* objectclass/attribute mapping */
1170         return rwm_map_config( &rwmap->rwm_oc,
1171                         &rwmap->rwm_at,
1172                         fname, lineno, argc, argv );
1173 }
1174
1175 static int
1176 rwm_response( Operation *op, SlapReply *rs )
1177 {
1178         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
1179         struct ldaprwmap        *rwmap = 
1180                         (struct ldaprwmap *)on->on_bi.bi_private;
1181
1182         int             rc;
1183
1184         if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1185                 return rwm_send_entry( op, rs );
1186         }
1187
1188         switch( op->o_tag ) {
1189         case LDAP_REQ_SEARCH:
1190                 /* Note: the operation attrs are remapped */
1191                 if ( op->ors_attrs != NULL && op->ors_attrs != rs->sr_attrs )
1192                 {
1193                         ch_free( op->ors_attrs );
1194                         op->ors_attrs = rs->sr_attrs;
1195                 }
1196                 /* fall thru */
1197
1198         case LDAP_REQ_BIND:
1199         case LDAP_REQ_ADD:
1200         case LDAP_REQ_DELETE:
1201         case LDAP_REQ_MODRDN:
1202         case LDAP_REQ_MODIFY:
1203         case LDAP_REQ_COMPARE:
1204         case LDAP_REQ_EXTENDED:
1205                 if ( rs->sr_ref ) {
1206                         dncookie                dc;
1207
1208                         /*
1209                          * Rewrite the dn of the referrals, if needed
1210                          */
1211                         dc.rwmap = rwmap;
1212 #ifdef ENABLE_REWRITE
1213                         dc.conn = op->o_conn;
1214                         dc.rs = NULL; 
1215                         dc.ctx = "referralDN";
1216 #else /* ! ENABLE_REWRITE */
1217                         dc.tofrom = 0;
1218                         dc.normalized = 0;
1219 #endif /* ! ENABLE_REWRITE */
1220                         rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1221                         if ( rc != LDAP_SUCCESS ) {
1222                                 rc = 1;
1223                                 break;
1224                         }
1225                 }
1226                 rc = rwm_matched( op, rs );
1227                 break;
1228
1229         default:
1230                 rc = SLAP_CB_CONTINUE;
1231                 break;
1232         }
1233
1234         return rc;
1235 }
1236
1237 static int
1238 rwm_db_config(
1239     BackendDB   *be,
1240     const char  *fname,
1241     int         lineno,
1242     int         argc,
1243     char        **argv
1244 )
1245 {
1246         int             rc = 0;
1247         char            *argv0 = NULL;
1248
1249         if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1250                 argv0 = argv[ 0 ];
1251                 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1252         }
1253
1254         if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1255                 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1256
1257         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1258                 rc = rwm_m_config( be, fname, lineno, argc, argv );
1259
1260         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1261                 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1262
1263         } else {
1264                 rc = SLAP_CONF_UNKNOWN;
1265         }
1266
1267         if ( argv0 ) {
1268                 argv[ 0 ] = argv0;
1269         }
1270
1271         return rc;
1272 }
1273
1274 static int
1275 rwm_db_init(
1276         BackendDB *be
1277 )
1278 {
1279         slap_overinst           *on = (slap_overinst *) be->bd_info;
1280         struct ldapmapping      *mapping = NULL;
1281         struct ldaprwmap        *rwmap;
1282
1283         rwmap = (struct ldaprwmap *)ch_malloc(sizeof(struct ldaprwmap));
1284         memset(rwmap, 0, sizeof(struct ldaprwmap));
1285
1286 #ifdef ENABLE_REWRITE
1287         rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
1288         if ( rwmap->rwm_rw == NULL ) {
1289                 ch_free( rwmap );
1290                 return -1;
1291         }
1292
1293         {
1294                 char    *rargv[3];
1295
1296                 /* this rewriteContext by default must be null;
1297                  * rules can be added if required */
1298                 rargv[ 0 ] = "rewriteContext";
1299                 rargv[ 1 ] = "searchFilter";
1300                 rargv[ 2 ] = NULL;
1301                 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
1302
1303                 rargv[ 0 ] = "rewriteContext";
1304                 rargv[ 1 ] = "default";
1305                 rargv[ 2 ] = NULL;
1306                 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
1307         }
1308         
1309 #endif /* ENABLE_REWRITE */
1310
1311         if ( rwm_map_init( &rwmap->rwm_oc, &mapping ) != LDAP_SUCCESS ||
1312                         rwm_map_init( &rwmap->rwm_at, &mapping ) != LDAP_SUCCESS )
1313         {
1314                 return 1;
1315         }
1316
1317         on->on_bi.bi_private = (void *)rwmap;
1318
1319         return 0;
1320 }
1321
1322 static int
1323 rwm_db_destroy(
1324         BackendDB *be
1325 )
1326 {
1327         slap_overinst   *on = (slap_overinst *) be->bd_info;
1328         int             rc = 0;
1329
1330         if ( on->on_bi.bi_private ) {
1331                 struct ldaprwmap        *rwmap = 
1332                         (struct ldaprwmap *)on->on_bi.bi_private;
1333
1334 #ifdef ENABLE_REWRITE
1335                 if (rwmap->rwm_rw) {
1336                         rewrite_info_delete( &rwmap->rwm_rw );
1337                 }
1338 #else /* !ENABLE_REWRITE */
1339                 if ( rwmap->rwm_suffix_massage ) {
1340                         ber_bvarray_free( rwmap->rwm_suffix_massage );
1341                 }
1342 #endif /* !ENABLE_REWRITE */
1343
1344                 avl_free( rwmap->rwm_oc.remap, NULL );
1345                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
1346                 avl_free( rwmap->rwm_at.remap, NULL );
1347                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
1348         }
1349
1350         return rc;
1351 }
1352
1353 static slap_overinst rwm = { { NULL } };
1354
1355 int
1356 rwm_init(void)
1357 {
1358         memset( &rwm, 0, sizeof( slap_overinst ) );
1359
1360         rwm.on_bi.bi_type = "rwm";
1361
1362         rwm.on_bi.bi_db_init = rwm_db_init;
1363         rwm.on_bi.bi_db_config = rwm_db_config;
1364         rwm.on_bi.bi_db_destroy = rwm_db_destroy;
1365
1366         rwm.on_bi.bi_op_bind = rwm_op_bind;
1367         rwm.on_bi.bi_op_search = rwm_op_search;
1368         rwm.on_bi.bi_op_compare = rwm_op_compare;
1369         rwm.on_bi.bi_op_modify = rwm_op_modify;
1370         rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
1371         rwm.on_bi.bi_op_add = rwm_op_add;
1372         rwm.on_bi.bi_op_delete = rwm_op_delete;
1373         rwm.on_bi.bi_op_unbind = rwm_op_unbind;
1374         rwm.on_bi.bi_extended = rwm_extended;
1375
1376         rwm.on_bi.bi_operational = rwm_operational;
1377         rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
1378
1379         rwm.on_response = rwm_response;
1380
1381         return overlay_register( &rwm );
1382 }
1383
1384 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1385 int
1386 init_module( int argc, char *argv[] )
1387 {
1388         return rwm_init();
1389 }
1390 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1391
1392 #endif /* SLAPD_OVER_RWM */