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