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