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