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