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