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