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