]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/rwm.c
1fbfac3a9f584d5e075eb3111085deae05057fd8
[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-2014 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 "config.h"
28 #include "lutil.h"
29 #include "rwm.h"
30
31 typedef struct rwm_op_state {
32         ber_tag_t r_tag;
33         struct berval ro_dn;
34         struct berval ro_ndn;
35         struct berval r_dn;
36         struct berval r_ndn;
37         struct berval rx_dn;
38         struct berval rx_ndn;
39         AttributeName *mapped_attrs;
40         OpRequest o_request;
41 } rwm_op_state;
42
43 typedef struct rwm_op_cb {
44         slap_callback cb;
45         rwm_op_state ros;
46 } rwm_op_cb;
47
48 static int
49 rwm_db_destroy( BackendDB *be, ConfigReply *cr );
50
51 static int
52 rwm_send_entry( Operation *op, SlapReply *rs );
53
54 static void
55 rwm_op_rollback( Operation *op, SlapReply *rs, rwm_op_state *ros )
56 {
57         /* in case of successful extended operation cleanup
58          * gets called *after* (ITS#6632); this hack counts
59          * on others to cleanup our o_req_dn/o_req_ndn,
60          * while we cleanup theirs. */
61         if ( ros->r_tag == LDAP_REQ_EXTENDED && rs->sr_err == LDAP_SUCCESS ) {
62                 if ( !BER_BVISNULL( &ros->rx_dn ) ) {
63                         ch_free( ros->rx_dn.bv_val );
64                 }
65                 if ( !BER_BVISNULL( &ros->rx_ndn ) ) {
66                         ch_free( ros->rx_ndn.bv_val );
67                 }
68
69         } else {
70                 if ( !BER_BVISNULL( &ros->ro_dn ) ) {
71                         op->o_req_dn = ros->ro_dn;
72                 }
73                 if ( !BER_BVISNULL( &ros->ro_ndn ) ) {
74                         op->o_req_ndn = ros->ro_ndn;
75                 }
76
77                 if ( !BER_BVISNULL( &ros->r_dn )
78                         && ros->r_dn.bv_val != ros->ro_dn.bv_val )
79                 {
80                         assert( ros->r_dn.bv_val != ros->r_ndn.bv_val );
81                         ch_free( ros->r_dn.bv_val );
82                 }
83
84                 if ( !BER_BVISNULL( &ros->r_ndn )
85                         && ros->r_ndn.bv_val != ros->ro_ndn.bv_val )
86                 {
87                         ch_free( ros->r_ndn.bv_val );
88                 }
89         }
90
91         BER_BVZERO( &ros->r_dn );
92         BER_BVZERO( &ros->r_ndn );
93         BER_BVZERO( &ros->ro_dn );
94         BER_BVZERO( &ros->ro_ndn );
95         BER_BVZERO( &ros->rx_dn );
96         BER_BVZERO( &ros->rx_ndn );
97
98         switch( ros->r_tag ) {
99         case LDAP_REQ_COMPARE:
100                 if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
101                         op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
102                 op->orc_ava = ros->orc_ava;
103                 break;
104         case LDAP_REQ_MODIFY:
105                 slap_mods_free( op->orm_modlist, 1 );
106                 op->orm_modlist = ros->orm_modlist;
107                 break;
108         case LDAP_REQ_MODRDN:
109                 if ( op->orr_newSup != ros->orr_newSup ) {
110                         if ( op->orr_newSup ) {
111                                 ch_free( op->orr_newSup->bv_val );
112                                 ch_free( op->orr_nnewSup->bv_val );
113                                 op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
114                                 op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
115                         }
116                         op->orr_newSup = ros->orr_newSup;
117                         op->orr_nnewSup = ros->orr_nnewSup;
118                 }
119                 if ( op->orr_newrdn.bv_val != ros->orr_newrdn.bv_val ) {
120                         ch_free( op->orr_newrdn.bv_val );
121                         ch_free( op->orr_nnewrdn.bv_val );
122                         op->orr_newrdn = ros->orr_newrdn;
123                         op->orr_nnewrdn = ros->orr_nnewrdn;
124                 }
125                 break;
126         case LDAP_REQ_SEARCH:
127                 op->o_tmpfree( ros->mapped_attrs, op->o_tmpmemctx );
128                 filter_free_x( op, op->ors_filter, 1 );
129                 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
130                 op->ors_attrs = ros->ors_attrs;
131                 op->ors_filter = ros->ors_filter;
132                 op->ors_filterstr = ros->ors_filterstr;
133                 break;
134         case LDAP_REQ_EXTENDED:
135                 if ( op->ore_reqdata != ros->ore_reqdata ) {
136                         ber_bvfree( op->ore_reqdata );
137                         op->ore_reqdata = ros->ore_reqdata;
138                 }
139                 break;
140         case LDAP_REQ_BIND:
141                 if ( rs->sr_err == LDAP_SUCCESS ) {
142 #if 0
143                         ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
144                         /* too late, c_mutex released */
145                         Debug( LDAP_DEBUG_ANY, "*** DN: \"%s\" => \"%s\"\n",
146                                 op->o_conn->c_ndn.bv_val,
147                                 op->o_req_ndn.bv_val );
148                         ber_bvreplace( &op->o_conn->c_ndn,
149                                 &op->o_req_ndn );
150                         ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
151 #endif
152                 }
153                 break;
154         default:        break;
155         }
156 }
157
158 static int
159 rwm_op_cleanup( Operation *op, SlapReply *rs )
160 {
161         slap_callback   *cb = op->o_callback;
162         rwm_op_state *ros = cb->sc_private;
163
164         if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
165                 op->o_abandon || rs->sr_err == SLAPD_ABANDON )
166         {
167                 rwm_op_rollback( op, rs, ros );
168
169                 op->o_callback = op->o_callback->sc_next;
170                 op->o_tmpfree( cb, op->o_tmpmemctx );
171         }
172
173         return SLAP_CB_CONTINUE;
174 }
175
176 static rwm_op_cb *
177 rwm_callback_get( Operation *op )
178 {
179         rwm_op_cb       *roc;
180
181         roc = op->o_tmpcalloc( 1, sizeof( struct rwm_op_cb ), op->o_tmpmemctx );
182         roc->cb.sc_cleanup = rwm_op_cleanup;
183         roc->cb.sc_response = NULL;
184         roc->cb.sc_next = op->o_callback;
185         roc->cb.sc_private = &roc->ros;
186         roc->ros.r_tag = op->o_tag;
187         roc->ros.ro_dn = op->o_req_dn;
188         roc->ros.ro_ndn = op->o_req_ndn;
189         BER_BVZERO( &roc->ros.r_dn );
190         BER_BVZERO( &roc->ros.r_ndn );
191         BER_BVZERO( &roc->ros.rx_dn );
192         BER_BVZERO( &roc->ros.rx_ndn );
193         roc->ros.mapped_attrs = NULL;
194         roc->ros.o_request = op->o_request;
195
196         return roc;
197 }
198
199
200 static int
201 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
202         rwm_op_state *ros )
203 {
204         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
205         struct ldaprwmap        *rwmap = 
206                         (struct ldaprwmap *)on->on_bi.bi_private;
207
208         struct berval           dn = BER_BVNULL,
209                                 ndn = BER_BVNULL;
210         int                     rc = 0;
211         dncookie                dc;
212
213         /*
214          * Rewrite the dn if needed
215          */
216         dc.rwmap = rwmap;
217         dc.conn = op->o_conn;
218         dc.rs = rs;
219         dc.ctx = (char *)cookie;
220
221         /* NOTE: in those cases where only the ndn is available,
222          * and the caller sets op->o_req_dn = op->o_req_ndn,
223          * only rewrite the op->o_req_ndn and use it as 
224          * op->o_req_dn as well */
225         ndn = op->o_req_ndn;
226         if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
227                 dn = op->o_req_dn;
228                 rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
229         } else {
230                 rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
231         }
232
233         if ( rc != LDAP_SUCCESS ) {
234                 return rc;
235         }
236
237         if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
238                         || ndn.bv_val == op->o_req_ndn.bv_val )
239         {
240                 return LDAP_SUCCESS;
241         }
242
243         if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
244                 op->o_req_dn = dn;
245                 assert( BER_BVISNULL( &ros->r_dn ) );
246                 ros->r_dn = dn;
247         } else {
248                 op->o_req_dn = ndn;
249         }
250         op->o_req_ndn = ndn;
251         assert( BER_BVISNULL( &ros->r_ndn ) );
252         ros->r_ndn = ndn;
253
254         if ( ros->r_tag == LDAP_REQ_EXTENDED ) {
255                 ros->rx_dn = ros->r_dn;
256                 ros->rx_ndn = ros->r_ndn;
257         }
258
259         return LDAP_SUCCESS;
260 }
261
262 static int
263 rwm_op_add( Operation *op, SlapReply *rs )
264 {
265         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
266         struct ldaprwmap        *rwmap = 
267                         (struct ldaprwmap *)on->on_bi.bi_private;
268
269         int                     rc,
270                                 i;
271         Attribute               **ap = NULL;
272         char                    *olddn = op->o_req_dn.bv_val;
273         int                     isupdate;
274
275         rwm_op_cb               *roc = rwm_callback_get( op );
276
277         rc = rwm_op_dn_massage( op, rs, "addDN", &roc->ros );
278         if ( rc != LDAP_SUCCESS ) {
279                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
280                 send_ldap_error( op, rs, rc, "addDN massage error" );
281                 return -1;
282         }
283
284         if ( olddn != op->o_req_dn.bv_val ) {
285                 ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
286                 ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
287         }
288
289         /* Count number of attributes in entry */ 
290         isupdate = be_shadow_update( op );
291         for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
292                 Attribute       *a;
293
294                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
295                                 (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
296                 {
297                         int             j, last;
298
299                         last = (*ap)->a_numvals - 1;
300                         for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
301                                 struct ldapmapping      *mapping = NULL;
302
303                                 ( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
304                                                 &mapping, RWM_MAP );
305                                 if ( mapping == NULL ) {
306                                         if ( rwmap->rwm_at.drop_missing ) {
307                                                 /* FIXME: we allow to remove objectClasses as well;
308                                                  * if the resulting entry is inconsistent, that's
309                                                  * the relayed database's business...
310                                                  */
311                                                 ch_free( (*ap)->a_vals[ j ].bv_val );
312                                                 if ( last > j ) {
313                                                         (*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
314                                                 }
315                                                 BER_BVZERO( &(*ap)->a_vals[ last ] );
316                                                 (*ap)->a_numvals--;
317                                                 last--;
318                                                 j--;
319                                         }
320
321                                 } else {
322                                         ch_free( (*ap)->a_vals[ j ].bv_val );
323                                         ber_dupbv( &(*ap)->a_vals[ j ], &mapping->m_dst );
324                                 }
325                         }
326
327                 } else if ( !isupdate && !get_relax( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
328                 {
329                         goto next_attr;
330
331                 } else {
332                         struct ldapmapping      *mapping = NULL;
333
334                         ( void )rwm_mapping( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
335                                         &mapping, RWM_MAP );
336                         if ( mapping == NULL ) {
337                                 if ( rwmap->rwm_at.drop_missing ) {
338                                         goto cleanup_attr;
339                                 }
340                         }
341
342                         if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
343                                         || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
344                         {
345                                 /*
346                                  * FIXME: rewrite could fail; in this case
347                                  * the operation should give up, right?
348                                  */
349                                 rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
350                                                 (*ap)->a_vals,
351                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
352                                 if ( rc ) {
353                                         goto cleanup_attr;
354                                 }
355
356                         } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
357                                 rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
358                                                 (*ap)->a_vals,
359                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
360                                 if ( rc != LDAP_SUCCESS ) {
361                                         goto cleanup_attr;
362                                 }
363                         }
364                 
365                         if ( mapping != NULL ) {
366                                 assert( mapping->m_dst_ad != NULL );
367                                 (*ap)->a_desc = mapping->m_dst_ad;
368                         }
369                 }
370
371 next_attr:;
372                 ap = &(*ap)->a_next;
373                 continue;
374
375 cleanup_attr:;
376                 /* FIXME: leaking attribute/values? */
377                 a = *ap;
378
379                 *ap = (*ap)->a_next;
380                 attr_free( a );
381         }
382
383         op->o_callback = &roc->cb;
384
385         return SLAP_CB_CONTINUE;
386 }
387
388 static int
389 rwm_conn_init( BackendDB *be, Connection *conn )
390 {
391         slap_overinst           *on = (slap_overinst *) be->bd_info;
392         struct ldaprwmap        *rwmap = 
393                         (struct ldaprwmap *)on->on_bi.bi_private;
394
395         ( void )rewrite_session_init( rwmap->rwm_rw, conn );
396
397         return SLAP_CB_CONTINUE;
398 }
399
400 static int
401 rwm_conn_destroy( BackendDB *be, Connection *conn )
402 {
403         slap_overinst           *on = (slap_overinst *) be->bd_info;
404         struct ldaprwmap        *rwmap = 
405                         (struct ldaprwmap *)on->on_bi.bi_private;
406
407         ( void )rewrite_session_delete( rwmap->rwm_rw, conn );
408
409         return SLAP_CB_CONTINUE;
410 }
411
412 static int
413 rwm_op_bind( Operation *op, SlapReply *rs )
414 {
415         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
416         int                     rc;
417
418         rwm_op_cb               *roc = rwm_callback_get( op );
419
420         rc = rwm_op_dn_massage( op, rs, "bindDN", &roc->ros );
421         if ( rc != LDAP_SUCCESS ) {
422                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
423                 send_ldap_error( op, rs, rc, "bindDN massage error" );
424                 return -1;
425         }
426
427         overlay_callback_after_backover( op, &roc->cb, 1 );
428
429         return SLAP_CB_CONTINUE;
430 }
431
432 static int
433 rwm_op_unbind( Operation *op, SlapReply *rs )
434 {
435         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
436         struct ldaprwmap        *rwmap = 
437                         (struct ldaprwmap *)on->on_bi.bi_private;
438
439         rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
440
441         return SLAP_CB_CONTINUE;
442 }
443
444 static int
445 rwm_op_compare( Operation *op, SlapReply *rs )
446 {
447         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
448         struct ldaprwmap        *rwmap = 
449                         (struct ldaprwmap *)on->on_bi.bi_private;
450
451         int                     rc;
452         struct berval           mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
453
454         rwm_op_cb               *roc = rwm_callback_get( op );
455
456         rc = rwm_op_dn_massage( op, rs, "compareDN", &roc->ros );
457         if ( rc != LDAP_SUCCESS ) {
458                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
459                 send_ldap_error( op, rs, rc, "compareDN massage error" );
460                 return -1;
461         }
462
463         /* if the attribute is an objectClass, try to remap its value */
464         if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
465                         || op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
466         {
467                 rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
468                                 &mapped_vals[0], RWM_MAP );
469                 if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
470                 {
471                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
472                         send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
473                         return -1;
474
475                 } else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
476                         ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
477                                 op->o_tmpmemctx );
478                 }
479
480         } else {
481                 struct ldapmapping      *mapping = NULL;
482                 AttributeDescription    *ad = op->orc_ava->aa_desc;
483
484                 ( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
485                                 &mapping, RWM_MAP );
486                 if ( mapping == NULL ) {
487                         if ( rwmap->rwm_at.drop_missing ) {
488                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
489                                 send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
490                                 return -1;
491                         }
492
493                 } else {
494                         assert( mapping->m_dst_ad != NULL );
495                         ad = mapping->m_dst_ad;
496                 }
497
498                 if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
499                                 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
500                 {
501                         struct berval   *mapped_valsp[2];
502                         
503                         mapped_valsp[0] = &mapped_vals[0];
504                         mapped_valsp[1] = &mapped_vals[1];
505
506                         mapped_vals[0] = op->orc_ava->aa_value;
507
508                         rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
509
510                         if ( rc != LDAP_SUCCESS ) {
511                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
512                                 send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
513                                 return -1;
514                         }
515
516                         if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
517                                 /* NOTE: if we get here, rwm_dnattr_rewrite()
518                                  * already freed the old value, so now 
519                                  * it's invalid */
520                                 ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
521                                         op->o_tmpmemctx );
522                                 ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
523                         }
524                 }
525                 op->orc_ava->aa_desc = ad;
526         }
527
528         op->o_callback = &roc->cb;
529
530         return SLAP_CB_CONTINUE;
531 }
532
533 static int
534 rwm_op_delete( Operation *op, SlapReply *rs )
535 {
536         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
537         int                     rc;
538
539         rwm_op_cb               *roc = rwm_callback_get( op );
540
541         rc = rwm_op_dn_massage( op, rs, "deleteDN", &roc->ros );
542         if ( rc != LDAP_SUCCESS ) {
543                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
544                 send_ldap_error( op, rs, rc, "deleteDN massage error" );
545                 return -1;
546         }
547
548         op->o_callback = &roc->cb;
549
550         return SLAP_CB_CONTINUE;
551 }
552
553 static int
554 rwm_op_modify( Operation *op, SlapReply *rs )
555 {
556         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
557         struct ldaprwmap        *rwmap = 
558                         (struct ldaprwmap *)on->on_bi.bi_private;
559
560         int                     isupdate;
561         Modifications           **mlp;
562         int                     rc;
563
564         rwm_op_cb               *roc = rwm_callback_get( op );
565
566         rc = rwm_op_dn_massage( op, rs, "modifyDN", &roc->ros );
567         if ( rc != LDAP_SUCCESS ) {
568                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
569                 send_ldap_error( op, rs, rc, "modifyDN massage error" );
570                 return -1;
571         }
572
573         isupdate = be_shadow_update( op );
574         for ( mlp = &op->orm_modlist; *mlp; ) {
575                 int                     is_oc = 0;
576                 Modifications           *ml = *mlp;
577                 struct ldapmapping      *mapping = NULL;
578
579                 /* ml points to a temporary mod until needs duplication */
580                 if ( ml->sml_desc == slap_schema.si_ad_objectClass 
581                                 || ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
582                 {
583                         is_oc = 1;
584
585                 } else if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
586                 {
587                         ml = ch_malloc( sizeof( Modifications ) );
588                         *ml = **mlp;
589                         if ( (*mlp)->sml_values ) {
590                                 ber_bvarray_dup_x( &ml->sml_values, (*mlp)->sml_values, NULL );
591                                 if ( (*mlp)->sml_nvalues ) {
592                                         ber_bvarray_dup_x( &ml->sml_nvalues, (*mlp)->sml_nvalues, NULL );
593                                 }
594                         }
595                         *mlp = ml;
596                         goto next_mod;
597
598                 } else {
599                         int                     drop_missing;
600
601                         drop_missing = rwm_mapping( &rwmap->rwm_at,
602                                         &ml->sml_desc->ad_cname,
603                                         &mapping, RWM_MAP );
604                         if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
605                         {
606                                 goto skip_mod;
607                         }
608                 }
609
610                 /* duplicate the modlist */
611                 ml = ch_malloc( sizeof( Modifications ));
612                 *ml = **mlp;
613                 *mlp = ml;
614
615                 if ( ml->sml_values != NULL ) {
616                         int i, num;
617                         struct berval *bva;
618
619                         for ( num = 0; !BER_BVISNULL( &ml->sml_values[ num ] ); num++ )
620                                 /* count values */ ;
621
622                         bva = ch_malloc( (num+1) * sizeof( struct berval ));
623                         for (i=0; i<num; i++)
624                                 ber_dupbv( &bva[i], &ml->sml_values[i] );
625                         BER_BVZERO( &bva[i] );
626                         ml->sml_values = bva;
627
628                         if ( ml->sml_nvalues ) {
629                                 bva = ch_malloc( (num+1) * sizeof( struct berval ));
630                                 for (i=0; i<num; i++)
631                                         ber_dupbv( &bva[i], &ml->sml_nvalues[i] );
632                                 BER_BVZERO( &bva[i] );
633                                 ml->sml_nvalues = bva;
634                         }
635
636                         if ( is_oc ) {
637                                 int     last, j;
638
639                                 last = num-1;
640
641                                 for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
642                                         struct ldapmapping      *oc_mapping = NULL;
643                 
644                                         ( void )rwm_mapping( &rwmap->rwm_oc, &ml->sml_values[ j ],
645                                                         &oc_mapping, RWM_MAP );
646                                         if ( oc_mapping == NULL ) {
647                                                 if ( rwmap->rwm_at.drop_missing ) {
648                                                         /* FIXME: we allow to remove objectClasses as well;
649                                                          * if the resulting entry is inconsistent, that's
650                                                          * the relayed database's business...
651                                                          */
652                                                         if ( last > j ) {
653                                                                 ch_free( ml->sml_values[ j ].bv_val );
654                                                                 ml->sml_values[ j ] = ml->sml_values[ last ];
655                                                         }
656                                                         BER_BVZERO( &ml->sml_values[ last ] );
657                                                         last--;
658                                                         j--;
659                                                 }
660         
661                                         } else {
662                                                 ch_free( ml->sml_values[ j ].bv_val );
663                                                 ber_dupbv( &ml->sml_values[ j ], &oc_mapping->m_dst );
664                                         }
665                                 }
666
667                         } else {
668                                 if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
669                                                 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
670                                 {
671                                         rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
672                                                         ml->sml_values,
673                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
674
675                                 } else if ( ml->sml_desc == slap_schema.si_ad_ref ) {
676                                         rc = rwm_referral_rewrite( op, rs,
677                                                         "referralAttrDN",
678                                                         ml->sml_values,
679                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
680                                         if ( rc != LDAP_SUCCESS ) {
681                                                 goto cleanup_mod;
682                                         }
683                                 }
684
685                                 if ( rc != LDAP_SUCCESS ) {
686                                         goto cleanup_mod;
687                                 }
688                         }
689                 }
690
691 next_mod:;
692                 if ( mapping != NULL ) {
693                         /* use new attribute description */
694                         assert( mapping->m_dst_ad != NULL );
695                         ml->sml_desc = mapping->m_dst_ad;
696                 }
697
698                 mlp = &ml->sml_next;
699                 continue;
700
701 skip_mod:;
702                 *mlp = (*mlp)->sml_next;
703                 continue;
704
705 cleanup_mod:;
706                 ml = *mlp;
707                 *mlp = (*mlp)->sml_next;
708                 slap_mod_free( &ml->sml_mod, 0 );
709                 free( ml );
710         }
711
712         op->o_callback = &roc->cb;
713
714         return SLAP_CB_CONTINUE;
715 }
716
717 static int
718 rwm_op_modrdn( Operation *op, SlapReply *rs )
719 {
720         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
721         struct ldaprwmap        *rwmap = 
722                         (struct ldaprwmap *)on->on_bi.bi_private;
723         
724         int                     rc;
725         dncookie                dc;
726
727         rwm_op_cb               *roc = rwm_callback_get( op );
728
729         if ( op->orr_newSup ) {
730                 struct berval   nnewSup = BER_BVNULL;
731                 struct berval   newSup = BER_BVNULL;
732
733                 /*
734                  * Rewrite the new superior, if defined and required
735                  */
736                 dc.rwmap = rwmap;
737                 dc.conn = op->o_conn;
738                 dc.rs = rs;
739                 dc.ctx = "newSuperiorDN";
740                 newSup = *op->orr_newSup;
741                 nnewSup = *op->orr_nnewSup;
742                 rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
743                 if ( rc != LDAP_SUCCESS ) {
744                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
745                         send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
746                         return -1;
747                 }
748
749                 if ( op->orr_newSup->bv_val != newSup.bv_val ) {
750                         op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ),
751                                 op->o_tmpmemctx );
752                         op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ),
753                                 op->o_tmpmemctx );
754                         *op->orr_newSup = newSup;
755                         *op->orr_nnewSup = nnewSup;
756                 }
757         }
758
759         /*
760          * Rewrite the newRDN, if needed
761          */
762         {
763                 struct berval   newrdn = BER_BVNULL;
764                 struct berval   nnewrdn = BER_BVNULL;
765
766                 dc.rwmap = rwmap;
767                 dc.conn = op->o_conn;
768                 dc.rs = rs;
769                 dc.ctx = "newRDN";
770                 newrdn = op->orr_newrdn;
771                 nnewrdn = op->orr_nnewrdn;
772                 rc = rwm_dn_massage_pretty_normalize( &dc, &op->orr_newrdn, &newrdn, &nnewrdn );
773                 if ( rc != LDAP_SUCCESS ) {
774                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
775                         send_ldap_error( op, rs, rc, "newRDN massage error" );
776                         goto err;
777                 }
778
779                 if ( op->orr_newrdn.bv_val != newrdn.bv_val ) {
780                         op->orr_newrdn = newrdn;
781                         op->orr_nnewrdn = nnewrdn;
782                 }
783         }
784
785         /*
786          * Rewrite the dn, if needed
787          */
788         rc = rwm_op_dn_massage( op, rs, "renameDN", &roc->ros );
789         if ( rc != LDAP_SUCCESS ) {
790                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
791                 send_ldap_error( op, rs, rc, "renameDN massage error" );
792                 goto err;
793         }
794
795         op->o_callback = &roc->cb;
796
797         rc = SLAP_CB_CONTINUE;
798
799         if ( 0 ) {
800 err:;
801                 if ( op->orr_newSup != roc->ros.orr_newSup ) {
802                         ch_free( op->orr_newSup->bv_val );
803                         ch_free( op->orr_nnewSup->bv_val );
804                         op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
805                         op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
806                         op->orr_newSup = roc->ros.orr_newSup;
807                         op->orr_nnewSup = roc->ros.orr_nnewSup;
808                 }
809
810                 if ( op->orr_newrdn.bv_val != roc->ros.orr_newrdn.bv_val ) {
811                         ch_free( op->orr_newrdn.bv_val );
812                         ch_free( op->orr_nnewrdn.bv_val );
813                         op->orr_newrdn = roc->ros.orr_newrdn;
814                         op->orr_nnewrdn = roc->ros.orr_nnewrdn;
815                 }
816         }
817
818         return rc;
819 }
820
821
822 static int
823 rwm_swap_attrs( Operation *op, SlapReply *rs )
824 {
825         slap_callback   *cb = op->o_callback;
826         rwm_op_state *ros = cb->sc_private;
827
828         rs->sr_attrs = ros->ors_attrs;
829
830         /* other overlays might have touched op->ors_attrs, 
831          * so we restore the original version here, otherwise
832          * attribute-mapping might fail */
833         op->ors_attrs = ros->mapped_attrs; 
834         
835         return SLAP_CB_CONTINUE;
836 }
837
838 /*
839  * NOTE: this implementation of get/release entry is probably far from
840  * optimal.  The rationale consists in intercepting the request directed
841  * to the underlying database, in order to rewrite/remap the request,
842  * perform it using the modified data, duplicate the resulting entry
843  * and finally free it when release is called.
844  * This implies that subsequent overlays are not called, as the request
845  * is directly shunted to the underlying database.
846  */
847 static int
848 rwm_entry_release_rw( Operation *op, Entry *e, int rw )
849 {
850         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
851
852         /* can't be ours */
853         if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
854                 return SLAP_CB_CONTINUE;
855         }
856
857         /* just free entry if (probably) ours */
858         if ( e->e_private == NULL && BER_BVISNULL( &e->e_bv ) ) {
859                 entry_free( e );
860                 return LDAP_SUCCESS;
861         }
862
863         return SLAP_CB_CONTINUE;
864 }
865
866 static int
867 rwm_entry_get_rw( Operation *op, struct berval *ndn,
868         ObjectClass *oc, AttributeDescription *at, int rw, Entry **ep )
869 {
870         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
871         int                     rc;
872         BackendDB               db;
873         Operation               op2;
874         SlapReply               rs = { REP_SEARCH };
875
876         rwm_op_state            ros = { 0 };
877         struct berval           mndn = BER_BVNULL;
878
879         if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
880                 return SLAP_CB_CONTINUE;
881         }
882
883         /* massage DN */
884         op2.o_tag = LDAP_REQ_SEARCH;
885         op2 = *op;
886         op2.o_req_dn = *ndn;
887         op2.o_req_ndn = *ndn;
888         rc = rwm_op_dn_massage( &op2, &rs, "searchDN", &ros );
889         if ( rc != LDAP_SUCCESS ) {
890                 return LDAP_OTHER;
891         }
892
893         mndn = BER_BVISNULL( &ros.r_ndn ) ? *ndn : ros.r_ndn;
894
895         /* map attribute & objectClass */
896         if ( at != NULL ) {
897         }
898
899         if ( oc != NULL ) {
900         }
901
902         /* fetch entry */
903         db = *op->o_bd;
904         op2.o_bd = &db;
905         op2.o_bd->bd_info = (BackendInfo *)on->on_info->oi_orig;
906         op2.ors_attrs = slap_anlist_all_attributes;
907         rc = op2.o_bd->bd_info->bi_entry_get_rw( &op2, &mndn, oc, at, rw, ep );
908         if ( rc == LDAP_SUCCESS && *ep != NULL ) {
909                 /* we assume be_entry_release() needs to be called */
910                 rs.sr_flags = REP_ENTRY_MUSTRELEASE;
911                 rs.sr_entry = *ep;
912
913                 /* duplicate & release */
914                 op2.o_bd->bd_info = (BackendInfo *)on;
915                 rc = rwm_send_entry( &op2, &rs );
916                 RS_ASSERT( rs.sr_flags & REP_ENTRY_MUSTFLUSH );
917                 if ( rc == SLAP_CB_CONTINUE ) {
918                         *ep = rs.sr_entry;
919                         rc = LDAP_SUCCESS;
920                 } else {
921                         assert( rc != LDAP_SUCCESS && rs.sr_entry == *ep );
922                         *ep = NULL;
923                         op2.o_bd->bd_info = (BackendInfo *)on->on_info;
924                         be_entry_release_r( &op2, rs.sr_entry );
925                         op2.o_bd->bd_info = (BackendInfo *)on;
926                 }
927         }
928
929         if ( !BER_BVISNULL( &ros.r_ndn) && ros.r_ndn.bv_val != ndn->bv_val ) {
930                 op->o_tmpfree( ros.r_ndn.bv_val, op->o_tmpmemctx );
931         }
932
933         return rc;
934 }
935
936 static int
937 rwm_op_search( Operation *op, SlapReply *rs )
938 {
939         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
940         struct ldaprwmap        *rwmap = 
941                         (struct ldaprwmap *)on->on_bi.bi_private;
942
943         int                     rc;
944         dncookie                dc;
945
946         struct berval           fstr = BER_BVNULL;
947         Filter                  *f = NULL;
948
949         AttributeName           *an = NULL;
950
951         char                    *text = NULL;
952
953         rwm_op_cb               *roc = rwm_callback_get( op );
954
955         rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
956                 "searchFilter", op->ors_filterstr.bv_val );
957         if ( rc == LDAP_SUCCESS )
958                 rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
959         if ( rc != LDAP_SUCCESS ) {
960                 text = "searchDN massage error";
961                 goto error_return;
962         }
963
964         /*
965          * Rewrite the dn if needed
966          */
967         dc.rwmap = rwmap;
968         dc.conn = op->o_conn;
969         dc.rs = rs;
970         dc.ctx = "searchFilterAttrDN";
971
972         rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
973         if ( rc != LDAP_SUCCESS ) {
974                 text = "searchFilter/searchFilterAttrDN massage error";
975                 goto error_return;
976         }
977
978         f = str2filter_x( op, fstr.bv_val );
979
980         if ( f == NULL ) {
981                 text = "massaged filter parse error";
982                 goto error_return;
983         }
984
985         op->ors_filter = f;
986         op->ors_filterstr = fstr;
987
988         rc = rwm_map_attrnames( op, &rwmap->rwm_at, &rwmap->rwm_oc,
989                         op->ors_attrs, &an, RWM_MAP );
990         if ( rc != LDAP_SUCCESS ) {
991                 text = "attribute list mapping error";
992                 goto error_return;
993         }
994
995         op->ors_attrs = an;
996         /* store the mapped Attributes for later usage, in
997          * the case that other overlays change op->ors_attrs */
998         roc->ros.mapped_attrs = an;
999         roc->cb.sc_response = rwm_swap_attrs;
1000
1001         op->o_callback = &roc->cb;
1002
1003         return SLAP_CB_CONTINUE;
1004
1005 error_return:;
1006         if ( an != NULL ) {
1007                 ch_free( an );
1008         }
1009
1010         if ( f != NULL ) {
1011                 filter_free_x( op, f, 1 );
1012         }
1013
1014         if ( !BER_BVISNULL( &fstr ) ) {
1015                 op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1016         }
1017
1018         rwm_op_rollback( op, rs, &roc->ros );
1019         op->oq_search = roc->ros.oq_search;
1020         op->o_tmpfree( roc, op->o_tmpmemctx );
1021
1022         op->o_bd->bd_info = (BackendInfo *)on->on_info;
1023         send_ldap_error( op, rs, rc, text );
1024
1025         return -1;
1026
1027 }
1028
1029 static int
1030 rwm_exop_passwd( Operation *op, SlapReply *rs )
1031 {
1032         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1033         int                     rc;
1034         rwm_op_cb *roc;
1035
1036         struct berval   id = BER_BVNULL,
1037                         pwold = BER_BVNULL,
1038                         pwnew = BER_BVNULL;
1039         BerElement *ber = NULL;
1040
1041         if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
1042                 return LDAP_SUCCESS;
1043         }
1044
1045         if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
1046                 rs->sr_err = LDAP_OTHER;
1047                 return rs->sr_err;
1048         }
1049
1050         rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
1051                 &pwold, &pwnew, &rs->sr_text );
1052         if ( rs->sr_err != LDAP_SUCCESS ) {
1053                 return rs->sr_err;
1054         }
1055
1056         if ( !BER_BVISNULL( &id ) ) {
1057                 char idNul = id.bv_val[id.bv_len];
1058                 id.bv_val[id.bv_len] = '\0';
1059                 rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
1060                                 &op->o_req_ndn, op->o_tmpmemctx );
1061                 id.bv_val[id.bv_len] = idNul;
1062                 if ( rs->sr_err != LDAP_SUCCESS ) {
1063                         rs->sr_text = "Invalid DN";
1064                         return rs->sr_err;
1065                 }
1066
1067         } else {
1068                 ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
1069                 ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
1070         }
1071
1072         roc = rwm_callback_get( op );
1073
1074         rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
1075         if ( rc != LDAP_SUCCESS ) {
1076                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1077                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
1078                 return -1;
1079         }
1080
1081         ber = ber_alloc_t( LBER_USE_DER );
1082         if ( !ber ) {
1083                 rs->sr_err = LDAP_OTHER;
1084                 rs->sr_text = "No memory";
1085                 return rs->sr_err;
1086         }
1087         ber_printf( ber, "{" );
1088         if ( !BER_BVISNULL( &id )) {
1089                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, 
1090                         &op->o_req_dn );
1091         }
1092         if ( !BER_BVISNULL( &pwold )) {
1093                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &pwold );
1094         }
1095         if ( !BER_BVISNULL( &pwnew )) {
1096                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &pwnew );
1097         }
1098         ber_printf( ber, "N}" );
1099         ber_flatten( ber, &op->ore_reqdata );
1100         ber_free( ber, 1 );
1101
1102         op->o_callback = &roc->cb;
1103
1104         return SLAP_CB_CONTINUE;
1105 }
1106
1107 static struct exop {
1108         struct berval   oid;
1109         BI_op_extended  *extended;
1110 } exop_table[] = {
1111         { BER_BVC(LDAP_EXOP_MODIFY_PASSWD),     rwm_exop_passwd },
1112         { BER_BVNULL, NULL }
1113 };
1114
1115 static int
1116 rwm_extended( Operation *op, SlapReply *rs )
1117 {
1118         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1119         int                     rc;
1120         rwm_op_cb *roc;
1121
1122         int     i;
1123
1124         for ( i = 0; exop_table[i].extended != NULL; i++ ) {
1125                 if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
1126                 {
1127                         rc = exop_table[i].extended( op, rs );
1128                         switch ( rc ) {
1129                         case LDAP_SUCCESS:
1130                                 break;
1131
1132                         case SLAP_CB_CONTINUE:
1133                         case SLAPD_ABANDON:
1134                                 return rc;
1135
1136                         default:
1137                                 send_ldap_result( op, rs );
1138                                 return rc;
1139                         }
1140                         break;
1141                 }
1142         }
1143
1144         roc = rwm_callback_get( op );
1145
1146         rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
1147         if ( rc != LDAP_SUCCESS ) {
1148                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1149                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
1150                 return -1;
1151         }
1152
1153         /* TODO: rewrite/map extended data ? ... */
1154         op->o_callback = &roc->cb;
1155
1156         return SLAP_CB_CONTINUE;
1157 }
1158
1159 static void
1160 rwm_matched( Operation *op, SlapReply *rs )
1161 {
1162         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1163         struct ldaprwmap        *rwmap = 
1164                         (struct ldaprwmap *)on->on_bi.bi_private;
1165
1166         struct berval           dn, mdn;
1167         dncookie                dc;
1168         int                     rc;
1169
1170         if ( rs->sr_matched == NULL ) {
1171                 return;
1172         }
1173
1174         dc.rwmap = rwmap;
1175         dc.conn = op->o_conn;
1176         dc.rs = rs;
1177         dc.ctx = "matchedDN";
1178         ber_str2bv( rs->sr_matched, 0, 0, &dn );
1179         mdn = dn;
1180         rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
1181         if ( rc != LDAP_SUCCESS ) {
1182                 rs->sr_err = rc;
1183                 rs->sr_text = "Rewrite error";
1184
1185         } else if ( mdn.bv_val != dn.bv_val ) {
1186                 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
1187                         ch_free( (void *)rs->sr_matched );
1188
1189                 } else {
1190                         rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
1191                 }
1192                 rs->sr_matched = mdn.bv_val;
1193         }
1194 }
1195
1196 static int
1197 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
1198 {
1199         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1200         struct ldaprwmap        *rwmap = 
1201                         (struct ldaprwmap *)on->on_bi.bi_private;
1202
1203         dncookie                dc;
1204         int                     rc;
1205         Attribute               **ap;
1206         int                     isupdate;
1207         int                     check_duplicate_attrs = 0;
1208
1209         /*
1210          * Rewrite the dn attrs, if needed
1211          */
1212         dc.rwmap = rwmap;
1213         dc.conn = op->o_conn;
1214         dc.rs = NULL; 
1215
1216         /* FIXME: the entries are in the remote mapping form;
1217          * so we need to select those attributes we are willing
1218          * to return, and remap them accordingly */
1219
1220         /* FIXME: in principle, one could map an attribute
1221          * on top of another, which already exists.
1222          * As such, in the end there might exist more than
1223          * one instance of an attribute.
1224          * We should at least check if this occurs, and issue
1225          * an error (because multiple instances of attrs in 
1226          * response are not valid), or merge the values (what
1227          * about duplicate values?) */
1228         isupdate = be_shadow_update( op );
1229         for ( ap = a_first; *ap; ) {
1230                 struct ldapmapping      *mapping = NULL;
1231                 int                     drop_missing;
1232                 int                     last = -1;
1233                 Attribute               *a;
1234
1235                 if ( ( rwmap->rwm_flags & RWM_F_DROP_UNREQUESTED_ATTRS ) &&
1236                                 op->ors_attrs != NULL && 
1237                                 !SLAP_USERATTRS( rs->sr_attr_flags ) &&
1238                                 !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
1239                 {
1240                         goto cleanup_attr;
1241                 }
1242
1243                 drop_missing = rwm_mapping( &rwmap->rwm_at,
1244                                 &(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
1245                 if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
1246                 {
1247                         goto cleanup_attr;
1248                 }
1249                 if ( mapping != NULL ) {
1250                         assert( mapping->m_dst_ad != NULL );
1251
1252                         /* try to normalize mapped Attributes if the original 
1253                          * AttributeType was not normalized */
1254                         if ( (!(*ap)->a_desc->ad_type->sat_equality || 
1255                                 !(*ap)->a_desc->ad_type->sat_equality->smr_normalize) &&
1256                                 mapping->m_dst_ad->ad_type->sat_equality &&
1257                                 mapping->m_dst_ad->ad_type->sat_equality->smr_normalize )
1258                         {
1259                                 if ((rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS))
1260                                 {
1261                                         int i = 0;
1262
1263                                         last = (*ap)->a_numvals;
1264                                         if ( last )
1265                                         {
1266                                                 (*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) );
1267
1268                                                 for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[i]); i++ ) {
1269                                                         int             rc;
1270                                                         /*
1271                                                          * check that each value is valid per syntax
1272                                                          * and pretty if appropriate
1273                                                          */
1274                                                         rc = mapping->m_dst_ad->ad_type->sat_equality->smr_normalize(
1275                                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1276                                                                 mapping->m_dst_ad->ad_type->sat_syntax,
1277                                                                 mapping->m_dst_ad->ad_type->sat_equality,
1278                                                                 &(*ap)->a_vals[i], &(*ap)->a_nvals[i],
1279                                                                 NULL );
1280
1281                                                         if ( rc != LDAP_SUCCESS ) {
1282                                                                 /* FIXME: this is wrong, putting a non-normalized value
1283                                                                  * into nvals. But when a proxy sends us bogus data,
1284                                                                  * we still need to give it to the client, even if it
1285                                                                  * violates the syntax. I.e., we don't want to silently
1286                                                                  * drop things and trigger an apparent data loss.
1287                                                                  */
1288                                                                 ber_dupbv( &(*ap)->a_nvals[i], &(*ap)->a_vals[i] );
1289                                                         }
1290                                                 }
1291                                                 BER_BVZERO( &(*ap)->a_nvals[i] );
1292                                         }
1293
1294                                 } else {
1295                                         assert( (*ap)->a_nvals == (*ap)->a_vals );
1296                                         (*ap)->a_nvals = NULL;
1297                                         ber_bvarray_dup_x( &(*ap)->a_nvals, (*ap)->a_vals, NULL );
1298                                 }
1299                         }
1300
1301                         /* rewrite the attribute description */
1302                         (*ap)->a_desc = mapping->m_dst_ad;
1303
1304                         /* will need to check for duplicate attrs */
1305                         check_duplicate_attrs++;
1306                 }
1307
1308                 if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
1309                         if ( stripEntryDN ) {
1310                                 /* will be generated by frontend */
1311                                 goto cleanup_attr;
1312                         }
1313                         
1314                 } else if ( !isupdate
1315                         && !get_relax( op )
1316                         && (*ap)->a_desc->ad_type->sat_no_user_mod 
1317                         && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
1318                 {
1319                         goto next_attr;
1320                 }
1321
1322                 if ( last == -1 ) { /* not yet counted */ 
1323                         last = (*ap)->a_numvals;
1324                 }
1325
1326                 if ( last == 0 ) {
1327                         /* empty? leave it in place because of attrsonly and vlv */
1328                         goto next_attr;
1329                 }
1330                 last--;
1331
1332                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
1333                                 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
1334                 {
1335                         struct berval   *bv;
1336                         
1337                         for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1338                                 struct berval   mapped;
1339
1340                                 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
1341                                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
1342 remove_oc:;
1343                                         ch_free( bv[0].bv_val );
1344                                         BER_BVZERO( &bv[0] );
1345                                         if ( &(*ap)->a_vals[last] > &bv[0] ) {
1346                                                 bv[0] = (*ap)->a_vals[last];
1347                                                 BER_BVZERO( &(*ap)->a_vals[last] );
1348                                         }
1349                                         last--;
1350                                         bv--;
1351
1352                                 } else if ( mapped.bv_val != bv[0].bv_val
1353                                         && ber_bvstrcasecmp( &mapped, &bv[0] ) != 0 )
1354                                 {
1355                                         int     i;
1356
1357                                         for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[ i ] ); i++ ) {
1358                                                 if ( &(*ap)->a_vals[ i ] == bv ) {
1359                                                         continue;
1360                                                 }
1361
1362                                                 if ( ber_bvstrcasecmp( &mapped, &(*ap)->a_vals[ i ] ) == 0 ) {
1363                                                         break;
1364                                                 }
1365                                         }
1366
1367                                         if ( !BER_BVISNULL( &(*ap)->a_vals[ i ] ) ) {
1368                                                 goto remove_oc;
1369                                         }
1370
1371                                         /*
1372                                          * FIXME: after LBER_FREEing
1373                                          * the value is replaced by
1374                                          * ch_alloc'ed memory
1375                                          */
1376                                         ber_bvreplace( &bv[0], &mapped );
1377
1378                                         /* FIXME: will need to check
1379                                          * if the structuralObjectClass
1380                                          * changed */
1381                                 }
1382                         }
1383
1384                 /*
1385                  * It is necessary to try to rewrite attributes with
1386                  * dn syntax because they might be used in ACLs as
1387                  * members of groups; since ACLs are applied to the
1388                  * rewritten stuff, no dn-based subject clause could
1389                  * be used at the ldap backend side (see
1390                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
1391                  * The problem can be overcome by moving the dn-based
1392                  * ACLs to the target directory server, and letting
1393                  * everything pass thru the ldap backend. */
1394                 /* FIXME: handle distinguishedName-like syntaxes, like
1395                  * nameAndOptionalUID */
1396                 } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
1397                                 || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
1398                 {
1399                         dc.ctx = "searchAttrDN";
1400                         rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals, (*ap)->a_nvals );
1401                         if ( rc != LDAP_SUCCESS ) {
1402                                 goto cleanup_attr;
1403                         }
1404
1405                 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
1406                         dc.ctx = "searchAttrDN";
1407                         rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
1408                         if ( rc != LDAP_SUCCESS ) {
1409                                 goto cleanup_attr;
1410                         }
1411                 }
1412
1413
1414 next_attr:;
1415                 ap = &(*ap)->a_next;
1416                 continue;
1417
1418 cleanup_attr:;
1419                 a = *ap;
1420                 *ap = (*ap)->a_next;
1421
1422                 attr_free( a );
1423         }
1424
1425         /* only check if some mapping occurred */
1426         if ( check_duplicate_attrs ) {
1427                 for ( ap = a_first; *ap != NULL; ap = &(*ap)->a_next ) {
1428                         Attribute       **tap;
1429
1430                         for ( tap = &(*ap)->a_next; *tap != NULL; ) {
1431                                 if ( (*tap)->a_desc == (*ap)->a_desc ) {
1432                                         Entry           e = { 0 };
1433                                         Modification    mod = { 0 };
1434                                         const char      *text = NULL;
1435                                         char            textbuf[ SLAP_TEXT_BUFLEN ];
1436                                         Attribute       *next = (*tap)->a_next;
1437
1438                                         BER_BVSTR( &e.e_name, "" );
1439                                         BER_BVSTR( &e.e_nname, "" );
1440                                         e.e_attrs = *ap;
1441                                         mod.sm_op = LDAP_MOD_ADD;
1442                                         mod.sm_desc = (*ap)->a_desc;
1443                                         mod.sm_type = mod.sm_desc->ad_cname;
1444                                         mod.sm_numvals = (*tap)->a_numvals;
1445                                         mod.sm_values = (*tap)->a_vals;
1446                                         if ( (*tap)->a_nvals != (*tap)->a_vals ) {
1447                                                 mod.sm_nvalues = (*tap)->a_nvals;
1448                                         }
1449
1450                                         (void)modify_add_values( &e, &mod,
1451                                                 /* permissive */ 1,
1452                                                 &text, textbuf, sizeof( textbuf ) );
1453
1454                                         /* should not insert new attrs! */
1455                                         assert( e.e_attrs == *ap );
1456
1457                                         attr_free( *tap );
1458                                         *tap = next;
1459
1460                                 } else {
1461                                         tap = &(*tap)->a_next;
1462                                 }
1463                         }
1464                 }
1465         }
1466
1467         return 0;
1468 }
1469
1470 /* Should return SLAP_CB_CONTINUE or failure, never LDAP_SUCCESS. */
1471 static int
1472 rwm_send_entry( Operation *op, SlapReply *rs )
1473 {
1474         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1475         struct ldaprwmap        *rwmap = 
1476                         (struct ldaprwmap *)on->on_bi.bi_private;
1477
1478         Entry                   *e = NULL;
1479         struct berval           dn = BER_BVNULL,
1480                                 ndn = BER_BVNULL;
1481         dncookie                dc;
1482         int                     rc;
1483
1484         assert( rs->sr_entry != NULL );
1485
1486         /*
1487          * Rewrite the dn of the result, if needed
1488          */
1489         dc.rwmap = rwmap;
1490         dc.conn = op->o_conn;
1491         dc.rs = NULL; 
1492         dc.ctx = "searchEntryDN";
1493
1494         e = rs->sr_entry;
1495         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
1496                 /* FIXME: all we need to duplicate are:
1497                  * - dn
1498                  * - ndn
1499                  * - attributes that are requested
1500                  * - no values if attrsonly is set
1501                  */
1502                 e = entry_dup( e );
1503                 if ( e == NULL ) {
1504                         rc = LDAP_NO_MEMORY;
1505                         goto fail;
1506                 }
1507         } else if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1508                 /* ITS#6423: REP_ENTRY_MUSTRELEASE incompatible
1509                  * with REP_ENTRY_MODIFIABLE */
1510                 RS_ASSERT( 0 );
1511                 rc = 1;
1512                 goto fail;
1513         }
1514
1515         /*
1516          * Note: this may fail if the target host(s) schema differs
1517          * from the one known to the meta, and a DN with unknown
1518          * attributes is returned.
1519          */
1520         dn = e->e_name;
1521         ndn = e->e_nname;
1522         rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
1523         if ( rc != LDAP_SUCCESS ) {
1524                 rc = 1;
1525                 goto fail;
1526         }
1527
1528         if ( e->e_name.bv_val != dn.bv_val ) {
1529                 ch_free( e->e_name.bv_val );
1530                 ch_free( e->e_nname.bv_val );
1531
1532                 e->e_name = dn;
1533                 e->e_nname = ndn;
1534         }
1535
1536         /* TODO: map entry attribute types, objectclasses 
1537          * and dn-valued attribute values */
1538
1539         /* FIXME: the entries are in the remote mapping form;
1540          * so we need to select those attributes we are willing
1541          * to return, and remap them accordingly */
1542         (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
1543
1544         if ( e != rs->sr_entry ) {
1545                 /* Reimplementing rs_replace_entry(), I suppose to
1546                  * bypass our own dubious rwm_entry_release_rw() */
1547                 if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1548                         rs->sr_flags ^= REP_ENTRY_MUSTRELEASE;
1549                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
1550                         be_entry_release_r( op, rs->sr_entry );
1551                         op->o_bd->bd_info = (BackendInfo *)on;
1552                 } else if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
1553                         entry_free( rs->sr_entry );
1554                 }
1555                 rs->sr_entry = e;
1556                 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
1557         }
1558
1559         return SLAP_CB_CONTINUE;
1560
1561 fail:;
1562         if ( e != NULL && e != rs->sr_entry ) {
1563                 if ( e->e_name.bv_val == dn.bv_val ) {
1564                         BER_BVZERO( &e->e_name );
1565                 }
1566
1567                 if ( e->e_nname.bv_val == ndn.bv_val ) {
1568                         BER_BVZERO( &e->e_nname );
1569                 }
1570
1571                 entry_free( e );
1572         }
1573
1574         if ( !BER_BVISNULL( &dn ) ) {
1575                 ch_free( dn.bv_val );
1576         }
1577
1578         if ( !BER_BVISNULL( &ndn ) ) {
1579                 ch_free( ndn.bv_val );
1580         }
1581
1582         return rc;
1583 }
1584
1585 static int
1586 rwm_operational( Operation *op, SlapReply *rs )
1587 {
1588         /* FIXME: the entries are in the remote mapping form;
1589          * so we need to select those attributes we are willing
1590          * to return, and remap them accordingly */
1591         if ( rs->sr_operational_attrs ) {
1592                 rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
1593         }
1594
1595         return SLAP_CB_CONTINUE;
1596 }
1597
1598 #if 0
1599 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1600  * rewritten for subsequent operations; fine for plain suffixmassage,
1601  * but destroys everything else */
1602 static int
1603 rwm_chk_referrals( Operation *op, SlapReply *rs )
1604 {
1605         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1606         int                     rc;
1607
1608         rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1609         if ( rc != LDAP_SUCCESS ) {
1610                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1611                 send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1612                 return -1;
1613         }
1614
1615         return SLAP_CB_CONTINUE;
1616 }
1617 #endif
1618
1619 static int
1620 rwm_rw_config(
1621         BackendDB       *be,
1622         const char      *fname,
1623         int             lineno,
1624         int             argc,
1625         char            **argv )
1626 {
1627         slap_overinst           *on = (slap_overinst *) be->bd_info;
1628         struct ldaprwmap        *rwmap = 
1629                         (struct ldaprwmap *)on->on_bi.bi_private;
1630
1631         return rewrite_parse( rwmap->rwm_rw,
1632                                 fname, lineno, argc, argv );
1633
1634         return 0;
1635 }
1636
1637 static int
1638 rwm_suffixmassage_config(
1639         BackendDB       *be,
1640         const char      *fname,
1641         int             lineno,
1642         int             argc,
1643         char            **argv )
1644 {
1645         slap_overinst           *on = (slap_overinst *) be->bd_info;
1646         struct ldaprwmap        *rwmap = 
1647                         (struct ldaprwmap *)on->on_bi.bi_private;
1648
1649         struct berval           bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1650         int                     massaged;
1651         int                     rc;
1652                 
1653         /*
1654          * syntax:
1655          * 
1656          *      suffixmassage [<suffix>] <massaged suffix>
1657          *
1658          * the [<suffix>] field must be defined as a valid suffix
1659          * for the current database;
1660          * the <massaged suffix> shouldn't have already been
1661          * defined as a valid suffix for the current server
1662          */
1663         if ( argc == 2 ) {
1664                 if ( be->be_suffix == NULL ) {
1665                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1666                                        " \"suffixMassage [<suffix>]"
1667                                        " <massaged suffix>\" without "
1668                                        "<suffix> part requires database "
1669                                        "suffix be defined first.\n",
1670                                 fname, lineno, 0 );
1671                         return 1;
1672                 }
1673                 bvnc = be->be_suffix[ 0 ];
1674                 massaged = 1;
1675
1676         } else if ( argc == 3 ) {
1677                 ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1678                 massaged = 2;
1679
1680         } else  {
1681                 Debug( LDAP_DEBUG_ANY, "%s: line %d: syntax is"
1682                                " \"suffixMassage [<suffix>]"
1683                                " <massaged suffix>\"\n",
1684                         fname, lineno, 0 );
1685                 return 1;
1686         }
1687
1688         if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1689                 Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix DN %s is invalid\n",
1690                         fname, lineno, bvnc.bv_val );
1691                 return 1;
1692         }
1693
1694         ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1695         if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1696                 Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix DN %s is invalid\n",
1697                                 fname, lineno, brnc.bv_val );
1698                 free( nvnc.bv_val );
1699                 free( pvnc.bv_val );
1700                 return 1;
1701         }
1702
1703         /*
1704          * The suffix massaging is emulated 
1705          * by means of the rewrite capabilities
1706          */
1707         rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1708                         &pvnc, &nvnc, &prnc, &nrnc );
1709         free( nvnc.bv_val );
1710         free( pvnc.bv_val );
1711         free( nrnc.bv_val );
1712         free( prnc.bv_val );
1713
1714         return rc;
1715 }
1716
1717 static int
1718 rwm_m_config(
1719         BackendDB       *be,
1720         const char      *fname,
1721         int             lineno,
1722         int             argc,
1723         char            **argv )
1724 {
1725         slap_overinst           *on = (slap_overinst *) be->bd_info;
1726         struct ldaprwmap        *rwmap = 
1727                         (struct ldaprwmap *)on->on_bi.bi_private;
1728
1729         /* objectclass/attribute mapping */
1730         return rwm_map_config( &rwmap->rwm_oc,
1731                         &rwmap->rwm_at,
1732                         fname, lineno, argc, argv );
1733 }
1734
1735 static int
1736 rwm_response( Operation *op, SlapReply *rs )
1737 {
1738         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
1739         struct ldaprwmap        *rwmap = 
1740                         (struct ldaprwmap *)on->on_bi.bi_private;
1741
1742         int             rc;
1743
1744         if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1745                 return rwm_send_entry( op, rs );
1746         }
1747
1748         switch( op->o_tag ) {
1749         case LDAP_REQ_SEARCH:
1750         case LDAP_REQ_BIND:
1751         case LDAP_REQ_ADD:
1752         case LDAP_REQ_DELETE:
1753         case LDAP_REQ_MODRDN:
1754         case LDAP_REQ_MODIFY:
1755         case LDAP_REQ_COMPARE:
1756         case LDAP_REQ_EXTENDED:
1757                 if ( rs->sr_ref ) {
1758                         dncookie                dc;
1759
1760                         /*
1761                          * Rewrite the dn of the referrals, if needed
1762                          */
1763                         dc.rwmap = rwmap;
1764                         dc.conn = op->o_conn;
1765                         dc.rs = NULL; 
1766                         dc.ctx = "referralDN";
1767                         rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1768                         /* FIXME: impossible, so far */
1769                         if ( rc != LDAP_SUCCESS ) {
1770                                 rs->sr_err = rc;
1771                                 break;
1772                         }
1773                 }
1774
1775                 rwm_matched( op, rs );
1776                 break;
1777         }
1778
1779         return SLAP_CB_CONTINUE;
1780 }
1781
1782 static int
1783 rwm_db_config(
1784         BackendDB       *be,
1785         const char      *fname,
1786         int             lineno,
1787         int             argc,
1788         char            **argv )
1789 {
1790         slap_overinst           *on = (slap_overinst *) be->bd_info;
1791         struct ldaprwmap        *rwmap = 
1792                         (struct ldaprwmap *)on->on_bi.bi_private;
1793
1794         int             rc = 0;
1795         char            *argv0 = NULL;
1796
1797         if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1798                 argv0 = argv[ 0 ];
1799                 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1800         }
1801
1802         if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1803                 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1804
1805         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1806                 rc = rwm_m_config( be, fname, lineno, argc, argv );
1807
1808         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1809                 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1810
1811         } else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
1812                 if ( argc != 2 ) {
1813                         Debug( LDAP_DEBUG_ANY,
1814                 "%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
1815                                         fname, lineno, 0 );
1816                         return( 1 );
1817                 }
1818
1819                 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1820                         rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F_MASK2);
1821
1822                 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1823                         rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
1824
1825                 /* TODO: not implemented yet */
1826                 } else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1827                         Debug( LDAP_DEBUG_ANY,
1828                 "%s: line %d: \"discover\" not supported yet "
1829                 "in \"t-f-support {no|yes|discover}\".\n",
1830                                         fname, lineno, 0 );
1831                         return( 1 );
1832 #if 0
1833                         rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
1834 #endif
1835
1836                 } else {
1837                         Debug( LDAP_DEBUG_ANY,
1838         "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1839                                 fname, lineno, argv[ 1 ] );
1840                         return 1;
1841                 }
1842
1843         } else if ( strcasecmp( argv[0], "normalize-mapped-attrs" ) ==  0 ) {
1844                 if ( argc !=2 ) { 
1845                         Debug( LDAP_DEBUG_ANY,
1846                 "%s: line %d: \"normalize-mapped-attrs {no|yes}\" needs 1 argument.\n",
1847                                         fname, lineno, 0 );
1848                         return( 1 );
1849                 }
1850
1851                 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1852                         rwmap->rwm_flags &= ~(RWM_F_NORMALIZE_MAPPED_ATTRS);
1853
1854                 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1855                         rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
1856                 }
1857
1858         } else {
1859                 rc = SLAP_CONF_UNKNOWN;
1860         }
1861
1862         if ( argv0 ) {
1863                 argv[ 0 ] = argv0;
1864         }
1865
1866         return rc;
1867 }
1868
1869 /*
1870  * dynamic configuration...
1871  */
1872
1873 enum {
1874         /* rewrite */
1875         RWM_CF_REWRITE = 1,
1876
1877         /* map */
1878         RWM_CF_MAP,
1879         RWM_CF_T_F_SUPPORT,
1880         RWM_CF_NORMALIZE_MAPPED,
1881         RWM_CF_DROP_UNREQUESTED,
1882
1883         RWM_CF_LAST
1884 };
1885
1886 static slap_verbmasks t_f_mode[] = {
1887         { BER_BVC( "true" ),            RWM_F_SUPPORT_T_F },
1888         { BER_BVC( "yes" ),             RWM_F_SUPPORT_T_F },
1889         { BER_BVC( "discover" ),        RWM_F_SUPPORT_T_F_DISCOVER },
1890         { BER_BVC( "false" ),           RWM_F_NONE },
1891         { BER_BVC( "no" ),              RWM_F_NONE },
1892         { BER_BVNULL,                   0 }
1893 };
1894
1895 static ConfigDriver rwm_cf_gen;
1896
1897 static ConfigTable rwmcfg[] = {
1898         { "rwm-rewrite", "rewrite",
1899                 2, 0, STRLENOF("rwm-rewrite"),
1900                 ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
1901                 "( OLcfgOvAt:16.1 NAME 'olcRwmRewrite' "
1902                         "DESC 'Rewrites strings' "
1903                         "EQUALITY caseIgnoreMatch "
1904                         "SYNTAX OMsDirectoryString "
1905                         "X-ORDERED 'VALUES' )",
1906                 NULL, NULL },
1907
1908         { "rwm-suffixmassage", "[virtual]> <real",
1909                 2, 3, 0, ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
1910                 NULL, NULL, NULL },
1911                 
1912         { "rwm-t-f-support", "true|false|discover",
1913                 2, 2, 0, ARG_MAGIC|RWM_CF_T_F_SUPPORT, rwm_cf_gen,
1914                 "( OLcfgOvAt:16.2 NAME 'olcRwmTFSupport' "
1915                         "DESC 'Absolute filters support' "
1916                         "SYNTAX OMsDirectoryString "
1917                         "SINGLE-VALUE )",
1918                 NULL, NULL },
1919
1920         { "rwm-map", "{objectClass|attribute}",
1921                 2, 4, 0, ARG_MAGIC|RWM_CF_MAP, rwm_cf_gen,
1922                 "( OLcfgOvAt:16.3 NAME 'olcRwmMap' "
1923                         "DESC 'maps attributes/objectClasses' "
1924                         "EQUALITY caseIgnoreMatch "
1925                         "SYNTAX OMsDirectoryString "
1926                         "X-ORDERED 'VALUES' )",
1927                 NULL, NULL },
1928
1929         { "rwm-normalize-mapped-attrs", "true|false",
1930                 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_NORMALIZE_MAPPED, rwm_cf_gen,
1931                 "( OLcfgOvAt:16.4 NAME 'olcRwmNormalizeMapped' "
1932                         "DESC 'Normalize mapped attributes/objectClasses' "
1933                         "SYNTAX OMsBoolean "
1934                         "SINGLE-VALUE )",
1935                 NULL, NULL },
1936
1937         { "rwm-drop-unrequested-attrs", "true|false",
1938                 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_DROP_UNREQUESTED, rwm_cf_gen,
1939                 "( OLcfgOvAt:16.5 NAME 'olcRwmDropUnrequested' "
1940                         "DESC 'Drop unrequested attributes' "
1941                         "SYNTAX OMsBoolean "
1942                         "SINGLE-VALUE )",
1943                 NULL, NULL },
1944
1945         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1946 };
1947
1948 static ConfigOCs rwmocs[] = {
1949         { "( OLcfgOvOc:16.1 "
1950                 "NAME 'olcRwmConfig' "
1951                 "DESC 'Rewrite/remap configuration' "
1952                 "SUP olcOverlayConfig "
1953                 "MAY ( "
1954                         "olcRwmRewrite $ "
1955                         "olcRwmTFSupport $ "
1956                         "olcRwmMap $ "
1957                         "olcRwmNormalizeMapped "
1958                         ") )",
1959                 Cft_Overlay, rwmcfg, NULL, NULL },
1960         { NULL, 0, NULL }
1961 };
1962
1963 static void
1964 slap_bv_x_ordered_unparse( BerVarray in, BerVarray *out )
1965 {
1966         int             i;
1967         BerVarray       bva = NULL;
1968         char            ibuf[32], *ptr;
1969         struct berval   idx;
1970
1971         assert( in != NULL );
1972
1973         for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
1974                 /* count'em */ ;
1975
1976         if ( i == 0 ) {
1977                 return;
1978         }
1979
1980         idx.bv_val = ibuf;
1981
1982         bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
1983         BER_BVZERO( &bva[ 0 ] );
1984
1985         for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
1986                 idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), "{%d}", i );
1987                 if ( idx.bv_len >= sizeof( ibuf ) ) {
1988                         ber_bvarray_free( bva );
1989                         return;
1990                 }
1991
1992                 bva[i].bv_len = idx.bv_len + in[i].bv_len;
1993                 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
1994                 ptr = lutil_strcopy( bva[i].bv_val, ibuf );
1995                 ptr = lutil_strcopy( ptr, in[i].bv_val );
1996                 *ptr = '\0';
1997                 BER_BVZERO( &bva[ i + 1 ] );
1998         }
1999
2000         *out = bva;
2001 }
2002
2003 static int
2004 rwm_bva_add(
2005         BerVarray               *bva,
2006         int                     idx,
2007         char                    **argv )
2008 {
2009         char            *line;
2010         struct berval   bv;
2011
2012         line = ldap_charray2str( argv, "\" \"" );
2013         if ( line != NULL ) {
2014                 int     len = strlen( argv[ 0 ] );
2015
2016                 ber_str2bv( line, 0, 0, &bv );
2017                 AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
2018                         bv.bv_len - ( len + 1 ) );
2019                 bv.bv_val[ bv.bv_len - 1 ] = '"';
2020
2021                 if ( idx == -1 ) {
2022                         ber_bvarray_add( bva, &bv );
2023
2024                 } else {
2025                         (*bva)[ idx ] = bv;
2026                 }
2027
2028                 return 0;
2029         }
2030
2031         return -1;
2032 }
2033
2034 static int
2035 rwm_bva_rewrite_add(
2036         struct ldaprwmap        *rwmap,
2037         int                     idx,
2038         char                    **argv )
2039 {
2040         return rwm_bva_add( &rwmap->rwm_bva_rewrite, idx, argv );
2041 }
2042
2043 #ifdef unused
2044 static int
2045 rwm_bva_map_add(
2046         struct ldaprwmap        *rwmap,
2047         int                     idx,
2048         char                    **argv )
2049 {
2050         return rwm_bva_add( &rwmap->rwm_bva_map, idx, argv );
2051 }
2052 #endif /* unused */
2053
2054 static int
2055 rwm_info_init( struct rewrite_info ** rwm_rw )
2056 {
2057         char                    *rargv[ 3 ];
2058
2059         *rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
2060         if ( *rwm_rw == NULL ) {
2061                 return -1;
2062         }
2063
2064         /* this rewriteContext by default must be null;
2065          * rules can be added if required */
2066         rargv[ 0 ] = "rewriteContext";
2067         rargv[ 1 ] = "searchFilter";
2068         rargv[ 2 ] = NULL;
2069         rewrite_parse( *rwm_rw, "<suffix massage>", 1, 2, rargv );
2070
2071         rargv[ 0 ] = "rewriteContext";
2072         rargv[ 1 ] = "default";
2073         rargv[ 2 ] = NULL;
2074         rewrite_parse( *rwm_rw, "<suffix massage>", 2, 2, rargv );
2075
2076         return 0;
2077 }
2078
2079 static int
2080 rwm_cf_gen( ConfigArgs *c )
2081 {
2082         slap_overinst           *on = (slap_overinst *)c->bi;
2083         struct ldaprwmap        *rwmap = 
2084                         (struct ldaprwmap *)on->on_bi.bi_private;
2085
2086         BackendDB               db;
2087         char                    *argv0;
2088         int                     idx0 = 0;
2089         int                     rc = 0;
2090
2091         db = *c->be;
2092         db.bd_info = c->bi;
2093
2094         if ( c->op == SLAP_CONFIG_EMIT ) {
2095                 struct berval   bv = BER_BVNULL;
2096
2097                 switch ( c->type ) {
2098                 case RWM_CF_REWRITE:
2099                         if ( rwmap->rwm_bva_rewrite == NULL ) {
2100                                 rc = 1;
2101
2102                         } else {
2103                                 slap_bv_x_ordered_unparse( rwmap->rwm_bva_rewrite, &c->rvalue_vals );
2104                                 if ( !c->rvalue_vals ) {
2105                                         rc = 1;
2106                                 }
2107                         }
2108                         break;
2109
2110                 case RWM_CF_T_F_SUPPORT:
2111                         enum_to_verb( t_f_mode, (rwmap->rwm_flags & RWM_F_SUPPORT_T_F_MASK2), &bv );
2112                         if ( BER_BVISNULL( &bv ) ) {
2113                                 /* there's something wrong... */
2114                                 assert( 0 );
2115                                 rc = 1;
2116
2117                         } else {
2118                                 value_add_one( &c->rvalue_vals, &bv );
2119                         }
2120                         break;
2121
2122                 case RWM_CF_MAP:
2123                         if ( rwmap->rwm_bva_map == NULL ) {
2124                                 rc = 1;
2125
2126                         } else {
2127                                 slap_bv_x_ordered_unparse( rwmap->rwm_bva_map, &c->rvalue_vals );
2128                                 if ( !c->rvalue_vals ) {
2129                                         rc = 1;
2130                                 }
2131                         }
2132                         break;
2133
2134                 case RWM_CF_NORMALIZE_MAPPED:
2135                         c->value_int = ( rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS );
2136                         break;
2137
2138                 case RWM_CF_DROP_UNREQUESTED:
2139                         c->value_int = ( rwmap->rwm_flags & RWM_F_DROP_UNREQUESTED_ATTRS );
2140                         break;
2141
2142                 default:
2143                         assert( 0 );
2144                         rc = 1;
2145                 }
2146
2147                 return rc;
2148
2149         } else if ( c->op == LDAP_MOD_DELETE ) {
2150                 switch ( c->type ) {
2151                 case RWM_CF_REWRITE:
2152                         if ( c->valx >= 0 ) {
2153                                 int i;
2154
2155                                 for ( i = 0; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
2156                                         /* count'em */ ;
2157
2158                                 if ( c->valx >= i ) {
2159                                         rc = 1;
2160                                         break;
2161                                 }
2162
2163                                 ber_memfree( rwmap->rwm_bva_rewrite[ c->valx ].bv_val );
2164                                 for ( i = c->valx; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i + 1 ] ); i++ )
2165                                 {
2166                                         rwmap->rwm_bva_rewrite[ i ] = rwmap->rwm_bva_rewrite[ i + 1 ];
2167                                 }
2168                                 BER_BVZERO( &rwmap->rwm_bva_rewrite[ i ] );
2169
2170                                 rewrite_info_delete( &rwmap->rwm_rw );
2171                                 assert( rwmap->rwm_rw == NULL );
2172
2173                                 rc = rwm_info_init( &rwmap->rwm_rw );
2174
2175                                 for ( i = 0; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
2176                                 {
2177                                         ConfigArgs ca = { 0 };
2178
2179                                         ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
2180                                         ca.argc = 0;
2181                                         config_fp_parse_line( &ca );
2182                                         
2183                                         if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
2184                                                 rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2185                                                         ca.argc, ca.argv );
2186
2187                                         } else {
2188                                                 rc = rwm_rw_config( &db, c->fname, c->lineno,
2189                                                         ca.argc, ca.argv );
2190                                         }
2191
2192                                         ch_free( ca.tline );
2193                                         ch_free( ca.argv );
2194
2195                                         assert( rc == 0 );
2196                                 }
2197
2198                         } else if ( rwmap->rwm_rw != NULL ) {
2199                                 rewrite_info_delete( &rwmap->rwm_rw );
2200                                 assert( rwmap->rwm_rw == NULL );
2201
2202                                 ber_bvarray_free( rwmap->rwm_bva_rewrite );
2203                                 rwmap->rwm_bva_rewrite = NULL;
2204
2205                                 rc = rwm_info_init( &rwmap->rwm_rw );
2206                         }
2207                         break;
2208
2209                 case RWM_CF_T_F_SUPPORT:
2210                         rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
2211                         break;
2212
2213                 case RWM_CF_MAP:
2214                         if ( c->valx >= 0 ) {
2215                                 struct ldapmap rwm_oc = rwmap->rwm_oc;
2216                                 struct ldapmap rwm_at = rwmap->rwm_at;
2217                                 char *argv[5];
2218                                 int cnt = 0;
2219
2220                                 if ( rwmap->rwm_bva_map ) {
2221                                         for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ )
2222                                                 /* count */ ;
2223                                 }
2224
2225                                 if ( c->valx >= cnt ) {
2226                                         rc = 1;
2227                                         break;
2228                                 }
2229
2230                                 memset( &rwmap->rwm_oc, 0, sizeof( rwmap->rwm_oc ) );
2231                                 memset( &rwmap->rwm_at, 0, sizeof( rwmap->rwm_at ) );
2232
2233                                 /* re-parse all mappings except the one
2234                                  * that needs to be eliminated */
2235                                 argv[0] = "map";
2236                                 for ( cnt = 0; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
2237                                         ConfigArgs ca = { 0 };
2238
2239                                         if ( cnt == c->valx ) {
2240                                                 continue;
2241                                         }
2242
2243                                         ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
2244                                         ca.argc = 0;
2245                                         config_fp_parse_line( &ca );
2246                                         
2247                                         argv[1] = ca.argv[0];
2248                                         argv[2] = ca.argv[1];
2249                                         argv[3] = ca.argv[2];
2250                                         argv[4] = ca.argv[3];
2251                         
2252                                         rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
2253
2254                                         ch_free( ca.tline );
2255                                         ch_free( ca.argv );
2256
2257                                         /* in case of failure, restore
2258                                          * the existing mapping */
2259                                         if ( rc ) {
2260                                                 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2261                                                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2262                                                 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2263                                                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2264                                                 rwmap->rwm_oc = rwm_oc;
2265                                                 rwmap->rwm_at = rwm_at;
2266                                                 break;
2267                                         }
2268                                 }
2269
2270                                 /* in case of success, destroy the old mapping
2271                                  * and eliminate the deleted one */
2272                                 if ( rc == 0 ) {
2273                                         avl_free( rwm_oc.remap, rwm_mapping_dst_free );
2274                                         avl_free( rwm_oc.map, rwm_mapping_free );
2275                                         avl_free( rwm_at.remap, rwm_mapping_dst_free );
2276                                         avl_free( rwm_at.map, rwm_mapping_free );
2277
2278                                         ber_memfree( rwmap->rwm_bva_map[ c->valx ].bv_val );
2279                                         for ( cnt = c->valx; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
2280                                                 rwmap->rwm_bva_map[ cnt ] = rwmap->rwm_bva_map[ cnt + 1 ];
2281                                         }
2282                                 }
2283
2284                         } else {
2285                                 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2286                                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2287                                 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2288                                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2289
2290                                 rwmap->rwm_oc.remap = NULL;
2291                                 rwmap->rwm_oc.map = NULL;
2292                                 rwmap->rwm_at.remap = NULL;
2293                                 rwmap->rwm_at.map = NULL;
2294
2295                                 ber_bvarray_free( rwmap->rwm_bva_map );
2296                                 rwmap->rwm_bva_map = NULL;
2297                         }
2298                         break;
2299
2300                 case RWM_CF_NORMALIZE_MAPPED:
2301                         rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
2302                         break;
2303
2304                 case RWM_CF_DROP_UNREQUESTED:
2305                         rwmap->rwm_flags &= ~RWM_F_DROP_UNREQUESTED_ATTRS;
2306                         break;
2307
2308                 default:
2309                         return 1;
2310                 }
2311                 return rc;
2312         }
2313
2314         if ( strncasecmp( c->argv[ 0 ], "olcRwm", STRLENOF( "olcRwm" ) ) == 0 ) {
2315                 idx0 = 1;
2316         }
2317
2318         switch ( c->type ) {
2319         case RWM_CF_REWRITE:
2320                 if ( c->valx >= 0 ) {
2321                         struct rewrite_info *rwm_rw = rwmap->rwm_rw;
2322                         int i, last;
2323
2324                         for ( last = 0; rwmap->rwm_bva_rewrite && !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ last ] ); last++ )
2325                                 /* count'em */ ;
2326
2327                         if ( c->valx > last ) {
2328                                 c->valx = last;
2329                         }
2330
2331                         rwmap->rwm_rw = NULL;
2332                         rc = rwm_info_init( &rwmap->rwm_rw );
2333
2334                         for ( i = 0; i < c->valx; i++ ) {
2335                                 ConfigArgs ca = { 0 };
2336
2337                                 ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
2338                                 ca.argc = 0;
2339                                 config_fp_parse_line( &ca );
2340
2341                                 argv0 = ca.argv[ 0 ];
2342                                 ca.argv[ 0 ] += STRLENOF( "rwm-" );
2343                                 
2344                                 if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
2345                                         rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2346                                                 ca.argc, ca.argv );
2347
2348                                 } else {
2349                                         rc = rwm_rw_config( &db, c->fname, c->lineno,
2350                                                 ca.argc, ca.argv );
2351                                 }
2352
2353                                 ca.argv[ 0 ] = argv0;
2354
2355                                 ch_free( ca.tline );
2356                                 ch_free( ca.argv );
2357
2358                                 assert( rc == 0 );
2359                         }
2360
2361                         argv0 = c->argv[ idx0 ];
2362                         if ( strncasecmp( argv0, "rwm-", STRLENOF( "rwm-" ) ) != 0 ) {
2363                                 return 1;
2364                         }
2365                         c->argv[ idx0 ] += STRLENOF( "rwm-" );
2366                         if ( strcasecmp( c->argv[ idx0 ], "suffixmassage" ) == 0 ) {
2367                                 rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2368                                         c->argc - idx0, &c->argv[ idx0 ] );
2369
2370                         } else {
2371                                 rc = rwm_rw_config( &db, c->fname, c->lineno,
2372                                         c->argc - idx0, &c->argv[ idx0 ] );
2373                         }
2374                         c->argv[ idx0 ] = argv0;
2375                         if ( rc != 0 ) {
2376                                 rewrite_info_delete( &rwmap->rwm_rw );
2377                                 assert( rwmap->rwm_rw == NULL );
2378
2379                                 rwmap->rwm_rw = rwm_rw;
2380                                 return 1;
2381                         }
2382
2383                         for ( i = c->valx; rwmap->rwm_bva_rewrite && !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
2384                         {
2385                                 ConfigArgs ca = { 0 };
2386
2387                                 ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
2388                                 ca.argc = 0;
2389                                 config_fp_parse_line( &ca );
2390                                 
2391                                 argv0 = ca.argv[ 0 ];
2392                                 ca.argv[ 0 ] += STRLENOF( "rwm-" );
2393                                 
2394                                 if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
2395                                         rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2396                                                 ca.argc, ca.argv );
2397
2398                                 } else {
2399                                         rc = rwm_rw_config( &db, c->fname, c->lineno,
2400                                                 ca.argc, ca.argv );
2401                                 }
2402
2403                                 ca.argv[ 0 ] = argv0;
2404
2405                                 ch_free( ca.tline );
2406                                 ch_free( ca.argv );
2407
2408                                 assert( rc == 0 );
2409                         }
2410
2411                         rwmap->rwm_bva_rewrite = ch_realloc( rwmap->rwm_bva_rewrite,
2412                                 ( last + 2 )*sizeof( struct berval ) );
2413                         BER_BVZERO( &rwmap->rwm_bva_rewrite[last+1] );
2414
2415                         for ( i = last - 1; i >= c->valx; i-- )
2416                         {
2417                                 rwmap->rwm_bva_rewrite[ i + 1 ] = rwmap->rwm_bva_rewrite[ i ];
2418                         }
2419
2420                         rwm_bva_rewrite_add( rwmap, c->valx, &c->argv[ idx0 ] );
2421
2422                         rewrite_info_delete( &rwm_rw );
2423                         assert( rwm_rw == NULL );
2424
2425                         break;
2426                 }
2427
2428                 argv0 = c->argv[ idx0 ];
2429                 if ( strncasecmp( argv0, "rwm-", STRLENOF( "rwm-" ) ) != 0 ) {
2430                         return 1;
2431                 }
2432                 c->argv[ idx0 ] += STRLENOF( "rwm-" );
2433                 if ( strcasecmp( c->argv[ idx0 ], "suffixmassage" ) == 0 ) {
2434                         rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2435                                 c->argc - idx0, &c->argv[ idx0 ] );
2436
2437                 } else {
2438                         rc = rwm_rw_config( &db, c->fname, c->lineno,
2439                                 c->argc - idx0, &c->argv[ idx0 ] );
2440                 }
2441                 c->argv[ idx0 ] = argv0;
2442                 if ( rc ) {
2443                         return 1;
2444
2445                 } else {
2446                         rwm_bva_rewrite_add( rwmap, -1, &c->argv[ idx0 ] );
2447                 }
2448                 break;
2449
2450         case RWM_CF_T_F_SUPPORT:
2451                 rc = verb_to_mask( c->argv[ 1 ], t_f_mode );
2452                 if ( BER_BVISNULL( &t_f_mode[ rc ].word ) ) {
2453                         return 1;
2454                 }
2455
2456                 rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
2457                 rwmap->rwm_flags |= t_f_mode[ rc ].mask;
2458                 rc = 0;
2459                 break;
2460
2461         case RWM_CF_MAP:
2462                 if ( c->valx >= 0 ) {
2463                         struct ldapmap rwm_oc = rwmap->rwm_oc;
2464                         struct ldapmap rwm_at = rwmap->rwm_at;
2465                         char *argv[5];
2466                         int cnt = 0;
2467
2468                         if ( rwmap->rwm_bva_map ) {
2469                                 for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ )
2470                                         /* count */ ;
2471                         }
2472
2473                         if ( c->valx >= cnt ) {
2474                                 c->valx = cnt;
2475                         }
2476
2477                         memset( &rwmap->rwm_oc, 0, sizeof( rwmap->rwm_oc ) );
2478                         memset( &rwmap->rwm_at, 0, sizeof( rwmap->rwm_at ) );
2479
2480                         /* re-parse all mappings, including the one
2481                          * that needs to be added */
2482                         argv[0] = "map";
2483                         for ( cnt = 0; cnt < c->valx; cnt++ ) {
2484                                 ConfigArgs ca = { 0 };
2485
2486                                 ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
2487                                 ca.argc = 0;
2488                                 config_fp_parse_line( &ca );
2489
2490                                 argv[1] = ca.argv[0];
2491                                 argv[2] = ca.argv[1];
2492                                 argv[3] = ca.argv[2];
2493                                 argv[4] = ca.argv[3];
2494                         
2495                                 rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
2496
2497                                 ch_free( ca.tline );
2498                                 ch_free( ca.argv );
2499
2500                                 /* in case of failure, restore
2501                                  * the existing mapping */
2502                                 if ( rc ) {
2503                                         goto rwmmap_fail;
2504                                 }
2505                         }
2506
2507                         argv0 = c->argv[0];
2508                         c->argv[0] = "map";
2509                         rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
2510                         c->argv[0] = argv0;
2511                         if ( rc ) {
2512                                 goto rwmmap_fail;
2513                         }
2514
2515                         if ( rwmap->rwm_bva_map ) {
2516                                 for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
2517                                         ConfigArgs ca = { 0 };
2518
2519                                         ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
2520                                         ca.argc = 0;
2521                                         config_fp_parse_line( &ca );
2522                         
2523                                         argv[1] = ca.argv[0];
2524                                         argv[2] = ca.argv[1];
2525                                         argv[3] = ca.argv[2];
2526                                         argv[4] = ca.argv[3];
2527                         
2528                                         rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
2529
2530                                         ch_free( ca.tline );
2531                                         ch_free( ca.argv );
2532
2533                                         /* in case of failure, restore
2534                                          * the existing mapping */
2535                                         if ( rc ) {
2536                                                 goto rwmmap_fail;
2537                                         }
2538                                 }
2539                         }
2540
2541                         /* in case of success, destroy the old mapping
2542                          * and add the new one */
2543                         if ( rc == 0 ) {
2544                                 BerVarray tmp;
2545                                 struct berval bv, *bvp = &bv;
2546
2547                                 if ( rwm_bva_add( &bvp, 0, &c->argv[ idx0 ] ) ) {
2548                                         rc = 1;
2549                                         goto rwmmap_fail;
2550                                 }
2551                                         
2552                                 tmp = ber_memrealloc( rwmap->rwm_bva_map,
2553                                         sizeof( struct berval )*( cnt + 2 ) );
2554                                 if ( tmp == NULL ) {
2555                                         ber_memfree( bv.bv_val );
2556                                         rc = 1;
2557                                         goto rwmmap_fail;
2558                                 }
2559                                 rwmap->rwm_bva_map = tmp;
2560                                 BER_BVZERO( &rwmap->rwm_bva_map[ cnt + 1 ] );
2561
2562                                 avl_free( rwm_oc.remap, rwm_mapping_dst_free );
2563                                 avl_free( rwm_oc.map, rwm_mapping_free );
2564                                 avl_free( rwm_at.remap, rwm_mapping_dst_free );
2565                                 avl_free( rwm_at.map, rwm_mapping_free );
2566
2567                                 for ( ; cnt-- > c->valx; ) {
2568                                         rwmap->rwm_bva_map[ cnt + 1 ] = rwmap->rwm_bva_map[ cnt ];
2569                                 }
2570                                 rwmap->rwm_bva_map[ c->valx ] = bv;
2571
2572                         } else {
2573 rwmmap_fail:;
2574                                 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2575                                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2576                                 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2577                                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2578                                 rwmap->rwm_oc = rwm_oc;
2579                                 rwmap->rwm_at = rwm_at;
2580                         }
2581
2582                         break;
2583                 }
2584
2585                 argv0 = c->argv[ 0 ];
2586                 c->argv[ 0 ] += STRLENOF( "rwm-" );
2587                 rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
2588                 c->argv[ 0 ] = argv0;
2589                 if ( rc ) {
2590                         return 1;
2591
2592                 } else {
2593                         char            *line;
2594                         struct berval   bv;
2595
2596                         line = ldap_charray2str( &c->argv[ 1 ], " " );
2597                         if ( line != NULL ) {
2598                                 ber_str2bv( line, 0, 0, &bv );
2599                                 ber_bvarray_add( &rwmap->rwm_bva_map, &bv );
2600                         }
2601                 }
2602                 break;
2603
2604         case RWM_CF_NORMALIZE_MAPPED:
2605                 if ( c->value_int ) {
2606                         rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
2607                 } else {
2608                         rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
2609                 }
2610                 break;
2611
2612         case RWM_CF_DROP_UNREQUESTED:
2613                 if ( c->value_int ) {
2614                         rwmap->rwm_flags |= RWM_F_DROP_UNREQUESTED_ATTRS;
2615                 } else {
2616                         rwmap->rwm_flags &= ~RWM_F_DROP_UNREQUESTED_ATTRS;
2617                 }
2618                 break;
2619
2620         default:
2621                 assert( 0 );
2622                 return 1;
2623         }
2624
2625         return rc;
2626 }
2627
2628 static int
2629 rwm_db_init(
2630         BackendDB       *be,
2631         ConfigReply     *cr )
2632 {
2633         slap_overinst           *on = (slap_overinst *) be->bd_info;
2634         struct ldaprwmap        *rwmap;
2635         int                     rc = 0;
2636
2637         rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
2638
2639         /* default */
2640         rwmap->rwm_flags = RWM_F_DROP_UNREQUESTED_ATTRS;
2641
2642         rc = rwm_info_init( &rwmap->rwm_rw );
2643
2644         on->on_bi.bi_private = (void *)rwmap;
2645
2646         if ( rc ) {
2647                 (void)rwm_db_destroy( be, NULL );
2648         }
2649
2650         return rc;
2651 }
2652
2653 static int
2654 rwm_db_destroy(
2655         BackendDB       *be,
2656         ConfigReply     *cr )
2657 {
2658         slap_overinst   *on = (slap_overinst *) be->bd_info;
2659         int             rc = 0;
2660
2661         if ( on->on_bi.bi_private ) {
2662                 struct ldaprwmap        *rwmap = 
2663                         (struct ldaprwmap *)on->on_bi.bi_private;
2664
2665                 if ( rwmap->rwm_rw ) {
2666                         rewrite_info_delete( &rwmap->rwm_rw );
2667                         if ( rwmap->rwm_bva_rewrite )
2668                                 ber_bvarray_free( rwmap->rwm_bva_rewrite );
2669                 }
2670
2671                 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2672                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2673                 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2674                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2675                 ber_bvarray_free( rwmap->rwm_bva_map );
2676
2677                 ch_free( rwmap );
2678         }
2679
2680         return rc;
2681 }
2682
2683 static slap_overinst rwm = { { NULL } };
2684
2685 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
2686 static
2687 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
2688 int
2689 rwm_initialize( void )
2690 {
2691         int             rc;
2692
2693         /* Make sure we don't exceed the bits reserved for userland */
2694         config_check_userland( RWM_CF_LAST );
2695
2696         memset( &rwm, 0, sizeof( slap_overinst ) );
2697
2698         rwm.on_bi.bi_type = "rwm";
2699         rwm.on_bi.bi_flags =
2700                 SLAPO_BFLAG_SINGLE |
2701                 0;
2702
2703         rwm.on_bi.bi_db_init = rwm_db_init;
2704         rwm.on_bi.bi_db_config = rwm_db_config;
2705         rwm.on_bi.bi_db_destroy = rwm_db_destroy;
2706
2707         rwm.on_bi.bi_op_bind = rwm_op_bind;
2708         rwm.on_bi.bi_op_search = rwm_op_search;
2709         rwm.on_bi.bi_op_compare = rwm_op_compare;
2710         rwm.on_bi.bi_op_modify = rwm_op_modify;
2711         rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
2712         rwm.on_bi.bi_op_add = rwm_op_add;
2713         rwm.on_bi.bi_op_delete = rwm_op_delete;
2714         rwm.on_bi.bi_op_unbind = rwm_op_unbind;
2715         rwm.on_bi.bi_extended = rwm_extended;
2716 #if 1 /* TODO */
2717         rwm.on_bi.bi_entry_release_rw = rwm_entry_release_rw;
2718         rwm.on_bi.bi_entry_get_rw = rwm_entry_get_rw;
2719 #endif
2720
2721         rwm.on_bi.bi_operational = rwm_operational;
2722         rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
2723
2724         rwm.on_bi.bi_connection_init = rwm_conn_init;
2725         rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
2726
2727         rwm.on_response = rwm_response;
2728
2729         rwm.on_bi.bi_cf_ocs = rwmocs;
2730
2731         rc = config_register_schema( rwmcfg, rwmocs );
2732         if ( rc ) {
2733                 return rc;
2734         }
2735
2736         return overlay_register( &rwm );
2737 }
2738
2739 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
2740 int
2741 init_module( int argc, char *argv[] )
2742 {
2743         return rwm_initialize();
2744 }
2745 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
2746
2747 #endif /* SLAPD_OVER_RWM */