]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/rwm.c
Remove redundant search cleanup
[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-2006 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 "rwm.h"
28
29 typedef struct rwm_op_state {
30         struct berval ro_dn;
31         struct berval ro_ndn;
32         struct berval r_dn;
33         struct berval r_ndn;
34         OpRequest o_request;
35 } rwm_op_state;
36
37 static int
38 rwm_db_destroy( BackendDB *be );
39
40 typedef struct rwm_op_cb {
41         slap_callback cb;
42         rwm_op_state ros;
43 } rwm_op_cb;
44
45 static rwm_op_cb rwm_cb;
46
47 static void
48 rwm_keyfree(
49         void            *key,
50         void            *data )
51 {
52         ber_memfree_x( data, NULL );
53 }
54
55 static int
56 rwm_op_cleanup( Operation *op, SlapReply *rs )
57 {
58         slap_callback   *cb = op->o_callback;
59         rwm_op_state *ros = cb->sc_private;
60
61         if ( rs->sr_type == REP_RESULT || op->o_abandon ||
62                 rs->sr_err == SLAPD_ABANDON ) {
63
64                 op->o_req_dn = ros->ro_dn;
65                 op->o_req_ndn = ros->ro_ndn;
66
67                 if ( !BER_BVISEMPTY( &ros->r_dn )) ch_free( ros->r_dn.bv_val );
68                 if ( !BER_BVISEMPTY( &ros->r_ndn )) ch_free( ros->r_ndn.bv_val );
69
70                 switch( op->o_tag ) {
71                 case LDAP_REQ_COMPARE:
72                         if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
73                                 op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
74                         op->orc_ava = ros->orc_ava;
75                         break;
76                 case LDAP_REQ_MODIFY:
77                         slap_mods_free( op->orm_modlist, 1 );
78                         op->orm_modlist = ros->orm_modlist;
79                         break;
80                 case LDAP_REQ_MODRDN:
81                         if ( op->orr_newSup != ros->orr_newSup ) {
82                                 ch_free( op->orr_newSup->bv_val );
83                                 ch_free( op->orr_nnewSup->bv_val );
84                                 op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
85                                 op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
86                                 op->orr_newSup = ros->orr_newSup;
87                                 op->orr_nnewSup = ros->orr_nnewSup;
88                         }
89                         break;
90                 case LDAP_REQ_SEARCH:
91                         ch_free( op->ors_attrs );
92                         filter_free_x( op, op->ors_filter );
93                         ch_free( op->ors_filterstr.bv_val );
94                         op->ors_attrs = ros->ors_attrs;
95                         op->ors_filter = ros->ors_filter;
96                         op->ors_filterstr = ros->ors_filterstr;
97                         break;
98                 default:        break;
99                 }
100         }
101
102         return SLAP_CB_CONTINUE;
103 }
104
105 static rwm_op_cb *
106 rwm_callback_get( Operation *op, SlapReply *rs )
107 {
108         rwm_op_cb       *roc = NULL;
109
110         if ( op->o_threadctx == NULL ) {
111                 roc = &rwm_cb;
112         } else {
113                 ldap_pvt_thread_pool_getkey( op->o_threadctx,
114                                 rwm_keyfree, (void *)&roc, NULL );
115                 if ( roc == NULL ) {
116                         roc = ch_malloc( sizeof( struct rwm_op_cb ));
117                         ldap_pvt_thread_pool_setkey( op->o_threadctx,
118                                         rwm_keyfree, roc, rwm_keyfree );
119                 }
120         }
121         roc->cb.sc_cleanup = rwm_op_cleanup;
122         roc->cb.sc_response = NULL;
123         roc->cb.sc_next = op->o_callback;
124         roc->cb.sc_private = &roc->ros;
125         roc->ros.ro_dn = op->o_req_dn;
126         roc->ros.ro_ndn = op->o_req_ndn;
127         roc->ros.o_request = op->o_request;
128         BER_BVZERO( &roc->ros.r_dn );
129         BER_BVZERO( &roc->ros.r_ndn );
130
131         return roc;
132 }
133
134
135 static int
136 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
137         rwm_op_state *ros )
138 {
139         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
140         struct ldaprwmap        *rwmap = 
141                         (struct ldaprwmap *)on->on_bi.bi_private;
142
143         struct berval           dn = BER_BVNULL,
144                                 ndn = BER_BVNULL;
145         int                     rc = 0;
146         dncookie                dc;
147
148         /*
149          * Rewrite the dn if needed
150          */
151         dc.rwmap = rwmap;
152 #ifdef ENABLE_REWRITE
153         dc.conn = op->o_conn;
154         dc.rs = rs;
155         dc.ctx = (char *)cookie;
156 #else /* ! ENABLE_REWRITE */
157         dc.tofrom = ((int *)cookie)[0];
158         dc.normalized = 0;
159 #endif /* ! ENABLE_REWRITE */
160
161         /* NOTE: in those cases where only the ndn is available,
162          * and the caller sets op->o_req_dn = op->o_req_ndn,
163          * only rewrite the op->o_req_ndn and use it as 
164          * op->o_req_dn as well */
165         ndn = op->o_req_ndn;
166         if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
167                 dn = op->o_req_dn;
168                 rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
169         } else {
170                 rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
171         }
172
173         if ( rc != LDAP_SUCCESS ) {
174                 return rc;
175         }
176
177         if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
178                         || ndn.bv_val == op->o_req_ndn.bv_val )
179         {
180                 return LDAP_SUCCESS;
181         }
182
183         if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
184                 op->o_req_dn = dn;
185                 ros->r_dn  = dn;
186         } else {
187                 op->o_req_dn = ndn;
188         }
189         ros->r_ndn = ndn;
190         op->o_req_ndn = ndn;
191
192         return LDAP_SUCCESS;
193 }
194
195 static int
196 rwm_op_add( Operation *op, SlapReply *rs )
197 {
198         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
199         struct ldaprwmap        *rwmap = 
200                         (struct ldaprwmap *)on->on_bi.bi_private;
201
202         int                     rc,
203                                 i;
204         Attribute               **ap = NULL;
205         char                    *olddn = op->o_req_dn.bv_val;
206         int                     isupdate;
207
208         rwm_op_cb *roc = rwm_callback_get( op, rs );
209
210 #ifdef ENABLE_REWRITE
211         rc = rwm_op_dn_massage( op, rs, "addDN", &roc->ros );
212 #else /* ! ENABLE_REWRITE */
213         rc = 1;
214         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
215 #endif /* ! ENABLE_REWRITE */
216         if ( rc != LDAP_SUCCESS ) {
217                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
218                 send_ldap_error( op, rs, rc, "addDN massage error" );
219                 return -1;
220         }
221
222         if ( olddn != op->o_req_dn.bv_val ) {
223                 ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
224                 ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
225         }
226
227         /* Count number of attributes in entry */ 
228         isupdate = be_shadow_update( op );
229         for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
230                 Attribute       *a;
231
232                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
233                                 (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
234                 {
235                         int             j, last;
236
237                         for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[ last ] ); last++ )
238                                         /* count values */ ;
239                         last--;
240                         for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
241                                 struct ldapmapping      *mapping = NULL;
242
243                                 ( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
244                                                 &mapping, RWM_MAP );
245                                 if ( mapping == NULL ) {
246                                         if ( rwmap->rwm_at.drop_missing ) {
247                                                 /* FIXME: we allow to remove objectClasses as well;
248                                                  * if the resulting entry is inconsistent, that's
249                                                  * the relayed database's business...
250                                                  */
251                                                 ch_free( (*ap)->a_vals[ j ].bv_val );
252                                                 if ( last > j ) {
253                                                         (*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
254                                                 }
255                                                 BER_BVZERO( &(*ap)->a_vals[ last ] );
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 #ifdef ENABLE_REWRITE
289                                 rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
290                                                 (*ap)->a_vals,
291                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
292 #else /* ! ENABLE_REWRITE */
293                                 rc = 1;
294                                 rc = rwm_dnattr_rewrite( op, rs, &rc, (*ap)->a_vals,
295                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
296 #endif /* ! ENABLE_REWRITE */
297                                 if ( rc ) {
298                                         goto cleanup_attr;
299                                 }
300
301                         } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
302 #ifdef ENABLE_REWRITE
303                                 rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
304                                                 (*ap)->a_vals,
305                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
306 #else /* ! ENABLE_REWRITE */
307                                 rc = 1;
308                                 rc = rwm_referral_rewrite( op, rs, &rc, (*ap)->a_vals,
309                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
310 #endif /* ! ENABLE_REWRITE */
311                                 if ( rc != LDAP_SUCCESS ) {
312                                         goto cleanup_attr;
313                                 }
314                         }
315                 
316                         if ( mapping != NULL ) {
317                                 assert( mapping->m_dst_ad != NULL );
318                                 (*ap)->a_desc = mapping->m_dst_ad;
319                         }
320                 }
321
322 next_attr:;
323                 ap = &(*ap)->a_next;
324                 continue;
325
326 cleanup_attr:;
327                 /* FIXME: leaking attribute/values? */
328                 a = *ap;
329
330                 *ap = (*ap)->a_next;
331                 attr_free( a );
332         }
333
334         op->o_callback = &roc->cb;
335
336         return SLAP_CB_CONTINUE;
337 }
338
339 #ifdef ENABLE_REWRITE
340 static int
341 rwm_conn_init( BackendDB *be, Connection *conn )
342 {
343         slap_overinst           *on = (slap_overinst *) be->bd_info;
344         struct ldaprwmap        *rwmap = 
345                         (struct ldaprwmap *)on->on_bi.bi_private;
346
347         ( void )rewrite_session_init( rwmap->rwm_rw, conn );
348
349         return SLAP_CB_CONTINUE;
350 }
351
352 static int
353 rwm_conn_destroy( BackendDB *be, Connection *conn )
354 {
355         slap_overinst           *on = (slap_overinst *) be->bd_info;
356         struct ldaprwmap        *rwmap = 
357                         (struct ldaprwmap *)on->on_bi.bi_private;
358
359         ( void )rewrite_session_delete( rwmap->rwm_rw, conn );
360
361         return SLAP_CB_CONTINUE;
362 }
363 #endif /* ENABLE_REWRITE */
364
365 static int
366 rwm_op_bind( Operation *op, SlapReply *rs )
367 {
368         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
369         int                     rc;
370
371         rwm_op_cb *roc = rwm_callback_get( op, rs );
372
373 #ifdef ENABLE_REWRITE
374         rc = rwm_op_dn_massage( op, rs, "bindDN", &roc->ros );
375 #else /* ! ENABLE_REWRITE */
376         rc = 1;
377         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
378 #endif /* ! ENABLE_REWRITE */
379         if ( rc != LDAP_SUCCESS ) {
380                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
381                 send_ldap_error( op, rs, rc, "bindDN massage error" );
382                 return -1;
383         }
384
385         op->o_callback = &roc->cb;
386
387         return SLAP_CB_CONTINUE;
388 }
389
390 static int
391 rwm_op_unbind( Operation *op, SlapReply *rs )
392 {
393         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
394         struct ldaprwmap        *rwmap = 
395                         (struct ldaprwmap *)on->on_bi.bi_private;
396
397 #ifdef ENABLE_REWRITE
398         rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
399 #endif /* ENABLE_REWRITE */
400
401         return SLAP_CB_CONTINUE;
402 }
403
404 static int
405 rwm_op_compare( Operation *op, SlapReply *rs )
406 {
407         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
408         struct ldaprwmap        *rwmap = 
409                         (struct ldaprwmap *)on->on_bi.bi_private;
410
411         int                     rc;
412         struct berval mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
413
414         rwm_op_cb *roc = rwm_callback_get( op, rs );
415
416 #ifdef ENABLE_REWRITE
417         rc = rwm_op_dn_massage( op, rs, "compareDN", &roc->ros );
418 #else /* ! ENABLE_REWRITE */
419         rc = 1;
420         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
421 #endif /* ! ENABLE_REWRITE */
422         if ( rc != LDAP_SUCCESS ) {
423                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
424                 send_ldap_error( op, rs, rc, "compareDN massage error" );
425                 return -1;
426         }
427
428         /* if the attribute is an objectClass, try to remap its value */
429         if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
430                         || op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
431         {
432                 rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
433                                 &mapped_vals[0], RWM_MAP );
434                 if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
435                 {
436                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
437                         send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
438                         return -1;
439
440                 } else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
441                         ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
442                                 op->o_tmpmemctx );
443                 }
444
445         } else {
446                 struct ldapmapping      *mapping = NULL;
447                 AttributeDescription    *ad = op->orc_ava->aa_desc;
448
449                 ( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
450                                 &mapping, RWM_MAP );
451                 if ( mapping == NULL ) {
452                         if ( rwmap->rwm_at.drop_missing ) {
453                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
454                                 send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
455                                 return -1;
456                         }
457
458                 } else {
459                         assert( mapping->m_dst_ad != NULL );
460                         ad = mapping->m_dst_ad;
461                 }
462
463                 if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
464                                 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
465                 {
466                         struct berval   *mapped_valsp[2];
467                         
468                         mapped_valsp[0] = &mapped_vals[0];
469                         mapped_valsp[1] = &mapped_vals[1];
470
471                         mapped_vals[0] = op->orc_ava->aa_value;
472
473 #ifdef ENABLE_REWRITE
474                         rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
475 #else /* ! ENABLE_REWRITE */
476                         rc = 1;
477                         rc = rwm_dnattr_rewrite( op, rs, &rc, NULL, mapped_valsp );
478 #endif /* ! ENABLE_REWRITE */
479
480                         if ( rc != LDAP_SUCCESS ) {
481                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
482                                 send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
483                                 return -1;
484                         }
485
486                         if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
487                                 /* NOTE: if we get here, rwm_dnattr_rewrite()
488                                  * already freed the old value, so now 
489                                  * it's invalid */
490                                 ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
491                                         op->o_tmpmemctx );
492                                 ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
493                         }
494                 }
495                 op->orc_ava->aa_desc = ad;
496         }
497
498         op->o_callback = &roc->cb;
499
500         return SLAP_CB_CONTINUE;
501 }
502
503 static int
504 rwm_op_delete( Operation *op, SlapReply *rs )
505 {
506         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
507         int                     rc;
508
509         rwm_op_cb *roc = rwm_callback_get( op, rs );
510
511 #ifdef ENABLE_REWRITE
512         rc = rwm_op_dn_massage( op, rs, "deleteDN", &roc->ros );
513 #else /* ! ENABLE_REWRITE */
514         rc = 1;
515         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
516 #endif /* ! ENABLE_REWRITE */
517         if ( rc != LDAP_SUCCESS ) {
518                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
519                 send_ldap_error( op, rs, rc, "deleteDN massage error" );
520                 return -1;
521         }
522
523         op->o_callback = &roc->cb;
524
525         return SLAP_CB_CONTINUE;
526 }
527
528 static int
529 rwm_op_modify( Operation *op, SlapReply *rs )
530 {
531         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
532         struct ldaprwmap        *rwmap = 
533                         (struct ldaprwmap *)on->on_bi.bi_private;
534
535         int                     isupdate;
536         Modifications           **mlp;
537         int                     rc;
538
539         rwm_op_cb *roc = rwm_callback_get( op, rs );
540
541 #ifdef ENABLE_REWRITE
542         rc = rwm_op_dn_massage( op, rs, "modifyDN", &roc->ros );
543 #else /* ! ENABLE_REWRITE */
544         rc = 1;
545         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
546 #endif /* ! ENABLE_REWRITE */
547         if ( rc != LDAP_SUCCESS ) {
548                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
549                 send_ldap_error( op, rs, rc, "modifyDN massage error" );
550                 return -1;
551         }
552
553         isupdate = be_shadow_update( op );
554         for ( mlp = &op->oq_modify.rs_modlist; *mlp; ) {
555                 int                     is_oc = 0;
556                 Modifications           *ml;
557                 struct ldapmapping      *mapping = NULL;
558
559                 /* duplicate the modlist */
560                 ml = ch_malloc( sizeof( Modifications ));
561                 *ml = **mlp;
562                 *mlp = ml;
563
564                 if ( ml->sml_desc == slap_schema.si_ad_objectClass 
565                                 || ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
566                 {
567                         is_oc = 1;
568
569                 } else if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
570                 {
571                         goto next_mod;
572
573                 } else {
574                         int                     drop_missing;
575
576                         drop_missing = rwm_mapping( &rwmap->rwm_at,
577                                         &ml->sml_desc->ad_cname,
578                                         &mapping, RWM_MAP );
579                         if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
580                         {
581                                 goto cleanup_mod;
582                         }
583                 }
584
585                 if ( ml->sml_values != NULL ) {
586                         int i, num;
587                         struct berval *bva;
588
589                         for ( num = 0; !BER_BVISNULL( &ml->sml_values[ num ] ); num++ )
590                                 /* count values */ ;
591
592                         bva = ch_malloc( (num+1) * sizeof( struct berval ));
593                         for (i=0; i<num; i++)
594                                 ber_dupbv( &bva[i], &ml->sml_values[i] );
595                         BER_BVZERO( &bva[i] );
596                         ml->sml_values = bva;
597
598                         if ( ml->sml_nvalues ) {
599                                 bva = ch_malloc( (num+1) * sizeof( struct berval ));
600                                 for (i=0; i<num; i++)
601                                         ber_dupbv( &bva[i], &ml->sml_nvalues[i] );
602                                 BER_BVZERO( &bva[i] );
603                                 ml->sml_nvalues = bva;
604                         }
605
606                         if ( is_oc ) {
607                                 int     last, j;
608
609                                 last = num-1;
610
611                                 for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
612                                         struct ldapmapping      *oc_mapping = NULL;
613                 
614                                         ( void )rwm_mapping( &rwmap->rwm_oc, &ml->sml_values[ j ],
615                                                         &oc_mapping, RWM_MAP );
616                                         if ( oc_mapping == NULL ) {
617                                                 if ( rwmap->rwm_at.drop_missing ) {
618                                                         /* FIXME: we allow to remove objectClasses as well;
619                                                          * if the resulting entry is inconsistent, that's
620                                                          * the relayed database's business...
621                                                          */
622                                                         if ( last > j ) {
623                                                                 ch_free( ml->sml_values[ j ].bv_val );
624                                                                 ml->sml_values[ j ] = ml->sml_values[ last ];
625                                                         }
626                                                         BER_BVZERO( &ml->sml_values[ last ] );
627                                                         last--;
628                                                         j--;
629                                                 }
630         
631                                         } else {
632                                                 ch_free( ml->sml_values[ j ].bv_val );
633                                                 ber_dupbv( &ml->sml_values[ j ], &oc_mapping->m_dst );
634                                         }
635                                 }
636
637                         } else {
638                                 if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
639                                                 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
640                                 {
641 #ifdef ENABLE_REWRITE
642                                         rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
643                                                         ml->sml_values,
644                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
645 #else /* ! ENABLE_REWRITE */
646                                         rc = 1;
647                                         rc = rwm_dnattr_rewrite( op, rs, &rc, 
648                                                         ml->sml_values,
649                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
650 #endif /* ! ENABLE_REWRITE */
651
652                                 } else if ( ml->sml_desc == slap_schema.si_ad_ref ) {
653 #ifdef ENABLE_REWRITE
654                                         rc = rwm_referral_rewrite( op, rs,
655                                                         "referralAttrDN",
656                                                         ml->sml_values,
657                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
658 #else /* ! ENABLE_REWRITE */
659                                         rc = 1;
660                                         rc = rwm_referral_rewrite( op, rs, &rc,
661                                                         ml->sml_values,
662                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
663 #endif /* ! ENABLE_REWRITE */
664                                         if ( rc != LDAP_SUCCESS ) {
665                                                 goto cleanup_mod;
666                                         }
667                                 }
668
669                                 if ( rc != LDAP_SUCCESS ) {
670                                         goto cleanup_mod;
671                                 }
672                         }
673                 }
674
675 next_mod:;
676                 if ( mapping != NULL ) {
677                         /* use new attribute description */
678                         assert( mapping->m_dst_ad != NULL );
679                         ml->sml_desc = mapping->m_dst_ad;
680                 }
681
682                 mlp = &ml->sml_next;
683                 continue;
684
685 cleanup_mod:;
686                 ml = *mlp;
687                 *mlp = (*mlp)->sml_next;
688                 slap_mod_free( &ml->sml_mod, 0 );
689                 free( ml );
690         }
691
692         op->o_callback = &roc->cb;
693
694         return SLAP_CB_CONTINUE;
695 }
696
697 static int
698 rwm_op_modrdn( Operation *op, SlapReply *rs )
699 {
700         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
701         struct ldaprwmap        *rwmap = 
702                         (struct ldaprwmap *)on->on_bi.bi_private;
703         
704         int                     rc;
705
706         rwm_op_cb *roc = rwm_callback_get( op, rs );
707
708         if ( op->orr_newSup ) {
709                 dncookie        dc;
710                 struct berval   nnewSup = BER_BVNULL;
711                 struct berval   newSup = BER_BVNULL;
712
713                 /*
714                  * Rewrite the new superior, if defined and required
715                  */
716                 dc.rwmap = rwmap;
717 #ifdef ENABLE_REWRITE
718                 dc.conn = op->o_conn;
719                 dc.rs = rs;
720                 dc.ctx = "newSuperiorDN";
721 #else /* ! ENABLE_REWRITE */
722                 dc.tofrom = 0;
723                 dc.normalized = 0;
724 #endif /* ! ENABLE_REWRITE */
725                 newSup = *op->orr_newSup;
726                 nnewSup = *op->orr_nnewSup;
727                 rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
728                 if ( rc != LDAP_SUCCESS ) {
729                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
730                         send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
731                         return -1;
732                 }
733
734                 if ( op->orr_newSup->bv_val != newSup.bv_val ) {
735                         op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ),
736                                 op->o_tmpmemctx );
737                         op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ),
738                                 op->o_tmpmemctx );
739                         *op->orr_newSup = newSup;
740                         *op->orr_nnewSup = nnewSup;
741                 }
742         }
743
744         /*
745          * Rewrite the dn, if needed
746          */
747 #ifdef ENABLE_REWRITE
748         rc = rwm_op_dn_massage( op, rs, "renameDN", &roc->ros );
749 #else /* ! ENABLE_REWRITE */
750         rc = 1;
751         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
752 #endif /* ! ENABLE_REWRITE */
753         if ( rc != LDAP_SUCCESS ) {
754                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
755                 send_ldap_error( op, rs, rc, "renameDN massage error" );
756                 if ( op->orr_newSup != roc->ros.orr_newSup ) {
757                         ch_free( op->orr_newSup->bv_val );
758                         ch_free( op->orr_nnewSup->bv_val );
759                         op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
760                         op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
761                         op->orr_newSup = roc->ros.orr_newSup;
762                         op->orr_nnewSup = roc->ros.orr_nnewSup;
763                 }
764                 return -1;
765         }
766
767         /* TODO: rewrite newRDN, attribute types, 
768          * values of DN-valued attributes ... */
769
770         op->o_callback = &roc->cb;
771
772         return SLAP_CB_CONTINUE;
773 }
774
775
776 static int
777 rwm_swap_attrs( Operation *op, SlapReply *rs )
778 {
779         slap_callback   *cb = op->o_callback;
780         rwm_op_state *ros = cb->sc_private;
781
782         rs->sr_attrs = ros->ors_attrs;
783         
784         return SLAP_CB_CONTINUE;
785 }
786
787 static int
788 rwm_op_search( Operation *op, SlapReply *rs )
789 {
790         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
791         struct ldaprwmap        *rwmap = 
792                         (struct ldaprwmap *)on->on_bi.bi_private;
793
794         int                     rc;
795         dncookie                dc;
796
797         struct berval           fstr = BER_BVNULL;
798         Filter                  *f = NULL;
799
800         AttributeName           *an = NULL;
801
802         char                    *text = NULL;
803
804         rwm_op_cb *roc = rwm_callback_get( op, rs );
805
806 #ifdef ENABLE_REWRITE
807         rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
808                 "searchFilter", op->ors_filterstr.bv_val );
809         if ( rc == LDAP_SUCCESS )
810                 rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
811 #else /* ! ENABLE_REWRITE */
812         rc = 1;
813         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
814 #endif /* ! ENABLE_REWRITE */
815         if ( rc != LDAP_SUCCESS ) {
816                 text = "searchDN massage error";
817                 goto error_return;
818         }
819
820         /*
821          * Rewrite the dn if needed
822          */
823         dc.rwmap = rwmap;
824 #ifdef ENABLE_REWRITE
825         dc.conn = op->o_conn;
826         dc.rs = rs;
827         dc.ctx = "searchFilterAttrDN";
828 #else /* ! ENABLE_REWRITE */
829         dc.tofrom = 0;
830         dc.normalized = 0;
831 #endif /* ! ENABLE_REWRITE */
832
833         rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
834         if ( rc != LDAP_SUCCESS ) {
835                 text = "searchFilter/searchFilterAttrDN massage error";
836                 goto error_return;
837         }
838
839         f = str2filter_x( op, fstr.bv_val );
840
841         if ( f == NULL ) {
842                 text = "massaged filter parse error";
843                 goto error_return;
844         }
845
846         op->ors_filter = f;
847         op->ors_filterstr = fstr;
848
849         rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
850                         op->ors_attrs, &an, RWM_MAP );
851         if ( rc != LDAP_SUCCESS ) {
852                 text = "attribute list mapping error";
853                 goto error_return;
854         }
855
856         op->ors_attrs = an;
857         roc->cb.sc_response = rwm_swap_attrs;
858
859         op->o_callback = &roc->cb;
860
861         return SLAP_CB_CONTINUE;
862
863 error_return:;
864         if ( an != NULL ) {
865                 ch_free( an );
866         }
867
868         if ( f != NULL ) {
869                 filter_free_x( op, f );
870         }
871
872         if ( !BER_BVISNULL( &fstr ) ) {
873                 ch_free( fstr.bv_val );
874         }
875
876         op->oq_search = roc->ros.oq_search;
877
878         op->o_bd->bd_info = (BackendInfo *)on->on_info;
879         send_ldap_error( op, rs, rc, text );
880
881         return -1;
882
883 }
884
885 static int
886 rwm_exop_passwd( Operation *op, SlapReply *rs )
887 {
888         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
889         int                     rc;
890         rwm_op_cb *roc;
891
892         struct berval   id = BER_BVNULL,
893                         pwold = BER_BVNULL,
894                         pwnew = BER_BVNULL;
895
896         if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
897                 return LDAP_SUCCESS;
898         }
899
900         if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
901                 rs->sr_err = LDAP_OTHER;
902                 return rs->sr_err;
903         }
904
905         rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
906                 &pwold, &pwnew, &rs->sr_text );
907         if ( rs->sr_err != LDAP_SUCCESS ) {
908                 return rs->sr_err;
909         }
910
911         if ( !BER_BVISNULL( &id ) ) {
912                 rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
913                                 &op->o_req_ndn, op->o_tmpmemctx );
914                 if ( rs->sr_err != LDAP_SUCCESS ) {
915                         rs->sr_text = "Invalid DN";
916                         return rs->sr_err;
917                 }
918
919         } else {
920                 ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
921                 ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
922         }
923
924         roc = rwm_callback_get( op, rs );
925
926 #ifdef ENABLE_REWRITE
927         rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
928 #else /* ! ENABLE_REWRITE */
929         rc = 1;
930         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
931 #endif /* ! ENABLE_REWRITE */
932         if ( rc != LDAP_SUCCESS ) {
933                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
934                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
935                 return -1;
936         }
937
938         /* TODO: re-encode the request with the massaged DN */
939
940         op->o_callback = &roc->cb;
941
942         return SLAP_CB_CONTINUE;
943 }
944
945 static struct exop {
946         struct berval   oid;
947         BI_op_extended  *extended;
948 } exop_table[] = {
949         { BER_BVC(LDAP_EXOP_MODIFY_PASSWD),     rwm_exop_passwd },
950         { BER_BVNULL, NULL }
951 };
952
953 static int
954 rwm_extended( Operation *op, SlapReply *rs )
955 {
956         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
957         int                     rc;
958         rwm_op_cb *roc;
959
960         int     i;
961
962         for ( i = 0; exop_table[i].extended != NULL; i++ ) {
963                 if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
964                 {
965                         rc = exop_table[i].extended( op, rs );
966                         switch ( rc ) {
967                         case LDAP_SUCCESS:
968                                 break;
969
970                         case SLAP_CB_CONTINUE:
971                         case SLAPD_ABANDON:
972                                 return rc;
973
974                         default:
975                                 send_ldap_result( op, rs );
976                                 return rc;
977                         }
978                         break;
979                 }
980         }
981
982         roc = rwm_callback_get( op, rs );
983
984 #ifdef ENABLE_REWRITE
985         rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
986 #else /* ! ENABLE_REWRITE */
987         rc = 1;
988         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
989 #endif /* ! ENABLE_REWRITE */
990         if ( rc != LDAP_SUCCESS ) {
991                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
992                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
993                 return -1;
994         }
995
996         /* TODO: rewrite/map extended data ? ... */
997         op->o_callback = &roc->cb;
998
999         return SLAP_CB_CONTINUE;
1000 }
1001
1002 static int
1003 rwm_matched( Operation *op, SlapReply *rs )
1004 {
1005         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1006         struct ldaprwmap        *rwmap = 
1007                         (struct ldaprwmap *)on->on_bi.bi_private;
1008
1009         struct berval           dn, mdn;
1010         dncookie                dc;
1011         int                     rc;
1012
1013         if ( rs->sr_matched == NULL ) {
1014                 return SLAP_CB_CONTINUE;
1015         }
1016
1017         dc.rwmap = rwmap;
1018 #ifdef ENABLE_REWRITE
1019         dc.conn = op->o_conn;
1020         dc.rs = rs;
1021         dc.ctx = "matchedDN";
1022 #else /* ! ENABLE_REWRITE */
1023         dc.tofrom = 0;
1024         dc.normalized = 0;
1025 #endif /* ! ENABLE_REWRITE */
1026         ber_str2bv( rs->sr_matched, 0, 0, &dn );
1027         mdn = dn;
1028         rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
1029         if ( rc != LDAP_SUCCESS ) {
1030                 rs->sr_err = rc;
1031                 rs->sr_text = "Rewrite error";
1032                 return 1;
1033         }
1034
1035         if ( mdn.bv_val != dn.bv_val ) {
1036                 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
1037                         ch_free( (void *)rs->sr_matched );
1038
1039                 } else {
1040                         rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
1041                 }
1042                 rs->sr_matched = mdn.bv_val;
1043         }
1044         
1045         return SLAP_CB_CONTINUE;
1046 }
1047
1048 static int
1049 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
1050 {
1051         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1052         struct ldaprwmap        *rwmap = 
1053                         (struct ldaprwmap *)on->on_bi.bi_private;
1054
1055         dncookie                dc;
1056         int                     rc;
1057         Attribute               **ap;
1058         int                     isupdate;
1059
1060         /*
1061          * Rewrite the dn attrs, if needed
1062          */
1063         dc.rwmap = rwmap;
1064 #ifdef ENABLE_REWRITE
1065         dc.conn = op->o_conn;
1066         dc.rs = NULL; 
1067 #else /* ! ENABLE_REWRITE */
1068         dc.tofrom = 0;
1069         dc.normalized = 0;
1070 #endif /* ! ENABLE_REWRITE */
1071
1072         /* FIXME: the entries are in the remote mapping form;
1073          * so we need to select those attributes we are willing
1074          * to return, and remap them accordingly */
1075
1076         /* FIXME: in principle, one could map an attribute
1077          * on top of another, which already exists.
1078          * As such, in the end there might exist more than
1079          * one instance of an attribute.
1080          * We should at least check if this occurs, and issue
1081          * an error (because multiple instances of attrs in 
1082          * response are not valid), or merge the values (what
1083          * about duplicate values?) */
1084         isupdate = be_shadow_update( op );
1085         for ( ap = a_first; *ap; ) {
1086                 struct ldapmapping      *mapping = NULL;
1087                 int                     drop_missing;
1088                 int                     last;
1089                 Attribute               *a;
1090
1091                 if ( SLAP_OPATTRS( rs->sr_attr_flags ) && is_at_operational( (*ap)->a_desc->ad_type ) )
1092                 {
1093                         /* go on */ ;
1094                         
1095                 } else {
1096                         if ( op->ors_attrs != NULL && 
1097                                         !SLAP_USERATTRS( rs->sr_attr_flags ) &&
1098                                         !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
1099                         {
1100                                 goto cleanup_attr;
1101                         }
1102
1103                         drop_missing = rwm_mapping( &rwmap->rwm_at,
1104                                         &(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
1105                         if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
1106                         {
1107                                 goto cleanup_attr;
1108                         }
1109
1110                         if ( mapping != NULL ) {
1111                                 (*ap)->a_desc = mapping->m_dst_ad;
1112                         }
1113                 }
1114
1115                 if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
1116                         if ( stripEntryDN ) {
1117                                 /* will be generated by frontend */
1118                                 goto cleanup_attr;
1119                         }
1120                         
1121                 } else if ( !isupdate
1122                         && !get_relax( op )
1123                         && (*ap)->a_desc->ad_type->sat_no_user_mod 
1124                         && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
1125                 {
1126                         goto next_attr;
1127                 }
1128
1129                 for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ )
1130                         /* just count */ ;
1131
1132                 if ( last == 0 ) {
1133                         /* empty? leave it in place because of attrsonly and vlv */
1134                         goto next_attr;
1135                 }
1136                 last--;
1137
1138                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
1139                                 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
1140                 {
1141                         struct berval   *bv;
1142                         
1143                         for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1144                                 struct berval   mapped;
1145
1146                                 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
1147                                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
1148                                         ch_free( bv[0].bv_val );
1149                                         BER_BVZERO( &bv[0] );
1150                                         if ( &(*ap)->a_vals[last] > &bv[0] ) {
1151                                                 bv[0] = (*ap)->a_vals[last];
1152                                                 BER_BVZERO( &(*ap)->a_vals[last] );
1153                                         }
1154                                         last--;
1155                                         bv--;
1156
1157                                 } else if ( mapped.bv_val != bv[0].bv_val ) {
1158                                         /*
1159                                          * FIXME: after LBER_FREEing
1160                                          * the value is replaced by
1161                                          * ch_alloc'ed memory
1162                                          */
1163                                         ber_bvreplace( &bv[0], &mapped );
1164                                 }
1165                         }
1166
1167                 /*
1168                  * It is necessary to try to rewrite attributes with
1169                  * dn syntax because they might be used in ACLs as
1170                  * members of groups; since ACLs are applied to the
1171                  * rewritten stuff, no dn-based subject clause could
1172                  * be used at the ldap backend side (see
1173                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
1174                  * The problem can be overcome by moving the dn-based
1175                  * ACLs to the target directory server, and letting
1176                  * everything pass thru the ldap backend. */
1177                 /* FIXME: handle distinguishedName-like syntaxes, like
1178                  * nameAndOptionalUID */
1179                 } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
1180                                 || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
1181                 {
1182 #ifdef ENABLE_REWRITE
1183                         dc.ctx = "searchAttrDN";
1184 #endif /* ENABLE_REWRITE */
1185                         rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
1186                         if ( rc != LDAP_SUCCESS ) {
1187                                 goto cleanup_attr;
1188                         }
1189
1190                 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
1191 #ifdef ENABLE_REWRITE
1192                         dc.ctx = "searchAttrDN";
1193 #endif /* ENABLE_REWRITE */
1194                         rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
1195                         if ( rc != LDAP_SUCCESS ) {
1196                                 goto cleanup_attr;
1197                         }
1198                 }
1199
1200                 if ( mapping != NULL ) {
1201                         /* rewrite the attribute description */
1202                         assert( mapping->m_dst_ad != NULL );
1203                         (*ap)->a_desc = mapping->m_dst_ad;
1204                 }
1205
1206 next_attr:;
1207                 ap = &(*ap)->a_next;
1208                 continue;
1209
1210 cleanup_attr:;
1211                 a = *ap;
1212                 *ap = (*ap)->a_next;
1213
1214                 attr_free( a );
1215         }
1216
1217         return 0;
1218 }
1219
1220 static int
1221 rwm_send_entry( Operation *op, SlapReply *rs )
1222 {
1223         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1224         struct ldaprwmap        *rwmap = 
1225                         (struct ldaprwmap *)on->on_bi.bi_private;
1226
1227         Entry                   *e = NULL;
1228         slap_mask_t             flags;
1229         struct berval           dn = BER_BVNULL,
1230                                 ndn = BER_BVNULL;
1231         dncookie                dc;
1232         int                     rc;
1233
1234         assert( rs->sr_entry != NULL );
1235
1236         /*
1237          * Rewrite the dn of the result, if needed
1238          */
1239         dc.rwmap = rwmap;
1240 #ifdef ENABLE_REWRITE
1241         dc.conn = op->o_conn;
1242         dc.rs = NULL; 
1243         dc.ctx = "searchEntryDN";
1244 #else /* ! ENABLE_REWRITE */
1245         dc.tofrom = 0;
1246         dc.normalized = 0;
1247 #endif /* ! ENABLE_REWRITE */
1248
1249         e = rs->sr_entry;
1250         flags = rs->sr_flags;
1251         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
1252                 /* FIXME: all we need to duplicate are:
1253                  * - dn
1254                  * - ndn
1255                  * - attributes that are requested
1256                  * - no values if attrsonly is set
1257                  */
1258
1259                 e = entry_dup( e );
1260                 if ( e == NULL ) {
1261                         rc = LDAP_NO_MEMORY;
1262                         goto fail;
1263                 }
1264
1265                 flags &= ~REP_ENTRY_MUSTRELEASE;
1266                 flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
1267         }
1268
1269         /*
1270          * Note: this may fail if the target host(s) schema differs
1271          * from the one known to the meta, and a DN with unknown
1272          * attributes is returned.
1273          */
1274         dn = e->e_name;
1275         ndn = e->e_nname;
1276         rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
1277         if ( rc != LDAP_SUCCESS ) {
1278                 rc = 1;
1279                 goto fail;
1280         }
1281
1282         if ( e->e_name.bv_val != dn.bv_val ) {
1283                 ch_free( e->e_name.bv_val );
1284                 ch_free( e->e_nname.bv_val );
1285
1286                 e->e_name = dn;
1287                 e->e_nname = ndn;
1288         }
1289
1290         /* TODO: map entry attribute types, objectclasses 
1291          * and dn-valued attribute values */
1292
1293         /* FIXME: the entries are in the remote mapping form;
1294          * so we need to select those attributes we are willing
1295          * to return, and remap them accordingly */
1296         (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
1297
1298         if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1299                 be_entry_release_rw( op, rs->sr_entry, 0 );
1300         }
1301
1302         rs->sr_entry = e;
1303         rs->sr_flags = flags;
1304
1305         return SLAP_CB_CONTINUE;
1306
1307 fail:;
1308         if ( e != NULL && e != rs->sr_entry ) {
1309                 if ( e->e_name.bv_val == dn.bv_val ) {
1310                         BER_BVZERO( &e->e_name );
1311                 }
1312
1313                 if ( e->e_nname.bv_val == ndn.bv_val ) {
1314                         BER_BVZERO( &e->e_nname );
1315                 }
1316
1317                 entry_free( e );
1318         }
1319
1320         if ( !BER_BVISNULL( &dn ) ) {
1321                 ch_free( dn.bv_val );
1322         }
1323
1324         if ( !BER_BVISNULL( &ndn ) ) {
1325                 ch_free( ndn.bv_val );
1326         }
1327
1328         return rc;
1329 }
1330
1331 static int
1332 rwm_operational( Operation *op, SlapReply *rs )
1333 {
1334         /* FIXME: the entries are in the remote mapping form;
1335          * so we need to select those attributes we are willing
1336          * to return, and remap them accordingly */
1337         if ( rs->sr_operational_attrs ) {
1338                 rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
1339         }
1340
1341         return SLAP_CB_CONTINUE;
1342 }
1343
1344 #if 0
1345 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1346  * rewritten for subsequent operations; fine for plain suffixmassage,
1347  * but destroys everything else */
1348 static int
1349 rwm_chk_referrals( Operation *op, SlapReply *rs )
1350 {
1351         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1352         int                     rc;
1353
1354 #ifdef ENABLE_REWRITE
1355         rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1356 #else /* ! ENABLE_REWRITE */
1357         rc = 1;
1358         rc = rwm_op_dn_massage( op, rs, &rc );
1359 #endif /* ! ENABLE_REWRITE */
1360         if ( rc != LDAP_SUCCESS ) {
1361                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1362                 send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1363                 return -1;
1364         }
1365
1366         return SLAP_CB_CONTINUE;
1367 }
1368 #endif
1369
1370 static int
1371 rwm_rw_config(
1372         BackendDB       *be,
1373         const char      *fname,
1374         int             lineno,
1375         int             argc,
1376         char            **argv )
1377 {
1378 #ifdef ENABLE_REWRITE
1379         slap_overinst           *on = (slap_overinst *) be->bd_info;
1380         struct ldaprwmap        *rwmap = 
1381                         (struct ldaprwmap *)on->on_bi.bi_private;
1382
1383         return rewrite_parse( rwmap->rwm_rw,
1384                                 fname, lineno, argc, argv );
1385
1386 #else /* !ENABLE_REWRITE */
1387         fprintf( stderr, "%s: line %d: rewrite capabilities "
1388                         "are not enabled\n", fname, lineno );
1389 #endif /* !ENABLE_REWRITE */
1390                 
1391         return 0;
1392 }
1393
1394 static int
1395 rwm_suffixmassage_config(
1396         BackendDB       *be,
1397         const char      *fname,
1398         int             lineno,
1399         int             argc,
1400         char            **argv )
1401 {
1402         slap_overinst           *on = (slap_overinst *) be->bd_info;
1403         struct ldaprwmap        *rwmap = 
1404                         (struct ldaprwmap *)on->on_bi.bi_private;
1405
1406         struct berval           bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1407         int                     massaged;
1408 #ifdef ENABLE_REWRITE
1409         int                     rc;
1410 #endif /* ENABLE_REWRITE */
1411                 
1412         /*
1413          * syntax:
1414          * 
1415          *      suffixmassage [<suffix>] <massaged suffix>
1416          *
1417          * the [<suffix>] field must be defined as a valid suffix
1418          * for the current database;
1419          * the <massaged suffix> shouldn't have already been
1420          * defined as a valid suffix for the current server
1421          */
1422         if ( argc == 2 ) {
1423                 if ( be->be_suffix == NULL ) {
1424                         fprintf( stderr, "%s: line %d: "
1425                                        " \"suffixMassage [<suffix>]"
1426                                        " <massaged suffix>\" without "
1427                                        "<suffix> part requires database "
1428                                        "suffix be defined first.\n",
1429                                 fname, lineno );
1430                         return 1;
1431                 }
1432                 bvnc = be->be_suffix[ 0 ];
1433                 massaged = 1;
1434
1435         } else if ( argc == 3 ) {
1436                 ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1437                 massaged = 2;
1438
1439         } else  {
1440                 fprintf( stderr, "%s: line %d: syntax is"
1441                                " \"suffixMassage [<suffix>]"
1442                                " <massaged suffix>\"\n",
1443                         fname, lineno );
1444                 return 1;
1445         }
1446
1447         if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1448                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1449                         fname, lineno, bvnc.bv_val );
1450                 return 1;
1451         }
1452
1453         ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1454         if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1455                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1456                                 fname, lineno, brnc.bv_val );
1457                 free( nvnc.bv_val );
1458                 free( pvnc.bv_val );
1459                 return 1;
1460         }
1461
1462 #ifdef ENABLE_REWRITE
1463         /*
1464          * The suffix massaging is emulated 
1465          * by means of the rewrite capabilities
1466          */
1467         rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1468                         &pvnc, &nvnc, &prnc, &nrnc );
1469         free( nvnc.bv_val );
1470         free( pvnc.bv_val );
1471         free( nrnc.bv_val );
1472         free( prnc.bv_val );
1473
1474         return( rc );
1475
1476 #else /* !ENABLE_REWRITE */
1477         ber_bvarray_add( &rwmap->rwm_suffix_massage, &pvnc );
1478         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nvnc );
1479                 
1480         ber_bvarray_add( &rwmap->rwm_suffix_massage, &prnc );
1481         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nrnc );
1482 #endif /* !ENABLE_REWRITE */
1483
1484         return 0;
1485 }
1486
1487 static int
1488 rwm_m_config(
1489         BackendDB       *be,
1490         const char      *fname,
1491         int             lineno,
1492         int             argc,
1493         char            **argv )
1494 {
1495         slap_overinst           *on = (slap_overinst *) be->bd_info;
1496         struct ldaprwmap        *rwmap = 
1497                         (struct ldaprwmap *)on->on_bi.bi_private;
1498
1499         /* objectclass/attribute mapping */
1500         return rwm_map_config( &rwmap->rwm_oc,
1501                         &rwmap->rwm_at,
1502                         fname, lineno, argc, argv );
1503 }
1504
1505 static int
1506 rwm_response( Operation *op, SlapReply *rs )
1507 {
1508         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
1509         struct ldaprwmap        *rwmap = 
1510                         (struct ldaprwmap *)on->on_bi.bi_private;
1511
1512         int             rc;
1513
1514         if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1515                 return rwm_send_entry( op, rs );
1516         }
1517
1518         switch( op->o_tag ) {
1519         case LDAP_REQ_SEARCH:
1520         case LDAP_REQ_BIND:
1521         case LDAP_REQ_ADD:
1522         case LDAP_REQ_DELETE:
1523         case LDAP_REQ_MODRDN:
1524         case LDAP_REQ_MODIFY:
1525         case LDAP_REQ_COMPARE:
1526         case LDAP_REQ_EXTENDED:
1527                 if ( rs->sr_ref ) {
1528                         dncookie                dc;
1529
1530                         /*
1531                          * Rewrite the dn of the referrals, if needed
1532                          */
1533                         dc.rwmap = rwmap;
1534 #ifdef ENABLE_REWRITE
1535                         dc.conn = op->o_conn;
1536                         dc.rs = NULL; 
1537                         dc.ctx = "referralDN";
1538 #else /* ! ENABLE_REWRITE */
1539                         dc.tofrom = 0;
1540                         dc.normalized = 0;
1541 #endif /* ! ENABLE_REWRITE */
1542                         rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1543                         if ( rc != LDAP_SUCCESS ) {
1544                                 rc = 1;
1545                                 break;
1546                         }
1547                 }
1548                 rc = rwm_matched( op, rs );
1549                 break;
1550
1551         default:
1552                 rc = SLAP_CB_CONTINUE;
1553                 break;
1554         }
1555
1556         return rc;
1557 }
1558
1559 static int
1560 rwm_db_config(
1561         BackendDB       *be,
1562         const char      *fname,
1563         int             lineno,
1564         int             argc,
1565         char            **argv )
1566 {
1567         slap_overinst           *on = (slap_overinst *) be->bd_info;
1568         struct ldaprwmap        *rwmap = 
1569                         (struct ldaprwmap *)on->on_bi.bi_private;
1570
1571         int             rc = 0;
1572         char            *argv0 = NULL;
1573
1574         if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1575                 argv0 = argv[ 0 ];
1576                 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1577         }
1578
1579         if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1580                 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1581
1582         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1583                 rc = rwm_m_config( be, fname, lineno, argc, argv );
1584
1585         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1586                 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1587
1588         } else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
1589                 if ( argc != 2 ) {
1590                         fprintf( stderr,
1591                 "%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
1592                                         fname, lineno );
1593                         return( 1 );
1594                 }
1595
1596                 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1597                         rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F|RWM_F_SUPPORT_T_F_DISCOVER);
1598
1599                 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1600                         rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
1601
1602                 /* TODO: not implemented yet */
1603                 } else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1604                         fprintf( stderr,
1605                 "%s: line %d: \"discover\" not supported yet "
1606                 "in \"t-f-support {no|yes|discover}\".\n",
1607                                         fname, lineno );
1608                         return( 1 );
1609 #if 0
1610                         rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
1611 #endif
1612
1613                 } else {
1614                         fprintf( stderr,
1615         "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1616                                 fname, lineno, argv[ 1 ] );
1617                         return 1;
1618                 }
1619
1620         } else {
1621                 rc = SLAP_CONF_UNKNOWN;
1622         }
1623
1624         if ( argv0 ) {
1625                 argv[ 0 ] = argv0;
1626         }
1627
1628         return rc;
1629 }
1630
1631 static int
1632 rwm_db_init(
1633         BackendDB       *be )
1634 {
1635         slap_overinst           *on = (slap_overinst *) be->bd_info;
1636         struct ldapmapping      *mapping = NULL;
1637         struct ldaprwmap        *rwmap;
1638 #ifdef ENABLE_REWRITE
1639         char                    *rargv[ 3 ];
1640 #endif /* ENABLE_REWRITE */
1641         int                     rc = 0;
1642
1643         rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
1644
1645 #ifdef ENABLE_REWRITE
1646         rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
1647         if ( rwmap->rwm_rw == NULL ) {
1648                 rc = -1;
1649                 goto error_return;
1650         }
1651
1652         /* this rewriteContext by default must be null;
1653          * rules can be added if required */
1654         rargv[ 0 ] = "rewriteContext";
1655         rargv[ 1 ] = "searchFilter";
1656         rargv[ 2 ] = NULL;
1657         rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
1658
1659         rargv[ 0 ] = "rewriteContext";
1660         rargv[ 1 ] = "default";
1661         rargv[ 2 ] = NULL;
1662         rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
1663 #endif /* ENABLE_REWRITE */
1664
1665         if ( rwm_map_init( &rwmap->rwm_oc, &mapping ) != LDAP_SUCCESS ||
1666                         rwm_map_init( &rwmap->rwm_at, &mapping ) != LDAP_SUCCESS )
1667         {
1668                 rc = 1;
1669                 goto error_return;
1670         }
1671
1672 error_return:;
1673         on->on_bi.bi_private = (void *)rwmap;
1674
1675         if ( rc ) {
1676                 (void)rwm_db_destroy( be );
1677         }
1678
1679         return rc;
1680 }
1681
1682 static int
1683 rwm_db_destroy(
1684         BackendDB       *be )
1685 {
1686         slap_overinst   *on = (slap_overinst *) be->bd_info;
1687         int             rc = 0;
1688
1689         if ( on->on_bi.bi_private ) {
1690                 struct ldaprwmap        *rwmap = 
1691                         (struct ldaprwmap *)on->on_bi.bi_private;
1692
1693 #ifdef ENABLE_REWRITE
1694                 if ( rwmap->rwm_rw ) {
1695                         rewrite_info_delete( &rwmap->rwm_rw );
1696                 }
1697 #else /* !ENABLE_REWRITE */
1698                 if ( rwmap->rwm_suffix_massage ) {
1699                         ber_bvarray_free( rwmap->rwm_suffix_massage );
1700                 }
1701 #endif /* !ENABLE_REWRITE */
1702
1703                 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
1704                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
1705                 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
1706                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
1707
1708                 ch_free( rwmap );
1709         }
1710
1711         return rc;
1712 }
1713
1714 static slap_overinst rwm = { { NULL } };
1715
1716 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1717 static
1718 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1719 int
1720 rwm_initialize( void )
1721 {
1722         memset( &rwm, 0, sizeof( slap_overinst ) );
1723
1724         rwm.on_bi.bi_type = "rwm";
1725         rwm.on_bi.bi_flags =
1726                 SLAPO_BFLAG_SINGLE |
1727                 0;
1728
1729         rwm.on_bi.bi_db_init = rwm_db_init;
1730         rwm.on_bi.bi_db_config = rwm_db_config;
1731         rwm.on_bi.bi_db_destroy = rwm_db_destroy;
1732
1733         rwm.on_bi.bi_op_bind = rwm_op_bind;
1734         rwm.on_bi.bi_op_search = rwm_op_search;
1735         rwm.on_bi.bi_op_compare = rwm_op_compare;
1736         rwm.on_bi.bi_op_modify = rwm_op_modify;
1737         rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
1738         rwm.on_bi.bi_op_add = rwm_op_add;
1739         rwm.on_bi.bi_op_delete = rwm_op_delete;
1740         rwm.on_bi.bi_op_unbind = rwm_op_unbind;
1741         rwm.on_bi.bi_extended = rwm_extended;
1742
1743         rwm.on_bi.bi_operational = rwm_operational;
1744         rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
1745
1746 #ifdef ENABLE_REWRITE
1747         rwm.on_bi.bi_connection_init = rwm_conn_init;
1748         rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
1749 #endif /* ENABLE_REWRITE */
1750
1751         rwm.on_response = rwm_response;
1752
1753         return overlay_register( &rwm );
1754 }
1755
1756 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1757 int
1758 init_module( int argc, char *argv[] )
1759 {
1760         return rwm_initialize();
1761 }
1762 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1763
1764 #endif /* SLAPD_OVER_RWM */