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