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