]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/rwm.c
ITS#5705
[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-2008 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         AttributeName *mapped_attrs;
38         OpRequest o_request;
39 } rwm_op_state;
40
41 static int
42 rwm_db_destroy( BackendDB *be, ConfigReply *cr );
43
44 typedef struct rwm_op_cb {
45         slap_callback cb;
46         rwm_op_state ros;
47 } rwm_op_cb;
48
49 static void
50 rwm_op_rollback( Operation *op, SlapReply *rs, rwm_op_state *ros )
51 {
52         if ( !BER_BVISNULL( &ros->ro_dn ) ) {
53                 op->o_req_dn = ros->ro_dn;
54         }
55         if ( !BER_BVISNULL( &ros->ro_ndn ) ) {
56                 op->o_req_ndn = ros->ro_ndn;
57         }
58
59         if ( !BER_BVISNULL( &ros->r_dn )
60                 && ros->r_dn.bv_val != ros->ro_dn.bv_val )
61         {
62                 assert( ros->r_dn.bv_val != ros->r_ndn.bv_val );
63                 ch_free( ros->r_dn.bv_val );
64                 BER_BVZERO( &ros->r_dn );
65         }
66
67         if ( !BER_BVISNULL( &ros->r_ndn )
68                 && ros->r_ndn.bv_val != ros->ro_ndn.bv_val )
69         {
70                 ch_free( ros->r_ndn.bv_val );
71                 BER_BVZERO( &ros->r_ndn );
72         }
73
74         BER_BVZERO( &ros->ro_dn );
75         BER_BVZERO( &ros->ro_ndn );
76
77         switch( ros->r_tag ) {
78         case LDAP_REQ_COMPARE:
79                 if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
80                         op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
81                 op->orc_ava = ros->orc_ava;
82                 break;
83         case LDAP_REQ_MODIFY:
84                 slap_mods_free( op->orm_modlist, 1 );
85                 op->orm_modlist = ros->orm_modlist;
86                 break;
87         case LDAP_REQ_MODRDN:
88                 if ( op->orr_newSup != ros->orr_newSup ) {
89                         ch_free( op->orr_newSup->bv_val );
90                         ch_free( op->orr_nnewSup->bv_val );
91                         op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
92                         op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
93                         op->orr_newSup = ros->orr_newSup;
94                         op->orr_nnewSup = ros->orr_nnewSup;
95                 }
96                 break;
97         case LDAP_REQ_SEARCH:
98                 ch_free( ros->mapped_attrs );
99                 filter_free_x( op, op->ors_filter, 1 );
100                 ch_free( op->ors_filterstr.bv_val );
101                 op->ors_attrs = ros->ors_attrs;
102                 op->ors_filter = ros->ors_filter;
103                 op->ors_filterstr = ros->ors_filterstr;
104                 break;
105         case LDAP_REQ_EXTENDED:
106                 if ( op->ore_reqdata != ros->ore_reqdata ) {
107                         ber_bvfree( op->ore_reqdata );
108                         op->ore_reqdata = ros->ore_reqdata;
109                 }
110                 break;
111         case LDAP_REQ_BIND:
112                 if ( rs->sr_err == LDAP_SUCCESS ) {
113 #if 0
114                         ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
115                         /* too late, c_mutex released */
116                         fprintf( stderr, "*** DN: \"%s\" => \"%s\"\n",
117                                 op->o_conn->c_ndn.bv_val,
118                                 op->o_req_ndn.bv_val );
119                         ber_bvreplace( &op->o_conn->c_ndn,
120                                 &op->o_req_ndn );
121                         ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
122 #endif
123                 }
124                 break;
125         default:        break;
126         }
127 }
128
129 static int
130 rwm_op_cleanup( Operation *op, SlapReply *rs )
131 {
132         slap_callback   *cb = op->o_callback;
133         rwm_op_state *ros = cb->sc_private;
134
135         if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
136                 op->o_abandon || rs->sr_err == SLAPD_ABANDON )
137         {
138                 rwm_op_rollback( op, rs, ros );
139
140                 op->o_callback = op->o_callback->sc_next;
141                 op->o_tmpfree( cb, op->o_tmpmemctx );
142         }
143
144         return SLAP_CB_CONTINUE;
145 }
146
147 static rwm_op_cb *
148 rwm_callback_get( Operation *op, SlapReply *rs )
149 {
150         rwm_op_cb       *roc = NULL;
151
152         roc = op->o_tmpalloc( sizeof( struct rwm_op_cb ), op->o_tmpmemctx );
153         roc->cb.sc_cleanup = rwm_op_cleanup;
154         roc->cb.sc_response = NULL;
155         roc->cb.sc_next = op->o_callback;
156         roc->cb.sc_private = &roc->ros;
157         roc->ros.r_tag = op->o_tag;
158         roc->ros.ro_dn = op->o_req_dn;
159         roc->ros.ro_ndn = op->o_req_ndn;
160         roc->ros.o_request = op->o_request;
161         BER_BVZERO( &roc->ros.r_dn );
162         BER_BVZERO( &roc->ros.r_ndn );
163
164         return roc;
165 }
166
167
168 static int
169 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
170         rwm_op_state *ros )
171 {
172         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
173         struct ldaprwmap        *rwmap = 
174                         (struct ldaprwmap *)on->on_bi.bi_private;
175
176         struct berval           dn = BER_BVNULL,
177                                 ndn = BER_BVNULL;
178         int                     rc = 0;
179         dncookie                dc;
180
181         /*
182          * Rewrite the dn if needed
183          */
184         dc.rwmap = rwmap;
185         dc.conn = op->o_conn;
186         dc.rs = rs;
187         dc.ctx = (char *)cookie;
188
189         /* NOTE: in those cases where only the ndn is available,
190          * and the caller sets op->o_req_dn = op->o_req_ndn,
191          * only rewrite the op->o_req_ndn and use it as 
192          * op->o_req_dn as well */
193         ndn = op->o_req_ndn;
194         if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
195                 dn = op->o_req_dn;
196                 rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
197         } else {
198                 rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
199         }
200
201         if ( rc != LDAP_SUCCESS ) {
202                 return rc;
203         }
204
205         if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
206                         || ndn.bv_val == op->o_req_ndn.bv_val )
207         {
208                 return LDAP_SUCCESS;
209         }
210
211         if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
212                 op->o_req_dn = dn;
213                 assert( BER_BVISNULL( &ros->r_dn ) );
214                 ros->r_dn = dn;
215         } else {
216                 op->o_req_dn = ndn;
217         }
218         op->o_req_ndn = ndn;
219         assert( BER_BVISNULL( &ros->r_ndn ) );
220         ros->r_ndn = ndn;
221
222         return LDAP_SUCCESS;
223 }
224
225 static int
226 rwm_op_add( Operation *op, SlapReply *rs )
227 {
228         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
229         struct ldaprwmap        *rwmap = 
230                         (struct ldaprwmap *)on->on_bi.bi_private;
231
232         int                     rc,
233                                 i;
234         Attribute               **ap = NULL;
235         char                    *olddn = op->o_req_dn.bv_val;
236         int                     isupdate;
237
238         rwm_op_cb               *roc = rwm_callback_get( op, rs );
239
240         rc = rwm_op_dn_massage( op, rs, "addDN", &roc->ros );
241         if ( rc != LDAP_SUCCESS ) {
242                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
243                 send_ldap_error( op, rs, rc, "addDN massage error" );
244                 return -1;
245         }
246
247         if ( olddn != op->o_req_dn.bv_val ) {
248                 ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
249                 ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
250         }
251
252         /* Count number of attributes in entry */ 
253         isupdate = be_shadow_update( op );
254         for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
255                 Attribute       *a;
256
257                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
258                                 (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
259                 {
260                         int             j, last;
261
262                         last = (*ap)->a_numvals - 1;
263                         for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
264                                 struct ldapmapping      *mapping = NULL;
265
266                                 ( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
267                                                 &mapping, RWM_MAP );
268                                 if ( mapping == NULL ) {
269                                         if ( rwmap->rwm_at.drop_missing ) {
270                                                 /* FIXME: we allow to remove objectClasses as well;
271                                                  * if the resulting entry is inconsistent, that's
272                                                  * the relayed database's business...
273                                                  */
274                                                 ch_free( (*ap)->a_vals[ j ].bv_val );
275                                                 if ( last > j ) {
276                                                         (*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
277                                                 }
278                                                 BER_BVZERO( &(*ap)->a_vals[ last ] );
279                                                 (*ap)->a_numvals--;
280                                                 last--;
281                                                 j--;
282                                         }
283
284                                 } else {
285                                         ch_free( (*ap)->a_vals[ j ].bv_val );
286                                         ber_dupbv( &(*ap)->a_vals[ j ], &mapping->m_dst );
287                                 }
288                         }
289
290                 } else if ( !isupdate && !get_relax( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
291                 {
292                         goto next_attr;
293
294                 } else {
295                         struct ldapmapping      *mapping = NULL;
296
297                         ( void )rwm_mapping( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
298                                         &mapping, RWM_MAP );
299                         if ( mapping == NULL ) {
300                                 if ( rwmap->rwm_at.drop_missing ) {
301                                         goto cleanup_attr;
302                                 }
303                         }
304
305                         if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
306                                         || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
307                         {
308                                 /*
309                                  * FIXME: rewrite could fail; in this case
310                                  * the operation should give up, right?
311                                  */
312                                 rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
313                                                 (*ap)->a_vals,
314                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
315                                 if ( rc ) {
316                                         goto cleanup_attr;
317                                 }
318
319                         } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
320                                 rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
321                                                 (*ap)->a_vals,
322                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
323                                 if ( rc != LDAP_SUCCESS ) {
324                                         goto cleanup_attr;
325                                 }
326                         }
327                 
328                         if ( mapping != NULL ) {
329                                 assert( mapping->m_dst_ad != NULL );
330                                 (*ap)->a_desc = mapping->m_dst_ad;
331                         }
332                 }
333
334 next_attr:;
335                 ap = &(*ap)->a_next;
336                 continue;
337
338 cleanup_attr:;
339                 /* FIXME: leaking attribute/values? */
340                 a = *ap;
341
342                 *ap = (*ap)->a_next;
343                 attr_free( a );
344         }
345
346         op->o_callback = &roc->cb;
347
348         return SLAP_CB_CONTINUE;
349 }
350
351 static int
352 rwm_conn_init( BackendDB *be, Connection *conn )
353 {
354         slap_overinst           *on = (slap_overinst *) be->bd_info;
355         struct ldaprwmap        *rwmap = 
356                         (struct ldaprwmap *)on->on_bi.bi_private;
357
358         ( void )rewrite_session_init( rwmap->rwm_rw, conn );
359
360         return SLAP_CB_CONTINUE;
361 }
362
363 static int
364 rwm_conn_destroy( BackendDB *be, Connection *conn )
365 {
366         slap_overinst           *on = (slap_overinst *) be->bd_info;
367         struct ldaprwmap        *rwmap = 
368                         (struct ldaprwmap *)on->on_bi.bi_private;
369
370         ( void )rewrite_session_delete( rwmap->rwm_rw, conn );
371
372         return SLAP_CB_CONTINUE;
373 }
374
375 static int
376 rwm_op_bind( Operation *op, SlapReply *rs )
377 {
378         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
379         int                     rc;
380
381         rwm_op_cb               *roc = rwm_callback_get( op, rs );
382
383         rc = rwm_op_dn_massage( op, rs, "bindDN", &roc->ros );
384         if ( rc != LDAP_SUCCESS ) {
385                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
386                 send_ldap_error( op, rs, rc, "bindDN massage error" );
387                 return -1;
388         }
389
390         overlay_callback_after_backover( op, &roc->cb, 1 );
391
392         return SLAP_CB_CONTINUE;
393 }
394
395 static int
396 rwm_op_unbind( Operation *op, SlapReply *rs )
397 {
398         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
399         struct ldaprwmap        *rwmap = 
400                         (struct ldaprwmap *)on->on_bi.bi_private;
401
402         rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
403
404         return SLAP_CB_CONTINUE;
405 }
406
407 static int
408 rwm_op_compare( Operation *op, SlapReply *rs )
409 {
410         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
411         struct ldaprwmap        *rwmap = 
412                         (struct ldaprwmap *)on->on_bi.bi_private;
413
414         int                     rc;
415         struct berval           mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
416
417         rwm_op_cb               *roc = rwm_callback_get( op, rs );
418
419         rc = rwm_op_dn_massage( op, rs, "compareDN", &roc->ros );
420         if ( rc != LDAP_SUCCESS ) {
421                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
422                 send_ldap_error( op, rs, rc, "compareDN massage error" );
423                 return -1;
424         }
425
426         /* if the attribute is an objectClass, try to remap its value */
427         if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
428                         || op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
429         {
430                 rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
431                                 &mapped_vals[0], RWM_MAP );
432                 if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
433                 {
434                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
435                         send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
436                         return -1;
437
438                 } else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
439                         ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
440                                 op->o_tmpmemctx );
441                 }
442
443         } else {
444                 struct ldapmapping      *mapping = NULL;
445                 AttributeDescription    *ad = op->orc_ava->aa_desc;
446
447                 ( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
448                                 &mapping, RWM_MAP );
449                 if ( mapping == NULL ) {
450                         if ( rwmap->rwm_at.drop_missing ) {
451                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
452                                 send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
453                                 return -1;
454                         }
455
456                 } else {
457                         assert( mapping->m_dst_ad != NULL );
458                         ad = mapping->m_dst_ad;
459                 }
460
461                 if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
462                                 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
463                 {
464                         struct berval   *mapped_valsp[2];
465                         
466                         mapped_valsp[0] = &mapped_vals[0];
467                         mapped_valsp[1] = &mapped_vals[1];
468
469                         mapped_vals[0] = op->orc_ava->aa_value;
470
471                         rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
472
473                         if ( rc != LDAP_SUCCESS ) {
474                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
475                                 send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
476                                 return -1;
477                         }
478
479                         if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
480                                 /* NOTE: if we get here, rwm_dnattr_rewrite()
481                                  * already freed the old value, so now 
482                                  * it's invalid */
483                                 ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
484                                         op->o_tmpmemctx );
485                                 ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
486                         }
487                 }
488                 op->orc_ava->aa_desc = ad;
489         }
490
491         op->o_callback = &roc->cb;
492
493         return SLAP_CB_CONTINUE;
494 }
495
496 static int
497 rwm_op_delete( Operation *op, SlapReply *rs )
498 {
499         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
500         int                     rc;
501
502         rwm_op_cb               *roc = rwm_callback_get( op, rs );
503
504         rc = rwm_op_dn_massage( op, rs, "deleteDN", &roc->ros );
505         if ( rc != LDAP_SUCCESS ) {
506                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
507                 send_ldap_error( op, rs, rc, "deleteDN massage error" );
508                 return -1;
509         }
510
511         op->o_callback = &roc->cb;
512
513         return SLAP_CB_CONTINUE;
514 }
515
516 static int
517 rwm_op_modify( Operation *op, SlapReply *rs )
518 {
519         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
520         struct ldaprwmap        *rwmap = 
521                         (struct ldaprwmap *)on->on_bi.bi_private;
522
523         int                     isupdate;
524         Modifications           **mlp;
525         int                     rc;
526
527         rwm_op_cb               *roc = rwm_callback_get( op, rs );
528
529         rc = rwm_op_dn_massage( op, rs, "modifyDN", &roc->ros );
530         if ( rc != LDAP_SUCCESS ) {
531                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
532                 send_ldap_error( op, rs, rc, "modifyDN massage error" );
533                 return -1;
534         }
535
536         isupdate = be_shadow_update( op );
537         for ( mlp = &op->orm_modlist; *mlp; ) {
538                 int                     is_oc = 0;
539                 Modifications           *ml = *mlp;
540                 struct ldapmapping      *mapping = NULL;
541
542                 /* ml points to a temporary mod until needs duplication */
543                 if ( ml->sml_desc == slap_schema.si_ad_objectClass 
544                                 || ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
545                 {
546                         is_oc = 1;
547
548                 } else if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
549                 {
550                         ml = ch_malloc( sizeof( Modifications ) );
551                         *ml = **mlp;
552                         if ( (*mlp)->sml_values ) {
553                                 ber_bvarray_dup_x( &ml->sml_values, (*mlp)->sml_values, NULL );
554                                 if ( (*mlp)->sml_nvalues ) {
555                                         ber_bvarray_dup_x( &ml->sml_nvalues, (*mlp)->sml_nvalues, NULL );
556                                 }
557                         }
558                         *mlp = ml;
559                         goto next_mod;
560
561                 } else {
562                         int                     drop_missing;
563
564                         drop_missing = rwm_mapping( &rwmap->rwm_at,
565                                         &ml->sml_desc->ad_cname,
566                                         &mapping, RWM_MAP );
567                         if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
568                         {
569                                 goto cleanup_mod;
570                         }
571                 }
572
573                 /* duplicate the modlist */
574                 ml = ch_malloc( sizeof( Modifications ));
575                 *ml = **mlp;
576                 *mlp = ml;
577
578                 if ( ml->sml_values != NULL ) {
579                         int i, num;
580                         struct berval *bva;
581
582                         for ( num = 0; !BER_BVISNULL( &ml->sml_values[ num ] ); num++ )
583                                 /* count values */ ;
584
585                         bva = ch_malloc( (num+1) * sizeof( struct berval ));
586                         for (i=0; i<num; i++)
587                                 ber_dupbv( &bva[i], &ml->sml_values[i] );
588                         BER_BVZERO( &bva[i] );
589                         ml->sml_values = bva;
590
591                         if ( ml->sml_nvalues ) {
592                                 bva = ch_malloc( (num+1) * sizeof( struct berval ));
593                                 for (i=0; i<num; i++)
594                                         ber_dupbv( &bva[i], &ml->sml_nvalues[i] );
595                                 BER_BVZERO( &bva[i] );
596                                 ml->sml_nvalues = bva;
597                         }
598
599                         if ( is_oc ) {
600                                 int     last, j;
601
602                                 last = num-1;
603
604                                 for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
605                                         struct ldapmapping      *oc_mapping = NULL;
606                 
607                                         ( void )rwm_mapping( &rwmap->rwm_oc, &ml->sml_values[ j ],
608                                                         &oc_mapping, RWM_MAP );
609                                         if ( oc_mapping == NULL ) {
610                                                 if ( rwmap->rwm_at.drop_missing ) {
611                                                         /* FIXME: we allow to remove objectClasses as well;
612                                                          * if the resulting entry is inconsistent, that's
613                                                          * the relayed database's business...
614                                                          */
615                                                         if ( last > j ) {
616                                                                 ch_free( ml->sml_values[ j ].bv_val );
617                                                                 ml->sml_values[ j ] = ml->sml_values[ last ];
618                                                         }
619                                                         BER_BVZERO( &ml->sml_values[ last ] );
620                                                         last--;
621                                                         j--;
622                                                 }
623         
624                                         } else {
625                                                 ch_free( ml->sml_values[ j ].bv_val );
626                                                 ber_dupbv( &ml->sml_values[ j ], &oc_mapping->m_dst );
627                                         }
628                                 }
629
630                         } else {
631                                 if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
632                                                 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
633                                 {
634                                         rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
635                                                         ml->sml_values,
636                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
637
638                                 } else if ( ml->sml_desc == slap_schema.si_ad_ref ) {
639                                         rc = rwm_referral_rewrite( op, rs,
640                                                         "referralAttrDN",
641                                                         ml->sml_values,
642                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
643                                         if ( rc != LDAP_SUCCESS ) {
644                                                 goto cleanup_mod;
645                                         }
646                                 }
647
648                                 if ( rc != LDAP_SUCCESS ) {
649                                         goto cleanup_mod;
650                                 }
651                         }
652                 }
653
654 next_mod:;
655                 if ( mapping != NULL ) {
656                         /* use new attribute description */
657                         assert( mapping->m_dst_ad != NULL );
658                         ml->sml_desc = mapping->m_dst_ad;
659                 }
660
661                 mlp = &ml->sml_next;
662                 continue;
663
664 cleanup_mod:;
665                 ml = *mlp;
666                 *mlp = (*mlp)->sml_next;
667                 slap_mod_free( &ml->sml_mod, 0 );
668                 free( ml );
669         }
670
671         op->o_callback = &roc->cb;
672
673         return SLAP_CB_CONTINUE;
674 }
675
676 static int
677 rwm_op_modrdn( Operation *op, SlapReply *rs )
678 {
679         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
680         struct ldaprwmap        *rwmap = 
681                         (struct ldaprwmap *)on->on_bi.bi_private;
682         
683         int                     rc;
684
685         rwm_op_cb               *roc = rwm_callback_get( op, rs );
686
687         if ( op->orr_newSup ) {
688                 dncookie        dc;
689                 struct berval   nnewSup = BER_BVNULL;
690                 struct berval   newSup = BER_BVNULL;
691
692                 /*
693                  * Rewrite the new superior, if defined and required
694                  */
695                 dc.rwmap = rwmap;
696                 dc.conn = op->o_conn;
697                 dc.rs = rs;
698                 dc.ctx = "newSuperiorDN";
699                 newSup = *op->orr_newSup;
700                 nnewSup = *op->orr_nnewSup;
701                 rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
702                 if ( rc != LDAP_SUCCESS ) {
703                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
704                         send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
705                         return -1;
706                 }
707
708                 if ( op->orr_newSup->bv_val != newSup.bv_val ) {
709                         op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ),
710                                 op->o_tmpmemctx );
711                         op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ),
712                                 op->o_tmpmemctx );
713                         *op->orr_newSup = newSup;
714                         *op->orr_nnewSup = nnewSup;
715                 }
716         }
717
718         /*
719          * Rewrite the dn, if needed
720          */
721         rc = rwm_op_dn_massage( op, rs, "renameDN", &roc->ros );
722         if ( rc != LDAP_SUCCESS ) {
723                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
724                 send_ldap_error( op, rs, rc, "renameDN massage error" );
725                 if ( op->orr_newSup != roc->ros.orr_newSup ) {
726                         ch_free( op->orr_newSup->bv_val );
727                         ch_free( op->orr_nnewSup->bv_val );
728                         op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
729                         op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
730                         op->orr_newSup = roc->ros.orr_newSup;
731                         op->orr_nnewSup = roc->ros.orr_nnewSup;
732                 }
733                 return -1;
734         }
735
736         /* TODO: rewrite newRDN, attribute types, 
737          * values of DN-valued attributes ... */
738
739         op->o_callback = &roc->cb;
740
741         return SLAP_CB_CONTINUE;
742 }
743
744
745 static int
746 rwm_swap_attrs( Operation *op, SlapReply *rs )
747 {
748         slap_callback   *cb = op->o_callback;
749         rwm_op_state *ros = cb->sc_private;
750
751         rs->sr_attrs = ros->ors_attrs;
752
753         /* other overlays might have touched op->ors_attrs, 
754          * so we restore the original version here, otherwise
755          * attribute-mapping might fail */
756         op->ors_attrs = ros->mapped_attrs; 
757         
758         return SLAP_CB_CONTINUE;
759 }
760
761 static int
762 rwm_op_search( Operation *op, SlapReply *rs )
763 {
764         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
765         struct ldaprwmap        *rwmap = 
766                         (struct ldaprwmap *)on->on_bi.bi_private;
767
768         int                     rc;
769         dncookie                dc;
770
771         struct berval           fstr = BER_BVNULL;
772         Filter                  *f = NULL;
773
774         AttributeName           *an = NULL;
775
776         char                    *text = NULL;
777
778         rwm_op_cb               *roc = rwm_callback_get( op, rs );
779
780         rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
781                 "searchFilter", op->ors_filterstr.bv_val );
782         if ( rc == LDAP_SUCCESS )
783                 rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
784         if ( rc != LDAP_SUCCESS ) {
785                 text = "searchDN massage error";
786                 goto error_return;
787         }
788
789         /*
790          * Rewrite the dn if needed
791          */
792         dc.rwmap = rwmap;
793         dc.conn = op->o_conn;
794         dc.rs = rs;
795         dc.ctx = "searchFilterAttrDN";
796
797         rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
798         if ( rc != LDAP_SUCCESS ) {
799                 text = "searchFilter/searchFilterAttrDN massage error";
800                 goto error_return;
801         }
802
803         f = str2filter_x( op, fstr.bv_val );
804
805         if ( f == NULL ) {
806                 text = "massaged filter parse error";
807                 goto error_return;
808         }
809
810         op->ors_filter = f;
811         op->ors_filterstr = fstr;
812
813         rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
814                         op->ors_attrs, &an, RWM_MAP );
815         if ( rc != LDAP_SUCCESS ) {
816                 text = "attribute list mapping error";
817                 goto error_return;
818         }
819
820         op->ors_attrs = an;
821         /* store the mapped Attributes for later usage, in
822          * the case that other overlays change op->ors_attrs */
823         roc->ros.mapped_attrs = an;
824         roc->cb.sc_response = rwm_swap_attrs;
825
826         op->o_callback = &roc->cb;
827
828         return SLAP_CB_CONTINUE;
829
830 error_return:;
831         if ( an != NULL ) {
832                 ch_free( an );
833         }
834
835         if ( f != NULL ) {
836                 filter_free_x( op, f, 1 );
837         }
838
839         if ( !BER_BVISNULL( &fstr ) ) {
840                 ch_free( fstr.bv_val );
841         }
842
843         rwm_op_rollback( op, rs, &roc->ros );
844         op->oq_search = roc->ros.oq_search;
845         op->o_tmpfree( roc, op->o_tmpmemctx );
846
847         op->o_bd->bd_info = (BackendInfo *)on->on_info;
848         send_ldap_error( op, rs, rc, text );
849
850         return -1;
851
852 }
853
854 static int
855 rwm_exop_passwd( Operation *op, SlapReply *rs )
856 {
857         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
858         int                     rc;
859         rwm_op_cb *roc;
860
861         struct berval   id = BER_BVNULL,
862                         pwold = BER_BVNULL,
863                         pwnew = BER_BVNULL;
864         BerElement *ber = NULL;
865
866         if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
867                 return LDAP_SUCCESS;
868         }
869
870         if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
871                 rs->sr_err = LDAP_OTHER;
872                 return rs->sr_err;
873         }
874
875         rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
876                 &pwold, &pwnew, &rs->sr_text );
877         if ( rs->sr_err != LDAP_SUCCESS ) {
878                 return rs->sr_err;
879         }
880
881         if ( !BER_BVISNULL( &id ) ) {
882                 char idNul = id.bv_val[id.bv_len];
883                 id.bv_val[id.bv_len] = '\0';
884                 rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
885                                 &op->o_req_ndn, op->o_tmpmemctx );
886                 id.bv_val[id.bv_len] = idNul;
887                 if ( rs->sr_err != LDAP_SUCCESS ) {
888                         rs->sr_text = "Invalid DN";
889                         return rs->sr_err;
890                 }
891
892         } else {
893                 ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
894                 ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
895         }
896
897         roc = rwm_callback_get( op, rs );
898
899         rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
900         if ( rc != LDAP_SUCCESS ) {
901                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
902                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
903                 return -1;
904         }
905
906         ber = ber_alloc_t( LBER_USE_DER );
907         if ( !ber ) {
908                 rs->sr_err = LDAP_OTHER;
909                 rs->sr_text = "No memory";
910                 return rs->sr_err;
911         }
912         ber_printf( ber, "{" );
913         if ( !BER_BVISNULL( &id )) {
914                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, 
915                         &op->o_req_dn );
916         }
917         if ( !BER_BVISNULL( &pwold )) {
918                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &pwold );
919         }
920         if ( !BER_BVISNULL( &pwnew )) {
921                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &pwnew );
922         }
923         ber_printf( ber, "N}" );
924         ber_flatten( ber, &op->ore_reqdata );
925         ber_free( ber, 1 );
926
927         op->o_callback = &roc->cb;
928
929         return SLAP_CB_CONTINUE;
930 }
931
932 static struct exop {
933         struct berval   oid;
934         BI_op_extended  *extended;
935 } exop_table[] = {
936         { BER_BVC(LDAP_EXOP_MODIFY_PASSWD),     rwm_exop_passwd },
937         { BER_BVNULL, NULL }
938 };
939
940 static int
941 rwm_extended( Operation *op, SlapReply *rs )
942 {
943         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
944         int                     rc;
945         rwm_op_cb *roc;
946
947         int     i;
948
949         for ( i = 0; exop_table[i].extended != NULL; i++ ) {
950                 if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
951                 {
952                         rc = exop_table[i].extended( op, rs );
953                         switch ( rc ) {
954                         case LDAP_SUCCESS:
955                                 break;
956
957                         case SLAP_CB_CONTINUE:
958                         case SLAPD_ABANDON:
959                                 return rc;
960
961                         default:
962                                 send_ldap_result( op, rs );
963                                 return rc;
964                         }
965                         break;
966                 }
967         }
968
969         roc = rwm_callback_get( op, rs );
970
971         rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
972         if ( rc != LDAP_SUCCESS ) {
973                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
974                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
975                 return -1;
976         }
977
978         /* TODO: rewrite/map extended data ? ... */
979         op->o_callback = &roc->cb;
980
981         return SLAP_CB_CONTINUE;
982 }
983
984 static int
985 rwm_matched( Operation *op, SlapReply *rs )
986 {
987         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
988         struct ldaprwmap        *rwmap = 
989                         (struct ldaprwmap *)on->on_bi.bi_private;
990
991         struct berval           dn, mdn;
992         dncookie                dc;
993         int                     rc;
994
995         if ( rs->sr_matched == NULL ) {
996                 return SLAP_CB_CONTINUE;
997         }
998
999         dc.rwmap = rwmap;
1000         dc.conn = op->o_conn;
1001         dc.rs = rs;
1002         dc.ctx = "matchedDN";
1003         ber_str2bv( rs->sr_matched, 0, 0, &dn );
1004         mdn = dn;
1005         rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
1006         if ( rc != LDAP_SUCCESS ) {
1007                 rs->sr_err = rc;
1008                 rs->sr_text = "Rewrite error";
1009                 return 1;
1010         }
1011
1012         if ( mdn.bv_val != dn.bv_val ) {
1013                 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
1014                         ch_free( (void *)rs->sr_matched );
1015
1016                 } else {
1017                         rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
1018                 }
1019                 rs->sr_matched = mdn.bv_val;
1020         }
1021         
1022         return SLAP_CB_CONTINUE;
1023 }
1024
1025 static int
1026 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
1027 {
1028         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1029         struct ldaprwmap        *rwmap = 
1030                         (struct ldaprwmap *)on->on_bi.bi_private;
1031
1032         dncookie                dc;
1033         int                     rc;
1034         Attribute               **ap;
1035         int                     isupdate;
1036         int                     check_duplicate_attrs = 0;
1037
1038         /*
1039          * Rewrite the dn attrs, if needed
1040          */
1041         dc.rwmap = rwmap;
1042         dc.conn = op->o_conn;
1043         dc.rs = NULL; 
1044
1045         /* FIXME: the entries are in the remote mapping form;
1046          * so we need to select those attributes we are willing
1047          * to return, and remap them accordingly */
1048
1049         /* FIXME: in principle, one could map an attribute
1050          * on top of another, which already exists.
1051          * As such, in the end there might exist more than
1052          * one instance of an attribute.
1053          * We should at least check if this occurs, and issue
1054          * an error (because multiple instances of attrs in 
1055          * response are not valid), or merge the values (what
1056          * about duplicate values?) */
1057         isupdate = be_shadow_update( op );
1058         for ( ap = a_first; *ap; ) {
1059                 struct ldapmapping      *mapping = NULL;
1060                 int                     drop_missing;
1061                 int                     last = -1;
1062                 Attribute               *a;
1063
1064                 if ( SLAP_OPATTRS( rs->sr_attr_flags ) && is_at_operational( (*ap)->a_desc->ad_type ) )
1065                 {
1066                         /* go on */ ;
1067                         
1068                 } else {
1069                         if ( op->ors_attrs != NULL && 
1070                                         !SLAP_USERATTRS( rs->sr_attr_flags ) &&
1071                                         !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
1072                         {
1073                                 goto cleanup_attr;
1074                         }
1075
1076                         drop_missing = rwm_mapping( &rwmap->rwm_at,
1077                                         &(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
1078                         if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
1079                         {
1080                                 goto cleanup_attr;
1081                         }
1082                         if ( mapping != NULL ) {
1083                                 assert( mapping->m_dst_ad != NULL );
1084
1085                                 /* try to normalize mapped Attributes if the original 
1086                                  * AttributeType was not normalized */
1087                                 if ( (!(*ap)->a_desc->ad_type->sat_equality || 
1088                                         !(*ap)->a_desc->ad_type->sat_equality->smr_normalize) &&
1089                                         mapping->m_dst_ad->ad_type->sat_equality &&
1090                                         mapping->m_dst_ad->ad_type->sat_equality->smr_normalize )
1091                                 {
1092                                         if ((rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS))
1093                                         {
1094                                                 int i = 0;
1095
1096                                                 last = (*ap)->a_numvals;
1097                                                 if ( last )
1098                                                 {
1099                                                         (*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) );
1100
1101                                                         for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[i]); i++ ) {
1102                                                                 int             rc;
1103                                                                 /*
1104                                                                  * check that each value is valid per syntax
1105                                                                  * and pretty if appropriate
1106                                                                  */
1107                                                                 rc = mapping->m_dst_ad->ad_type->sat_equality->smr_normalize(
1108                                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1109                                                                         mapping->m_dst_ad->ad_type->sat_syntax,
1110                                                                         mapping->m_dst_ad->ad_type->sat_equality,
1111                                                                         &(*ap)->a_vals[i], &(*ap)->a_nvals[i],
1112                                                                         NULL );
1113
1114                                                                 if ( rc != LDAP_SUCCESS ) {
1115                                                                         BER_BVZERO( &(*ap)->a_nvals[i] );
1116                                                                 }
1117                                                         }
1118                                                         BER_BVZERO( &(*ap)->a_nvals[i] );
1119                                                 }
1120
1121                                         } else {
1122                                                 assert( (*ap)->a_nvals == (*ap)->a_vals );
1123                                                 (*ap)->a_nvals = NULL;
1124                                                 ber_bvarray_dup_x( &(*ap)->a_nvals, (*ap)->a_vals, NULL );
1125                                         }
1126                                 }
1127
1128                                 /* rewrite the attribute description */
1129                                 (*ap)->a_desc = mapping->m_dst_ad;
1130
1131                                 /* will need to check for duplicate attrs */
1132                                 check_duplicate_attrs++;
1133                         }
1134                 }
1135
1136                 if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
1137                         if ( stripEntryDN ) {
1138                                 /* will be generated by frontend */
1139                                 goto cleanup_attr;
1140                         }
1141                         
1142                 } else if ( !isupdate
1143                         && !get_relax( op )
1144                         && (*ap)->a_desc->ad_type->sat_no_user_mod 
1145                         && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
1146                 {
1147                         goto next_attr;
1148                 }
1149
1150                 if ( last == -1 ) { /* not yet counted */ 
1151                         last = (*ap)->a_numvals;
1152                 }
1153
1154                 if ( last == 0 ) {
1155                         /* empty? leave it in place because of attrsonly and vlv */
1156                         goto next_attr;
1157                 }
1158                 last--;
1159
1160                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
1161                                 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
1162                 {
1163                         struct berval   *bv;
1164                         
1165                         for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1166                                 struct berval   mapped;
1167
1168                                 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
1169                                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
1170 remove_oc:;
1171                                         ch_free( bv[0].bv_val );
1172                                         BER_BVZERO( &bv[0] );
1173                                         if ( &(*ap)->a_vals[last] > &bv[0] ) {
1174                                                 bv[0] = (*ap)->a_vals[last];
1175                                                 BER_BVZERO( &(*ap)->a_vals[last] );
1176                                         }
1177                                         last--;
1178                                         bv--;
1179
1180                                 } else if ( mapped.bv_val != bv[0].bv_val ) {
1181                                         int     i;
1182
1183                                         for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[ i ] ); i++ ) {
1184                                                 if ( &(*ap)->a_vals[ i ] == bv ) {
1185                                                         continue;
1186                                                 }
1187
1188                                                 if ( ber_bvstrcasecmp( &mapped, &(*ap)->a_vals[ i ] ) == 0 ) {
1189                                                         break;
1190                                                 }
1191                                         }
1192
1193                                         if ( !BER_BVISNULL( &(*ap)->a_vals[ i ] ) ) {
1194                                                 goto remove_oc;
1195                                         }
1196
1197                                         /*
1198                                          * FIXME: after LBER_FREEing
1199                                          * the value is replaced by
1200                                          * ch_alloc'ed memory
1201                                          */
1202                                         ber_bvreplace( &bv[0], &mapped );
1203
1204                                         /* FIXME: will need to check
1205                                          * if the structuralObjectClass
1206                                          * changed */
1207                                 }
1208                         }
1209
1210                 /*
1211                  * It is necessary to try to rewrite attributes with
1212                  * dn syntax because they might be used in ACLs as
1213                  * members of groups; since ACLs are applied to the
1214                  * rewritten stuff, no dn-based subject clause could
1215                  * be used at the ldap backend side (see
1216                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
1217                  * The problem can be overcome by moving the dn-based
1218                  * ACLs to the target directory server, and letting
1219                  * everything pass thru the ldap backend. */
1220                 /* FIXME: handle distinguishedName-like syntaxes, like
1221                  * nameAndOptionalUID */
1222                 } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
1223                                 || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
1224                 {
1225                         dc.ctx = "searchAttrDN";
1226                         rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
1227                         if ( rc != LDAP_SUCCESS ) {
1228                                 goto cleanup_attr;
1229                         }
1230
1231                 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
1232                         dc.ctx = "searchAttrDN";
1233                         rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
1234                         if ( rc != LDAP_SUCCESS ) {
1235                                 goto cleanup_attr;
1236                         }
1237                 }
1238
1239
1240 next_attr:;
1241                 ap = &(*ap)->a_next;
1242                 continue;
1243
1244 cleanup_attr:;
1245                 a = *ap;
1246                 *ap = (*ap)->a_next;
1247
1248                 attr_free( a );
1249         }
1250
1251         /* only check if some mapping occurred */
1252         if ( check_duplicate_attrs ) {
1253                 for ( ap = a_first; *ap != NULL; ap = &(*ap)->a_next ) {
1254                         Attribute       **tap;
1255
1256                         for ( tap = &(*ap)->a_next; *tap != NULL; ) {
1257                                 if ( (*tap)->a_desc == (*ap)->a_desc ) {
1258                                         Entry           e = { 0 };
1259                                         Modification    mod = { 0 };
1260                                         const char      *text = NULL;
1261                                         char            textbuf[ SLAP_TEXT_BUFLEN ];
1262                                         Attribute       *next = (*tap)->a_next;
1263
1264                                         BER_BVSTR( &e.e_name, "" );
1265                                         BER_BVSTR( &e.e_nname, "" );
1266                                         e.e_attrs = *ap;
1267                                         mod.sm_op = LDAP_MOD_ADD;
1268                                         mod.sm_desc = (*ap)->a_desc;
1269                                         mod.sm_type = mod.sm_desc->ad_cname;
1270                                         mod.sm_numvals = (*tap)->a_numvals;
1271                                         mod.sm_values = (*tap)->a_vals;
1272                                         if ( (*tap)->a_nvals != (*tap)->a_vals ) {
1273                                                 mod.sm_nvalues = (*tap)->a_nvals;
1274                                         }
1275
1276                                         (void)modify_add_values( &e, &mod,
1277                                                 /* permissive */ 1,
1278                                                 &text, textbuf, sizeof( textbuf ) );
1279
1280                                         /* should not insert new attrs! */
1281                                         assert( e.e_attrs == *ap );
1282
1283                                         attr_free( *tap );
1284                                         *tap = next;
1285
1286                                 } else {
1287                                         tap = &(*tap)->a_next;
1288                                 }
1289                         }
1290                 }
1291         }
1292
1293         return 0;
1294 }
1295
1296 static int
1297 rwm_send_entry( Operation *op, SlapReply *rs )
1298 {
1299         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1300         struct ldaprwmap        *rwmap = 
1301                         (struct ldaprwmap *)on->on_bi.bi_private;
1302
1303         Entry                   *e = NULL;
1304         slap_mask_t             flags;
1305         struct berval           dn = BER_BVNULL,
1306                                 ndn = BER_BVNULL;
1307         dncookie                dc;
1308         int                     rc;
1309
1310         assert( rs->sr_entry != NULL );
1311
1312         /*
1313          * Rewrite the dn of the result, if needed
1314          */
1315         dc.rwmap = rwmap;
1316         dc.conn = op->o_conn;
1317         dc.rs = NULL; 
1318         dc.ctx = "searchEntryDN";
1319
1320         e = rs->sr_entry;
1321         flags = rs->sr_flags;
1322         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
1323                 /* FIXME: all we need to duplicate are:
1324                  * - dn
1325                  * - ndn
1326                  * - attributes that are requested
1327                  * - no values if attrsonly is set
1328                  */
1329
1330                 e = entry_dup( e );
1331                 if ( e == NULL ) {
1332                         rc = LDAP_NO_MEMORY;
1333                         goto fail;
1334                 }
1335
1336                 flags &= ~REP_ENTRY_MUSTRELEASE;
1337                 flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
1338         }
1339
1340         /*
1341          * Note: this may fail if the target host(s) schema differs
1342          * from the one known to the meta, and a DN with unknown
1343          * attributes is returned.
1344          */
1345         dn = e->e_name;
1346         ndn = e->e_nname;
1347         rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
1348         if ( rc != LDAP_SUCCESS ) {
1349                 rc = 1;
1350                 goto fail;
1351         }
1352
1353         if ( e->e_name.bv_val != dn.bv_val ) {
1354                 ch_free( e->e_name.bv_val );
1355                 ch_free( e->e_nname.bv_val );
1356
1357                 e->e_name = dn;
1358                 e->e_nname = ndn;
1359         }
1360
1361         /* TODO: map entry attribute types, objectclasses 
1362          * and dn-valued attribute values */
1363
1364         /* FIXME: the entries are in the remote mapping form;
1365          * so we need to select those attributes we are willing
1366          * to return, and remap them accordingly */
1367         (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
1368
1369         if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1370                 overlay_entry_release_ov( op, rs->sr_entry, 0, on );
1371         }
1372
1373         rs->sr_entry = e;
1374         rs->sr_flags = flags;
1375
1376         return SLAP_CB_CONTINUE;
1377
1378 fail:;
1379         if ( e != NULL && e != rs->sr_entry ) {
1380                 if ( e->e_name.bv_val == dn.bv_val ) {
1381                         BER_BVZERO( &e->e_name );
1382                 }
1383
1384                 if ( e->e_nname.bv_val == ndn.bv_val ) {
1385                         BER_BVZERO( &e->e_nname );
1386                 }
1387
1388                 entry_free( e );
1389         }
1390
1391         if ( !BER_BVISNULL( &dn ) ) {
1392                 ch_free( dn.bv_val );
1393         }
1394
1395         if ( !BER_BVISNULL( &ndn ) ) {
1396                 ch_free( ndn.bv_val );
1397         }
1398
1399         return rc;
1400 }
1401
1402 static int
1403 rwm_operational( Operation *op, SlapReply *rs )
1404 {
1405         /* FIXME: the entries are in the remote mapping form;
1406          * so we need to select those attributes we are willing
1407          * to return, and remap them accordingly */
1408         if ( rs->sr_operational_attrs ) {
1409                 rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
1410         }
1411
1412         return SLAP_CB_CONTINUE;
1413 }
1414
1415 #if 0
1416 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1417  * rewritten for subsequent operations; fine for plain suffixmassage,
1418  * but destroys everything else */
1419 static int
1420 rwm_chk_referrals( Operation *op, SlapReply *rs )
1421 {
1422         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1423         int                     rc;
1424
1425         rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1426         if ( rc != LDAP_SUCCESS ) {
1427                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1428                 send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1429                 return -1;
1430         }
1431
1432         return SLAP_CB_CONTINUE;
1433 }
1434 #endif
1435
1436 static int
1437 rwm_rw_config(
1438         BackendDB       *be,
1439         const char      *fname,
1440         int             lineno,
1441         int             argc,
1442         char            **argv )
1443 {
1444         slap_overinst           *on = (slap_overinst *) be->bd_info;
1445         struct ldaprwmap        *rwmap = 
1446                         (struct ldaprwmap *)on->on_bi.bi_private;
1447
1448         return rewrite_parse( rwmap->rwm_rw,
1449                                 fname, lineno, argc, argv );
1450
1451         return 0;
1452 }
1453
1454 static int
1455 rwm_suffixmassage_config(
1456         BackendDB       *be,
1457         const char      *fname,
1458         int             lineno,
1459         int             argc,
1460         char            **argv )
1461 {
1462         slap_overinst           *on = (slap_overinst *) be->bd_info;
1463         struct ldaprwmap        *rwmap = 
1464                         (struct ldaprwmap *)on->on_bi.bi_private;
1465
1466         struct berval           bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1467         int                     massaged;
1468         int                     rc;
1469                 
1470         /*
1471          * syntax:
1472          * 
1473          *      suffixmassage [<suffix>] <massaged suffix>
1474          *
1475          * the [<suffix>] field must be defined as a valid suffix
1476          * for the current database;
1477          * the <massaged suffix> shouldn't have already been
1478          * defined as a valid suffix for the current server
1479          */
1480         if ( argc == 2 ) {
1481                 if ( be->be_suffix == NULL ) {
1482                         fprintf( stderr, "%s: line %d: "
1483                                        " \"suffixMassage [<suffix>]"
1484                                        " <massaged suffix>\" without "
1485                                        "<suffix> part requires database "
1486                                        "suffix be defined first.\n",
1487                                 fname, lineno );
1488                         return 1;
1489                 }
1490                 bvnc = be->be_suffix[ 0 ];
1491                 massaged = 1;
1492
1493         } else if ( argc == 3 ) {
1494                 ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1495                 massaged = 2;
1496
1497         } else  {
1498                 fprintf( stderr, "%s: line %d: syntax is"
1499                                " \"suffixMassage [<suffix>]"
1500                                " <massaged suffix>\"\n",
1501                         fname, lineno );
1502                 return 1;
1503         }
1504
1505         if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1506                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1507                         fname, lineno, bvnc.bv_val );
1508                 return 1;
1509         }
1510
1511         ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1512         if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1513                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1514                                 fname, lineno, brnc.bv_val );
1515                 free( nvnc.bv_val );
1516                 free( pvnc.bv_val );
1517                 return 1;
1518         }
1519
1520         /*
1521          * The suffix massaging is emulated 
1522          * by means of the rewrite capabilities
1523          */
1524         rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1525                         &pvnc, &nvnc, &prnc, &nrnc );
1526         free( nvnc.bv_val );
1527         free( pvnc.bv_val );
1528         free( nrnc.bv_val );
1529         free( prnc.bv_val );
1530
1531         return rc;
1532 }
1533
1534 static int
1535 rwm_m_config(
1536         BackendDB       *be,
1537         const char      *fname,
1538         int             lineno,
1539         int             argc,
1540         char            **argv )
1541 {
1542         slap_overinst           *on = (slap_overinst *) be->bd_info;
1543         struct ldaprwmap        *rwmap = 
1544                         (struct ldaprwmap *)on->on_bi.bi_private;
1545
1546         /* objectclass/attribute mapping */
1547         return rwm_map_config( &rwmap->rwm_oc,
1548                         &rwmap->rwm_at,
1549                         fname, lineno, argc, argv );
1550 }
1551
1552 static int
1553 rwm_response( Operation *op, SlapReply *rs )
1554 {
1555         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
1556         struct ldaprwmap        *rwmap = 
1557                         (struct ldaprwmap *)on->on_bi.bi_private;
1558
1559         int             rc;
1560
1561         if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1562                 return rwm_send_entry( op, rs );
1563         }
1564
1565         switch( op->o_tag ) {
1566         case LDAP_REQ_SEARCH:
1567         case LDAP_REQ_BIND:
1568         case LDAP_REQ_ADD:
1569         case LDAP_REQ_DELETE:
1570         case LDAP_REQ_MODRDN:
1571         case LDAP_REQ_MODIFY:
1572         case LDAP_REQ_COMPARE:
1573         case LDAP_REQ_EXTENDED:
1574                 if ( rs->sr_ref ) {
1575                         dncookie                dc;
1576
1577                         /*
1578                          * Rewrite the dn of the referrals, if needed
1579                          */
1580                         dc.rwmap = rwmap;
1581                         dc.conn = op->o_conn;
1582                         dc.rs = NULL; 
1583                         dc.ctx = "referralDN";
1584                         rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1585                         if ( rc != LDAP_SUCCESS ) {
1586                                 rc = 1;
1587                                 break;
1588                         }
1589                 }
1590                 rc = rwm_matched( op, rs );
1591                 break;
1592
1593         default:
1594                 rc = SLAP_CB_CONTINUE;
1595                 break;
1596         }
1597
1598         return rc;
1599 }
1600
1601 static int
1602 rwm_db_config(
1603         BackendDB       *be,
1604         const char      *fname,
1605         int             lineno,
1606         int             argc,
1607         char            **argv )
1608 {
1609         slap_overinst           *on = (slap_overinst *) be->bd_info;
1610         struct ldaprwmap        *rwmap = 
1611                         (struct ldaprwmap *)on->on_bi.bi_private;
1612
1613         int             rc = 0;
1614         char            *argv0 = NULL;
1615
1616         if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1617                 argv0 = argv[ 0 ];
1618                 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1619         }
1620
1621         if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1622                 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1623
1624         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1625                 rc = rwm_m_config( be, fname, lineno, argc, argv );
1626
1627         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1628                 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1629
1630         } else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
1631                 if ( argc != 2 ) {
1632                         fprintf( stderr,
1633                 "%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
1634                                         fname, lineno );
1635                         return( 1 );
1636                 }
1637
1638                 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1639                         rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F_MASK2);
1640
1641                 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1642                         rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
1643
1644                 /* TODO: not implemented yet */
1645                 } else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1646                         fprintf( stderr,
1647                 "%s: line %d: \"discover\" not supported yet "
1648                 "in \"t-f-support {no|yes|discover}\".\n",
1649                                         fname, lineno );
1650                         return( 1 );
1651 #if 0
1652                         rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
1653 #endif
1654
1655                 } else {
1656                         fprintf( stderr,
1657         "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1658                                 fname, lineno, argv[ 1 ] );
1659                         return 1;
1660                 }
1661
1662         } else if ( strcasecmp( argv[0], "normalize-mapped-attrs" ) ==  0 ) {
1663                 if ( argc !=2 ) { 
1664                         fprintf( stderr,
1665                 "%s: line %d: \"normalize-mapped-attrs {no|yes}\" needs 1 argument.\n",
1666                                         fname, lineno );
1667                         return( 1 );
1668                 }
1669
1670                 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1671                         rwmap->rwm_flags &= ~(RWM_F_NORMALIZE_MAPPED_ATTRS);
1672
1673                 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1674                         rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
1675                 }
1676
1677         } else {
1678                 rc = SLAP_CONF_UNKNOWN;
1679         }
1680
1681         if ( argv0 ) {
1682                 argv[ 0 ] = argv0;
1683         }
1684
1685         return rc;
1686 }
1687
1688 /*
1689  * dynamic configuration...
1690  */
1691
1692 enum {
1693         /* rewrite */
1694         RWM_CF_REWRITE = 1,
1695         RWM_CF_SUFFIXMASSAGE,
1696
1697         /* map */
1698         RWM_CF_MAP,
1699         RWM_CF_T_F_SUPPORT,
1700         RWM_CF_NORMALIZE_MAPPED,
1701
1702         RWM_CF_LAST
1703 };
1704
1705 static slap_verbmasks t_f_mode[] = {
1706         { BER_BVC( "yes" ),             RWM_F_SUPPORT_T_F },
1707         { BER_BVC( "discover" ),        RWM_F_SUPPORT_T_F_DISCOVER },
1708         { BER_BVC( "no" ),              RWM_F_NONE },
1709         { BER_BVNULL,                   0 }
1710 };
1711
1712 static ConfigDriver rwm_cf_gen;
1713
1714 static ConfigTable rwmcfg[] = {
1715         { "rwm-rewrite", "rewrite",
1716                 2, 0, STRLENOF("rwm-rewrite"),
1717                 ARG_MAGIC|ARG_QUOTE|RWM_CF_REWRITE, rwm_cf_gen,
1718                 "( OLcfgOvAt:16.1 NAME 'olcRwmRewrite' "
1719                         "DESC 'Rewrites strings' "
1720                         "EQUALITY caseIgnoreMatch "
1721                         "SYNTAX OMsDirectoryString "
1722                         "X-ORDERED 'VALUES' )",
1723                 NULL, NULL },
1724
1725         { "rwm-suffixmassage", "[virtual]> <real",
1726                 2, 3, 0, ARG_MAGIC|RWM_CF_SUFFIXMASSAGE, rwm_cf_gen,
1727                 NULL, NULL, NULL },
1728                 
1729         { "rwm-t-f-support", "true|false|discover",
1730                 2, 2, 0, ARG_MAGIC|RWM_CF_T_F_SUPPORT, rwm_cf_gen,
1731                 "( OLcfgOvAt:16.2 NAME 'olcRwmTFSupport' "
1732                         "DESC 'Absolute filters support' "
1733                         "SYNTAX OMsDirectoryString "
1734                         "SINGLE-VALUE )",
1735                 NULL, NULL },
1736
1737         { "rwm-map", "{objectClass|attribute}",
1738                 2, 4, 0, ARG_MAGIC|RWM_CF_MAP, rwm_cf_gen,
1739                 "( OLcfgOvAt:16.3 NAME 'olcRwmMap' "
1740                         "DESC 'maps attributes/objectClasses' "
1741                         "SYNTAX OMsDirectoryString "
1742                         "X-ORDERED 'VALUES' )",
1743                 NULL, NULL },
1744
1745         { "rwm-normalize-mapped-attrs", "true|false",
1746                 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_NORMALIZE_MAPPED, rwm_cf_gen,
1747                 "( OLcfgOvAt:16.4 NAME 'olcRwmNormalizeMapped' "
1748                         "DESC 'Normalize mapped attributes/objectClasses' "
1749                         "SYNTAX OMsBoolean "
1750                         "SINGLE-VALUE )",
1751                 NULL, NULL },
1752
1753         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1754 };
1755
1756 static ConfigOCs rwmocs[] = {
1757         { "( OLcfgOvOc:16.1 "
1758                 "NAME 'olcRwmConfig' "
1759                 "DESC 'Rewrite/remap configuration' "
1760                 "SUP olcOverlayConfig "
1761                 "MAY ( "
1762                         "olcRwmRewrite $ "
1763                         "olcRwmTFSupport $ "
1764                         "olcRwmMap $ "
1765                         "olcRwmNormalizeMapped "
1766                         ") )",
1767                 Cft_Overlay, rwmcfg, NULL, NULL },
1768         { NULL, 0, NULL }
1769 };
1770
1771 static void
1772 slap_rewrite_unparse( BerVarray in, BerVarray *out )
1773 {
1774         int             i;
1775         BerVarray       bva = NULL;
1776         char            ibuf[32], *ptr;
1777         struct berval   idx;
1778
1779         assert( in != NULL );
1780
1781         for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
1782                 /* count'em */ ;
1783
1784         if ( i == 0 ) {
1785                 return;
1786         }
1787
1788         idx.bv_val = ibuf;
1789
1790         bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
1791         BER_BVZERO( &bva[ 0 ] );
1792
1793         for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
1794                 idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), "{%d}", i );
1795                 if ( idx.bv_len >= sizeof( ibuf ) ) {
1796                         ber_bvarray_free( bva );
1797                         return;
1798                 }
1799
1800                 bva[i].bv_len = idx.bv_len + in[i].bv_len;
1801                 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
1802                 ptr = lutil_strcopy( bva[i].bv_val, ibuf );
1803                 ptr = lutil_strcopy( ptr, in[i].bv_val );
1804                 *ptr = '\0';
1805                 BER_BVZERO( &bva[ i + 1 ] );
1806         }
1807
1808         *out = bva;
1809 }
1810
1811 static int
1812 rwm_cf_gen( ConfigArgs *c )
1813 {
1814         slap_overinst           *on = (slap_overinst *)c->bi;
1815         struct ldaprwmap        *rwmap = 
1816                         (struct ldaprwmap *)on->on_bi.bi_private;
1817
1818         BackendDB               db;
1819         char                    *argv0;
1820         int                     rc = 0;
1821
1822         db = *c->be;
1823         db.bd_info = c->bi;
1824
1825         if ( c->op == SLAP_CONFIG_EMIT ) {
1826                 struct berval   bv = BER_BVNULL;
1827
1828                 switch ( c->type ) {
1829                 case RWM_CF_REWRITE:
1830                         if ( rwmap->rwm_bva_rewrite == NULL ) {
1831                                 rc = 1;
1832
1833                         } else {
1834                                 slap_rewrite_unparse( rwmap->rwm_bva_rewrite, &c->rvalue_vals );
1835                                 if ( !c->rvalue_vals ) {
1836                                         rc = 1;
1837                                 }
1838                         }
1839                         break;
1840
1841                 case RWM_CF_T_F_SUPPORT:
1842                         enum_to_verb( t_f_mode, (rwmap->rwm_flags & RWM_F_SUPPORT_T_F_MASK2), &bv );
1843                         if ( BER_BVISNULL( &bv ) ) {
1844                                 /* there's something wrong... */
1845                                 assert( 0 );
1846                                 rc = 1;
1847
1848                         } else {
1849                                 value_add_one( &c->rvalue_vals, &bv );
1850                         }
1851                         break;
1852
1853                 case RWM_CF_MAP:
1854                         if ( rwmap->rwm_bva_map == NULL ) {
1855                                 rc = 1;
1856
1857                         } else {
1858                                 value_add( &c->rvalue_vals, rwmap->rwm_bva_map );
1859                         }
1860                         break;
1861
1862                 case RWM_CF_NORMALIZE_MAPPED:
1863                         c->value_int = ( rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS );
1864                         break;
1865
1866                 default:
1867                         assert( 0 );
1868                         rc = 1;
1869                 }
1870
1871                 return rc;
1872
1873         } else if ( c->op == LDAP_MOD_DELETE ) {
1874                 switch ( c->type ) {
1875                 case RWM_CF_REWRITE:
1876                         if ( c->valx >= 0 ) {
1877                                 /* single modification is not allowed */
1878                                 rc = 1;
1879
1880                         } else if ( rwmap->rwm_rw != NULL ) {
1881                                 rewrite_info_delete( &rwmap->rwm_rw );
1882                                 assert( rwmap->rwm_rw == NULL );
1883
1884                                 ber_bvarray_free( rwmap->rwm_bva_rewrite );
1885                                 rwmap->rwm_bva_rewrite = NULL;
1886                         }
1887                         break;
1888
1889                 case RWM_CF_T_F_SUPPORT:
1890                         rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
1891                         break;
1892
1893                 case RWM_CF_MAP:
1894                         if ( c->valx >= 0 ) {
1895                                 /* single modification is not allowed */
1896                                 rc = 1;
1897
1898                         } else {
1899                                 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
1900                                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
1901                                 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
1902                                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
1903
1904                                 rwmap->rwm_oc.remap = NULL;
1905                                 rwmap->rwm_oc.map = NULL;
1906                                 rwmap->rwm_at.remap = NULL;
1907                                 rwmap->rwm_at.map = NULL;
1908
1909                                 ber_bvarray_free( rwmap->rwm_bva_map );
1910                                 rwmap->rwm_bva_map = NULL;
1911                         }
1912                         break;
1913
1914                 case RWM_CF_NORMALIZE_MAPPED:
1915                         rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
1916                         break;
1917
1918                 default:
1919                         return 1;
1920                 }
1921                 return rc;
1922         }
1923
1924         switch ( c->type ) {
1925         case RWM_CF_REWRITE:
1926                 argv0 = c->argv[ 0 ];
1927                 c->argv[ 0 ] += STRLENOF( "rwm-" );
1928                 rc = rwm_rw_config( &db, c->fname, c->lineno, c->argc, c->argv );
1929                 c->argv[ 0 ] = argv0;
1930                 if ( rc ) {
1931                         return 1;
1932
1933                 } else {
1934                         char            *line;
1935                         struct berval   bv;
1936
1937                         line = ldap_charray2str( c->argv, "\" \"" );
1938                         if ( line != NULL ) {
1939                                 int     len = strlen( c->argv[ 0 ] );
1940
1941                                 ber_str2bv( line, 0, 0, &bv );
1942                                 AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
1943                                         bv.bv_len - ( len + 1 ) );
1944                                 bv.bv_val[ bv.bv_len - 1 ] = '"';
1945                                 ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
1946                         }
1947                 }
1948                 break;
1949
1950         case RWM_CF_SUFFIXMASSAGE:
1951                 argv0 = c->argv[ 0 ];
1952                 c->argv[ 0 ] += STRLENOF( "rwm-" );
1953                 rc = rwm_suffixmassage_config( &db, c->fname, c->lineno, c->argc, c->argv );
1954                 c->argv[ 0 ] = argv0;
1955                 if ( rc ) {
1956                         return 1;
1957
1958                 } else {
1959                         char            *line;
1960                         struct berval   bv;
1961
1962                         /* FIXME: not optimal; in fact, this keeps track
1963                          * of the fact that a set of rules was added
1964                          * using the rwm-suffixmassage shortcut, but the
1965                          * rules are not clarified */
1966
1967                         line = ldap_charray2str( c->argv, "\" \"" );
1968                         if ( line != NULL ) {
1969                                 int     len = strlen( c->argv[ 0 ] );
1970
1971                                 ber_str2bv( line, 0, 0, &bv );
1972                                 AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
1973                                         bv.bv_len - ( len + 1 ) );
1974                                 bv.bv_val[ bv.bv_len - 1 ] = '"';
1975                                 ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
1976                         }
1977                 }
1978                 break;
1979
1980         case RWM_CF_T_F_SUPPORT:
1981                 rc = verb_to_mask( c->argv[ 1 ], t_f_mode );
1982                 if ( BER_BVISNULL( &t_f_mode[ rc ].word ) ) {
1983                         return 1;
1984                 }
1985
1986                 rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
1987                 rwmap->rwm_flags |= t_f_mode[ rc ].mask;
1988                 rc = 0;
1989                 break;
1990
1991         case RWM_CF_MAP:
1992                 argv0 = c->argv[ 0 ];
1993                 c->argv[ 0 ] += STRLENOF( "rwm-" );
1994                 rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
1995                 c->argv[ 0 ] = argv0;
1996                 if ( rc ) {
1997                         return 1;
1998
1999                 } else {
2000                         char            *line;
2001                         struct berval   bv;
2002
2003                         line = ldap_charray2str( &c->argv[ 1 ], " " );
2004                         if ( line != NULL ) {
2005                                 ber_str2bv( line, 0, 0, &bv );
2006                                 ber_bvarray_add( &rwmap->rwm_bva_map, &bv );
2007                         }
2008                 }
2009                 break;
2010
2011         case RWM_CF_NORMALIZE_MAPPED:
2012                 if ( c->value_int ) {
2013                         rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
2014                 } else {
2015                         rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
2016                 }
2017                 break;
2018
2019         default:
2020                 assert( 0 );
2021                 return 1;
2022         }
2023
2024         return rc;
2025 }
2026
2027 static int
2028 rwm_db_init(
2029         BackendDB       *be,
2030         ConfigReply     *cr )
2031 {
2032         slap_overinst           *on = (slap_overinst *) be->bd_info;
2033         struct ldaprwmap        *rwmap;
2034         char                    *rargv[ 3 ];
2035         int                     rc = 0;
2036
2037         rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
2038
2039         rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
2040         if ( rwmap->rwm_rw == NULL ) {
2041                 rc = -1;
2042                 goto error_return;
2043         }
2044
2045         /* this rewriteContext by default must be null;
2046          * rules can be added if required */
2047         rargv[ 0 ] = "rewriteContext";
2048         rargv[ 1 ] = "searchFilter";
2049         rargv[ 2 ] = NULL;
2050         rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
2051
2052         rargv[ 0 ] = "rewriteContext";
2053         rargv[ 1 ] = "default";
2054         rargv[ 2 ] = NULL;
2055         rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
2056
2057 error_return:;
2058         on->on_bi.bi_private = (void *)rwmap;
2059
2060         if ( rc ) {
2061                 (void)rwm_db_destroy( be, NULL );
2062         }
2063
2064         return rc;
2065 }
2066
2067 static int
2068 rwm_db_destroy(
2069         BackendDB       *be,
2070         ConfigReply     *cr )
2071 {
2072         slap_overinst   *on = (slap_overinst *) be->bd_info;
2073         int             rc = 0;
2074
2075         if ( on->on_bi.bi_private ) {
2076                 struct ldaprwmap        *rwmap = 
2077                         (struct ldaprwmap *)on->on_bi.bi_private;
2078
2079                 if ( rwmap->rwm_rw ) {
2080                         rewrite_info_delete( &rwmap->rwm_rw );
2081                         ber_bvarray_free( rwmap->rwm_bva_rewrite );
2082                 }
2083
2084                 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2085                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2086                 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2087                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2088                 ber_bvarray_free( rwmap->rwm_bva_map );
2089
2090                 ch_free( rwmap );
2091         }
2092
2093         return rc;
2094 }
2095
2096 static slap_overinst rwm = { { NULL } };
2097
2098 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
2099 static
2100 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
2101 int
2102 rwm_initialize( void )
2103 {
2104         int             rc;
2105
2106         /* Make sure we don't exceed the bits reserved for userland */
2107         config_check_userland( RWM_CF_LAST );
2108
2109         memset( &rwm, 0, sizeof( slap_overinst ) );
2110
2111         rwm.on_bi.bi_type = "rwm";
2112         rwm.on_bi.bi_flags =
2113                 SLAPO_BFLAG_SINGLE |
2114                 0;
2115
2116         rwm.on_bi.bi_db_init = rwm_db_init;
2117         rwm.on_bi.bi_db_config = rwm_db_config;
2118         rwm.on_bi.bi_db_destroy = rwm_db_destroy;
2119
2120         rwm.on_bi.bi_op_bind = rwm_op_bind;
2121         rwm.on_bi.bi_op_search = rwm_op_search;
2122         rwm.on_bi.bi_op_compare = rwm_op_compare;
2123         rwm.on_bi.bi_op_modify = rwm_op_modify;
2124         rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
2125         rwm.on_bi.bi_op_add = rwm_op_add;
2126         rwm.on_bi.bi_op_delete = rwm_op_delete;
2127         rwm.on_bi.bi_op_unbind = rwm_op_unbind;
2128         rwm.on_bi.bi_extended = rwm_extended;
2129
2130         rwm.on_bi.bi_operational = rwm_operational;
2131         rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
2132
2133         rwm.on_bi.bi_connection_init = rwm_conn_init;
2134         rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
2135
2136         rwm.on_response = rwm_response;
2137
2138         rwm.on_bi.bi_cf_ocs = rwmocs;
2139
2140         rc = config_register_schema( rwmcfg, rwmocs );
2141         if ( rc ) {
2142                 return rc;
2143         }
2144
2145         return overlay_register( &rwm );
2146 }
2147
2148 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
2149 int
2150 init_module( int argc, char *argv[] )
2151 {
2152         return rwm_initialize();
2153 }
2154 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
2155
2156 #endif /* SLAPD_OVER_RWM */