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