]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/rwm.c
Fallout from ITS#4986 - remove unused param of select_backend()
[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-2007 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         ber_tag_t r_tag;
31         struct berval ro_dn;
32         struct berval ro_ndn;
33         struct berval r_dn;
34         struct berval r_ndn;
35         AttributeName *mapped_attrs;
36         OpRequest o_request;
37 } rwm_op_state;
38
39 static int
40 rwm_db_destroy( BackendDB *be );
41
42 typedef struct rwm_op_cb {
43         slap_callback cb;
44         rwm_op_state ros;
45 } rwm_op_cb;
46
47 static int
48 rwm_op_cleanup( Operation *op, SlapReply *rs )
49 {
50         slap_callback   *cb = op->o_callback;
51         rwm_op_state *ros = cb->sc_private;
52
53         if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
54                 op->o_abandon || rs->sr_err == SLAPD_ABANDON ) {
55
56                 op->o_req_dn = ros->ro_dn;
57                 op->o_req_ndn = ros->ro_ndn;
58
59                 if ( !BER_BVISNULL( &ros->r_dn )
60                         && ros->r_dn.bv_val != ros->r_ndn.bv_val )
61                 {
62                         ch_free( ros->r_dn.bv_val );
63                         BER_BVZERO( &ros->r_dn );
64                 }
65
66                 if ( !BER_BVISNULL( &ros->r_ndn ) ) {
67                         ch_free( ros->r_ndn.bv_val );
68                         BER_BVZERO( &ros->r_ndn );
69                 }
70
71                 switch( ros->r_tag ) {
72                 case LDAP_REQ_COMPARE:
73                         if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
74                                 op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
75                         op->orc_ava = ros->orc_ava;
76                         break;
77                 case LDAP_REQ_MODIFY:
78                         slap_mods_free( op->orm_modlist, 1 );
79                         op->orm_modlist = ros->orm_modlist;
80                         break;
81                 case LDAP_REQ_MODRDN:
82                         if ( op->orr_newSup != ros->orr_newSup ) {
83                                 ch_free( op->orr_newSup->bv_val );
84                                 ch_free( op->orr_nnewSup->bv_val );
85                                 op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
86                                 op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
87                                 op->orr_newSup = ros->orr_newSup;
88                                 op->orr_nnewSup = ros->orr_nnewSup;
89                         }
90                         break;
91                 case LDAP_REQ_SEARCH:
92                         ch_free( ros->mapped_attrs );
93                         filter_free_x( op, op->ors_filter );
94                         ch_free( op->ors_filterstr.bv_val );
95                         op->ors_attrs = ros->ors_attrs;
96                         op->ors_filter = ros->ors_filter;
97                         op->ors_filterstr = ros->ors_filterstr;
98                         break;
99                 case LDAP_REQ_EXTENDED:
100                         if ( op->ore_reqdata != ros->ore_reqdata ) {
101                                 ber_bvfree( op->ore_reqdata );
102                                 op->ore_reqdata = ros->ore_reqdata;
103                         }
104                         break;
105                 default:        break;
106                 }
107                 op->o_callback = op->o_callback->sc_next;
108                 op->o_tmpfree( cb, op->o_tmpmemctx );
109         }
110
111         return SLAP_CB_CONTINUE;
112 }
113
114 static rwm_op_cb *
115 rwm_callback_get( Operation *op, SlapReply *rs )
116 {
117         rwm_op_cb       *roc = NULL;
118
119         roc = op->o_tmpalloc( sizeof( struct rwm_op_cb ), op->o_tmpmemctx );
120         roc->cb.sc_cleanup = rwm_op_cleanup;
121         roc->cb.sc_response = NULL;
122         roc->cb.sc_next = op->o_callback;
123         roc->cb.sc_private = &roc->ros;
124         roc->ros.r_tag = op->o_tag;
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         op->o_req_ndn = ndn;
190         ros->r_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         /* other overlays might have touched op->ors_attrs, 
785          * so we restore the original version here, otherwise
786          * attribute-mapping might fail */
787         op->ors_attrs = ros->mapped_attrs; 
788         
789         return SLAP_CB_CONTINUE;
790 }
791
792 static int
793 rwm_op_search( Operation *op, SlapReply *rs )
794 {
795         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
796         struct ldaprwmap        *rwmap = 
797                         (struct ldaprwmap *)on->on_bi.bi_private;
798
799         int                     rc;
800         dncookie                dc;
801
802         struct berval           fstr = BER_BVNULL;
803         Filter                  *f = NULL;
804
805         AttributeName           *an = NULL;
806
807         char                    *text = NULL;
808
809         rwm_op_cb               *roc = rwm_callback_get( op, rs );
810
811 #ifdef ENABLE_REWRITE
812         rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
813                 "searchFilter", op->ors_filterstr.bv_val );
814         if ( rc == LDAP_SUCCESS )
815                 rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
816 #else /* ! ENABLE_REWRITE */
817         rc = 1;
818         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
819 #endif /* ! ENABLE_REWRITE */
820         if ( rc != LDAP_SUCCESS ) {
821                 text = "searchDN massage error";
822                 goto error_return;
823         }
824
825         /*
826          * Rewrite the dn if needed
827          */
828         dc.rwmap = rwmap;
829 #ifdef ENABLE_REWRITE
830         dc.conn = op->o_conn;
831         dc.rs = rs;
832         dc.ctx = "searchFilterAttrDN";
833 #else /* ! ENABLE_REWRITE */
834         dc.tofrom = 0;
835         dc.normalized = 0;
836 #endif /* ! ENABLE_REWRITE */
837
838         rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
839         if ( rc != LDAP_SUCCESS ) {
840                 text = "searchFilter/searchFilterAttrDN massage error";
841                 goto error_return;
842         }
843
844         f = str2filter_x( op, fstr.bv_val );
845
846         if ( f == NULL ) {
847                 text = "massaged filter parse error";
848                 goto error_return;
849         }
850
851         op->ors_filter = f;
852         op->ors_filterstr = fstr;
853
854         rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
855                         op->ors_attrs, &an, RWM_MAP );
856         if ( rc != LDAP_SUCCESS ) {
857                 text = "attribute list mapping error";
858                 goto error_return;
859         }
860
861         op->ors_attrs = an;
862         /* store the mapped Attributes for later usage, in
863          * the case that other overlays change op->ors_attrs */
864         roc->ros.mapped_attrs = an;
865         roc->cb.sc_response = rwm_swap_attrs;
866
867         op->o_callback = &roc->cb;
868
869         return SLAP_CB_CONTINUE;
870
871 error_return:;
872         if ( an != NULL ) {
873                 ch_free( an );
874         }
875
876         if ( f != NULL ) {
877                 filter_free_x( op, f );
878         }
879
880         if ( !BER_BVISNULL( &fstr ) ) {
881                 ch_free( fstr.bv_val );
882         }
883
884         op->oq_search = roc->ros.oq_search;
885
886         op->o_bd->bd_info = (BackendInfo *)on->on_info;
887         send_ldap_error( op, rs, rc, text );
888
889         return -1;
890
891 }
892
893 static int
894 rwm_exop_passwd( Operation *op, SlapReply *rs )
895 {
896         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
897         int                     rc;
898         rwm_op_cb *roc;
899
900         struct berval   id = BER_BVNULL,
901                         pwold = BER_BVNULL,
902                         pwnew = BER_BVNULL;
903         BerElement *ber = NULL;
904
905         if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
906                 return LDAP_SUCCESS;
907         }
908
909         if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
910                 rs->sr_err = LDAP_OTHER;
911                 return rs->sr_err;
912         }
913
914         rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
915                 &pwold, &pwnew, &rs->sr_text );
916         if ( rs->sr_err != LDAP_SUCCESS ) {
917                 return rs->sr_err;
918         }
919
920         if ( !BER_BVISNULL( &id ) ) {
921                 rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
922                                 &op->o_req_ndn, op->o_tmpmemctx );
923                 if ( rs->sr_err != LDAP_SUCCESS ) {
924                         rs->sr_text = "Invalid DN";
925                         return rs->sr_err;
926                 }
927
928         } else {
929                 ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
930                 ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
931         }
932
933         roc = rwm_callback_get( op, rs );
934
935 #ifdef ENABLE_REWRITE
936         rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
937 #else /* ! ENABLE_REWRITE */
938         rc = 1;
939         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
940 #endif /* ! ENABLE_REWRITE */
941         if ( rc != LDAP_SUCCESS ) {
942                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
943                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
944                 return -1;
945         }
946
947         ber = ber_alloc_t( LBER_USE_DER );
948         if ( !ber ) {
949                 rs->sr_err = LDAP_OTHER;
950                 rs->sr_text = "No memory";
951                 return rs->sr_err;
952         }
953         ber_printf( ber, "{" );
954         if ( !BER_BVISNULL( &id )) {
955                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, 
956                         &op->o_req_dn );
957         }
958         if ( !BER_BVISNULL( &pwold )) {
959                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &pwold );
960         }
961         if ( !BER_BVISNULL( &pwnew )) {
962                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &pwnew );
963         }
964         ber_printf( ber, "N}" );
965         ber_flatten( ber, &op->ore_reqdata );
966         ber_free( ber, 1 );
967
968         op->o_callback = &roc->cb;
969
970         return SLAP_CB_CONTINUE;
971 }
972
973 static struct exop {
974         struct berval   oid;
975         BI_op_extended  *extended;
976 } exop_table[] = {
977         { BER_BVC(LDAP_EXOP_MODIFY_PASSWD),     rwm_exop_passwd },
978         { BER_BVNULL, NULL }
979 };
980
981 static int
982 rwm_extended( Operation *op, SlapReply *rs )
983 {
984         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
985         int                     rc;
986         rwm_op_cb *roc;
987
988         int     i;
989
990         for ( i = 0; exop_table[i].extended != NULL; i++ ) {
991                 if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
992                 {
993                         rc = exop_table[i].extended( op, rs );
994                         switch ( rc ) {
995                         case LDAP_SUCCESS:
996                                 break;
997
998                         case SLAP_CB_CONTINUE:
999                         case SLAPD_ABANDON:
1000                                 return rc;
1001
1002                         default:
1003                                 send_ldap_result( op, rs );
1004                                 return rc;
1005                         }
1006                         break;
1007                 }
1008         }
1009
1010         roc = rwm_callback_get( op, rs );
1011
1012 #ifdef ENABLE_REWRITE
1013         rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
1014 #else /* ! ENABLE_REWRITE */
1015         rc = 1;
1016         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
1017 #endif /* ! ENABLE_REWRITE */
1018         if ( rc != LDAP_SUCCESS ) {
1019                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1020                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
1021                 return -1;
1022         }
1023
1024         /* TODO: rewrite/map extended data ? ... */
1025         op->o_callback = &roc->cb;
1026
1027         return SLAP_CB_CONTINUE;
1028 }
1029
1030 static int
1031 rwm_matched( Operation *op, SlapReply *rs )
1032 {
1033         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1034         struct ldaprwmap        *rwmap = 
1035                         (struct ldaprwmap *)on->on_bi.bi_private;
1036
1037         struct berval           dn, mdn;
1038         dncookie                dc;
1039         int                     rc;
1040
1041         if ( rs->sr_matched == NULL ) {
1042                 return SLAP_CB_CONTINUE;
1043         }
1044
1045         dc.rwmap = rwmap;
1046 #ifdef ENABLE_REWRITE
1047         dc.conn = op->o_conn;
1048         dc.rs = rs;
1049         dc.ctx = "matchedDN";
1050 #else /* ! ENABLE_REWRITE */
1051         dc.tofrom = 0;
1052         dc.normalized = 0;
1053 #endif /* ! ENABLE_REWRITE */
1054         ber_str2bv( rs->sr_matched, 0, 0, &dn );
1055         mdn = dn;
1056         rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
1057         if ( rc != LDAP_SUCCESS ) {
1058                 rs->sr_err = rc;
1059                 rs->sr_text = "Rewrite error";
1060                 return 1;
1061         }
1062
1063         if ( mdn.bv_val != dn.bv_val ) {
1064                 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
1065                         ch_free( (void *)rs->sr_matched );
1066
1067                 } else {
1068                         rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
1069                 }
1070                 rs->sr_matched = mdn.bv_val;
1071         }
1072         
1073         return SLAP_CB_CONTINUE;
1074 }
1075
1076 static int
1077 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
1078 {
1079         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1080         struct ldaprwmap        *rwmap = 
1081                         (struct ldaprwmap *)on->on_bi.bi_private;
1082
1083         dncookie                dc;
1084         int                     rc;
1085         Attribute               **ap;
1086         int                     isupdate;
1087
1088         /*
1089          * Rewrite the dn attrs, if needed
1090          */
1091         dc.rwmap = rwmap;
1092 #ifdef ENABLE_REWRITE
1093         dc.conn = op->o_conn;
1094         dc.rs = NULL; 
1095 #else /* ! ENABLE_REWRITE */
1096         dc.tofrom = 0;
1097         dc.normalized = 0;
1098 #endif /* ! ENABLE_REWRITE */
1099
1100         /* FIXME: the entries are in the remote mapping form;
1101          * so we need to select those attributes we are willing
1102          * to return, and remap them accordingly */
1103
1104         /* FIXME: in principle, one could map an attribute
1105          * on top of another, which already exists.
1106          * As such, in the end there might exist more than
1107          * one instance of an attribute.
1108          * We should at least check if this occurs, and issue
1109          * an error (because multiple instances of attrs in 
1110          * response are not valid), or merge the values (what
1111          * about duplicate values?) */
1112         isupdate = be_shadow_update( op );
1113         for ( ap = a_first; *ap; ) {
1114                 struct ldapmapping      *mapping = NULL;
1115                 int                     drop_missing;
1116                 int                     last=-1;
1117                 Attribute               *a;
1118
1119                 if ( SLAP_OPATTRS( rs->sr_attr_flags ) && is_at_operational( (*ap)->a_desc->ad_type ) )
1120                 {
1121                         /* go on */ ;
1122                         
1123                 } else {
1124                         if ( op->ors_attrs != NULL && 
1125                                         !SLAP_USERATTRS( rs->sr_attr_flags ) &&
1126                                         !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
1127                         {
1128                                 goto cleanup_attr;
1129                         }
1130
1131                         drop_missing = rwm_mapping( &rwmap->rwm_at,
1132                                         &(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
1133                         if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
1134                         {
1135                                 goto cleanup_attr;
1136                         }
1137                         if ( mapping != NULL ) {
1138                                 assert( mapping->m_dst_ad != NULL );
1139
1140                                 /* try to normalize mapped Attributes if the original 
1141                                  * AttributeType was not normalized */
1142                                 if ((rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS) && 
1143                                         (!(*ap)->a_desc->ad_type->sat_equality || 
1144                                         !(*ap)->a_desc->ad_type->sat_equality->smr_normalize) &&
1145                                         mapping->m_dst_ad->ad_type->sat_equality &&
1146                                         mapping->m_dst_ad->ad_type->sat_equality->smr_normalize )
1147                                 {
1148                                         int i=0;
1149                                         for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ )
1150                                                 /* just count */ ;
1151
1152                                         if ( last )
1153                                         {
1154                                                 (*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) );
1155
1156                                                 for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[i]); i++ ) {
1157                                                         int             rc;
1158                                                         /*
1159                                                          * check that each value is valid per syntax
1160                                                          * and pretty if appropriate
1161                                                          */
1162                                                         rc = mapping->m_dst_ad->ad_type->sat_equality->smr_normalize(
1163                                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1164                                                                 mapping->m_dst_ad->ad_type->sat_syntax,
1165                                                                 mapping->m_dst_ad->ad_type->sat_equality,
1166                                                                 &(*ap)->a_vals[i], &(*ap)->a_nvals[i],
1167                                                                 NULL );
1168
1169                                                         if ( rc != LDAP_SUCCESS ) {
1170                                                                 BER_BVZERO( &(*ap)->a_nvals[i] );
1171                                                         }
1172                                                 }
1173                                                 BER_BVZERO( &(*ap)->a_nvals[i] );
1174                                         }
1175                                 }
1176                                 /* rewrite the attribute description */
1177                                 (*ap)->a_desc = mapping->m_dst_ad;
1178                         }
1179                 }
1180
1181                 if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
1182                         if ( stripEntryDN ) {
1183                                 /* will be generated by frontend */
1184                                 goto cleanup_attr;
1185                         }
1186                         
1187                 } else if ( !isupdate
1188                         && !get_relax( op )
1189                         && (*ap)->a_desc->ad_type->sat_no_user_mod 
1190                         && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
1191                 {
1192                         goto next_attr;
1193                 }
1194
1195                 if ( last == -1 ) { /* not yet counted */ 
1196                         for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ )
1197                                 /* just count */ ;
1198                 }
1199
1200                 if ( last == 0 ) {
1201                         /* empty? leave it in place because of attrsonly and vlv */
1202                         goto next_attr;
1203                 }
1204                 last--;
1205
1206                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
1207                                 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
1208                 {
1209                         struct berval   *bv;
1210                         
1211                         for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1212                                 struct berval   mapped;
1213
1214                                 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
1215                                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
1216                                         ch_free( bv[0].bv_val );
1217                                         BER_BVZERO( &bv[0] );
1218                                         if ( &(*ap)->a_vals[last] > &bv[0] ) {
1219                                                 bv[0] = (*ap)->a_vals[last];
1220                                                 BER_BVZERO( &(*ap)->a_vals[last] );
1221                                         }
1222                                         last--;
1223                                         bv--;
1224
1225                                 } else if ( mapped.bv_val != bv[0].bv_val ) {
1226                                         /*
1227                                          * FIXME: after LBER_FREEing
1228                                          * the value is replaced by
1229                                          * ch_alloc'ed memory
1230                                          */
1231                                         ber_bvreplace( &bv[0], &mapped );
1232                                 }
1233                         }
1234
1235                 /*
1236                  * It is necessary to try to rewrite attributes with
1237                  * dn syntax because they might be used in ACLs as
1238                  * members of groups; since ACLs are applied to the
1239                  * rewritten stuff, no dn-based subject clause could
1240                  * be used at the ldap backend side (see
1241                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
1242                  * The problem can be overcome by moving the dn-based
1243                  * ACLs to the target directory server, and letting
1244                  * everything pass thru the ldap backend. */
1245                 /* FIXME: handle distinguishedName-like syntaxes, like
1246                  * nameAndOptionalUID */
1247                 } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
1248                                 || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
1249                 {
1250 #ifdef ENABLE_REWRITE
1251                         dc.ctx = "searchAttrDN";
1252 #endif /* ENABLE_REWRITE */
1253                         rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
1254                         if ( rc != LDAP_SUCCESS ) {
1255                                 goto cleanup_attr;
1256                         }
1257
1258                 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
1259 #ifdef ENABLE_REWRITE
1260                         dc.ctx = "searchAttrDN";
1261 #endif /* ENABLE_REWRITE */
1262                         rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
1263                         if ( rc != LDAP_SUCCESS ) {
1264                                 goto cleanup_attr;
1265                         }
1266                 }
1267
1268
1269 next_attr:;
1270                 ap = &(*ap)->a_next;
1271                 continue;
1272
1273 cleanup_attr:;
1274                 a = *ap;
1275                 *ap = (*ap)->a_next;
1276
1277                 attr_free( a );
1278         }
1279
1280         return 0;
1281 }
1282
1283 static int
1284 rwm_send_entry( Operation *op, SlapReply *rs )
1285 {
1286         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1287         struct ldaprwmap        *rwmap = 
1288                         (struct ldaprwmap *)on->on_bi.bi_private;
1289
1290         Entry                   *e = NULL;
1291         slap_mask_t             flags;
1292         struct berval           dn = BER_BVNULL,
1293                                 ndn = BER_BVNULL;
1294         dncookie                dc;
1295         int                     rc;
1296
1297         assert( rs->sr_entry != NULL );
1298
1299         /*
1300          * Rewrite the dn of the result, if needed
1301          */
1302         dc.rwmap = rwmap;
1303 #ifdef ENABLE_REWRITE
1304         dc.conn = op->o_conn;
1305         dc.rs = NULL; 
1306         dc.ctx = "searchEntryDN";
1307 #else /* ! ENABLE_REWRITE */
1308         dc.tofrom = 0;
1309         dc.normalized = 0;
1310 #endif /* ! ENABLE_REWRITE */
1311
1312         e = rs->sr_entry;
1313         flags = rs->sr_flags;
1314         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
1315                 /* FIXME: all we need to duplicate are:
1316                  * - dn
1317                  * - ndn
1318                  * - attributes that are requested
1319                  * - no values if attrsonly is set
1320                  */
1321
1322                 e = entry_dup( e );
1323                 if ( e == NULL ) {
1324                         rc = LDAP_NO_MEMORY;
1325                         goto fail;
1326                 }
1327
1328                 flags &= ~REP_ENTRY_MUSTRELEASE;
1329                 flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
1330         }
1331
1332         /*
1333          * Note: this may fail if the target host(s) schema differs
1334          * from the one known to the meta, and a DN with unknown
1335          * attributes is returned.
1336          */
1337         dn = e->e_name;
1338         ndn = e->e_nname;
1339         rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
1340         if ( rc != LDAP_SUCCESS ) {
1341                 rc = 1;
1342                 goto fail;
1343         }
1344
1345         if ( e->e_name.bv_val != dn.bv_val ) {
1346                 ch_free( e->e_name.bv_val );
1347                 ch_free( e->e_nname.bv_val );
1348
1349                 e->e_name = dn;
1350                 e->e_nname = ndn;
1351         }
1352
1353         /* TODO: map entry attribute types, objectclasses 
1354          * and dn-valued attribute values */
1355
1356         /* FIXME: the entries are in the remote mapping form;
1357          * so we need to select those attributes we are willing
1358          * to return, and remap them accordingly */
1359         (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
1360
1361         if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1362                 be_entry_release_rw( op, rs->sr_entry, 0 );
1363         }
1364
1365         rs->sr_entry = e;
1366         rs->sr_flags = flags;
1367
1368         return SLAP_CB_CONTINUE;
1369
1370 fail:;
1371         if ( e != NULL && e != rs->sr_entry ) {
1372                 if ( e->e_name.bv_val == dn.bv_val ) {
1373                         BER_BVZERO( &e->e_name );
1374                 }
1375
1376                 if ( e->e_nname.bv_val == ndn.bv_val ) {
1377                         BER_BVZERO( &e->e_nname );
1378                 }
1379
1380                 entry_free( e );
1381         }
1382
1383         if ( !BER_BVISNULL( &dn ) ) {
1384                 ch_free( dn.bv_val );
1385         }
1386
1387         if ( !BER_BVISNULL( &ndn ) ) {
1388                 ch_free( ndn.bv_val );
1389         }
1390
1391         return rc;
1392 }
1393
1394 static int
1395 rwm_operational( Operation *op, SlapReply *rs )
1396 {
1397         /* FIXME: the entries are in the remote mapping form;
1398          * so we need to select those attributes we are willing
1399          * to return, and remap them accordingly */
1400         if ( rs->sr_operational_attrs ) {
1401                 rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
1402         }
1403
1404         return SLAP_CB_CONTINUE;
1405 }
1406
1407 #if 0
1408 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1409  * rewritten for subsequent operations; fine for plain suffixmassage,
1410  * but destroys everything else */
1411 static int
1412 rwm_chk_referrals( Operation *op, SlapReply *rs )
1413 {
1414         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1415         int                     rc;
1416
1417 #ifdef ENABLE_REWRITE
1418         rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1419 #else /* ! ENABLE_REWRITE */
1420         rc = 1;
1421         rc = rwm_op_dn_massage( op, rs, &rc );
1422 #endif /* ! ENABLE_REWRITE */
1423         if ( rc != LDAP_SUCCESS ) {
1424                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1425                 send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1426                 return -1;
1427         }
1428
1429         return SLAP_CB_CONTINUE;
1430 }
1431 #endif
1432
1433 static int
1434 rwm_rw_config(
1435         BackendDB       *be,
1436         const char      *fname,
1437         int             lineno,
1438         int             argc,
1439         char            **argv )
1440 {
1441 #ifdef ENABLE_REWRITE
1442         slap_overinst           *on = (slap_overinst *) be->bd_info;
1443         struct ldaprwmap        *rwmap = 
1444                         (struct ldaprwmap *)on->on_bi.bi_private;
1445
1446         return rewrite_parse( rwmap->rwm_rw,
1447                                 fname, lineno, argc, argv );
1448
1449 #else /* !ENABLE_REWRITE */
1450         fprintf( stderr, "%s: line %d: rewrite capabilities "
1451                         "are not enabled\n", fname, lineno );
1452 #endif /* !ENABLE_REWRITE */
1453                 
1454         return 0;
1455 }
1456
1457 static int
1458 rwm_suffixmassage_config(
1459         BackendDB       *be,
1460         const char      *fname,
1461         int             lineno,
1462         int             argc,
1463         char            **argv )
1464 {
1465         slap_overinst           *on = (slap_overinst *) be->bd_info;
1466         struct ldaprwmap        *rwmap = 
1467                         (struct ldaprwmap *)on->on_bi.bi_private;
1468
1469         struct berval           bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1470         int                     massaged;
1471 #ifdef ENABLE_REWRITE
1472         int                     rc;
1473 #endif /* ENABLE_REWRITE */
1474                 
1475         /*
1476          * syntax:
1477          * 
1478          *      suffixmassage [<suffix>] <massaged suffix>
1479          *
1480          * the [<suffix>] field must be defined as a valid suffix
1481          * for the current database;
1482          * the <massaged suffix> shouldn't have already been
1483          * defined as a valid suffix for the current server
1484          */
1485         if ( argc == 2 ) {
1486                 if ( be->be_suffix == NULL ) {
1487                         fprintf( stderr, "%s: line %d: "
1488                                        " \"suffixMassage [<suffix>]"
1489                                        " <massaged suffix>\" without "
1490                                        "<suffix> part requires database "
1491                                        "suffix be defined first.\n",
1492                                 fname, lineno );
1493                         return 1;
1494                 }
1495                 bvnc = be->be_suffix[ 0 ];
1496                 massaged = 1;
1497
1498         } else if ( argc == 3 ) {
1499                 ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1500                 massaged = 2;
1501
1502         } else  {
1503                 fprintf( stderr, "%s: line %d: syntax is"
1504                                " \"suffixMassage [<suffix>]"
1505                                " <massaged suffix>\"\n",
1506                         fname, lineno );
1507                 return 1;
1508         }
1509
1510         if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1511                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1512                         fname, lineno, bvnc.bv_val );
1513                 return 1;
1514         }
1515
1516         ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1517         if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1518                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1519                                 fname, lineno, brnc.bv_val );
1520                 free( nvnc.bv_val );
1521                 free( pvnc.bv_val );
1522                 return 1;
1523         }
1524
1525 #ifdef ENABLE_REWRITE
1526         /*
1527          * The suffix massaging is emulated 
1528          * by means of the rewrite capabilities
1529          */
1530         rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1531                         &pvnc, &nvnc, &prnc, &nrnc );
1532         free( nvnc.bv_val );
1533         free( pvnc.bv_val );
1534         free( nrnc.bv_val );
1535         free( prnc.bv_val );
1536
1537         return( rc );
1538
1539 #else /* !ENABLE_REWRITE */
1540         ber_bvarray_add( &rwmap->rwm_suffix_massage, &pvnc );
1541         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nvnc );
1542                 
1543         ber_bvarray_add( &rwmap->rwm_suffix_massage, &prnc );
1544         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nrnc );
1545 #endif /* !ENABLE_REWRITE */
1546
1547         return 0;
1548 }
1549
1550 static int
1551 rwm_m_config(
1552         BackendDB       *be,
1553         const char      *fname,
1554         int             lineno,
1555         int             argc,
1556         char            **argv )
1557 {
1558         slap_overinst           *on = (slap_overinst *) be->bd_info;
1559         struct ldaprwmap        *rwmap = 
1560                         (struct ldaprwmap *)on->on_bi.bi_private;
1561
1562         /* objectclass/attribute mapping */
1563         return rwm_map_config( &rwmap->rwm_oc,
1564                         &rwmap->rwm_at,
1565                         fname, lineno, argc, argv );
1566 }
1567
1568 static int
1569 rwm_response( Operation *op, SlapReply *rs )
1570 {
1571         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
1572         struct ldaprwmap        *rwmap = 
1573                         (struct ldaprwmap *)on->on_bi.bi_private;
1574
1575         int             rc;
1576
1577         if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1578                 return rwm_send_entry( op, rs );
1579         }
1580
1581         switch( op->o_tag ) {
1582         case LDAP_REQ_SEARCH:
1583         case LDAP_REQ_BIND:
1584         case LDAP_REQ_ADD:
1585         case LDAP_REQ_DELETE:
1586         case LDAP_REQ_MODRDN:
1587         case LDAP_REQ_MODIFY:
1588         case LDAP_REQ_COMPARE:
1589         case LDAP_REQ_EXTENDED:
1590                 if ( rs->sr_ref ) {
1591                         dncookie                dc;
1592
1593                         /*
1594                          * Rewrite the dn of the referrals, if needed
1595                          */
1596                         dc.rwmap = rwmap;
1597 #ifdef ENABLE_REWRITE
1598                         dc.conn = op->o_conn;
1599                         dc.rs = NULL; 
1600                         dc.ctx = "referralDN";
1601 #else /* ! ENABLE_REWRITE */
1602                         dc.tofrom = 0;
1603                         dc.normalized = 0;
1604 #endif /* ! ENABLE_REWRITE */
1605                         rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1606                         if ( rc != LDAP_SUCCESS ) {
1607                                 rc = 1;
1608                                 break;
1609                         }
1610                 }
1611                 rc = rwm_matched( op, rs );
1612                 break;
1613
1614         default:
1615                 rc = SLAP_CB_CONTINUE;
1616                 break;
1617         }
1618
1619         return rc;
1620 }
1621
1622 static int
1623 rwm_db_config(
1624         BackendDB       *be,
1625         const char      *fname,
1626         int             lineno,
1627         int             argc,
1628         char            **argv )
1629 {
1630         slap_overinst           *on = (slap_overinst *) be->bd_info;
1631         struct ldaprwmap        *rwmap = 
1632                         (struct ldaprwmap *)on->on_bi.bi_private;
1633
1634         int             rc = 0;
1635         char            *argv0 = NULL;
1636
1637         if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1638                 argv0 = argv[ 0 ];
1639                 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1640         }
1641
1642         if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1643                 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1644
1645         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1646                 rc = rwm_m_config( be, fname, lineno, argc, argv );
1647
1648         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1649                 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1650
1651         } else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
1652                 if ( argc != 2 ) {
1653                         fprintf( stderr,
1654                 "%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
1655                                         fname, lineno );
1656                         return( 1 );
1657                 }
1658
1659                 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1660                         rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F|RWM_F_SUPPORT_T_F_DISCOVER);
1661
1662                 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1663                         rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
1664
1665                 /* TODO: not implemented yet */
1666                 } else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1667                         fprintf( stderr,
1668                 "%s: line %d: \"discover\" not supported yet "
1669                 "in \"t-f-support {no|yes|discover}\".\n",
1670                                         fname, lineno );
1671                         return( 1 );
1672 #if 0
1673                         rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
1674 #endif
1675
1676                 } else {
1677                         fprintf( stderr,
1678         "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1679                                 fname, lineno, argv[ 1 ] );
1680                         return 1;
1681                 }
1682         } else if ( strcasecmp( argv[0], "normalize-mapped-attrs" ) ==  0 ) {
1683                 if ( argc !=2 ) { 
1684                         fprintf( stderr,
1685                 "%s: line %d: \"normalize-mapped-attrs {no|yes}\" needs 1 argument.\n",
1686                                         fname, lineno );
1687                         return( 1 );
1688                 }
1689
1690                 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1691                         rwmap->rwm_flags &= ~(RWM_F_NORMALIZE_MAPPED_ATTRS);
1692                 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1693                         rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS ;
1694                 }
1695
1696         } else {
1697                 rc = SLAP_CONF_UNKNOWN;
1698         }
1699
1700         if ( argv0 ) {
1701                 argv[ 0 ] = argv0;
1702         }
1703
1704         return rc;
1705 }
1706
1707 static int
1708 rwm_db_init(
1709         BackendDB       *be )
1710 {
1711         slap_overinst           *on = (slap_overinst *) be->bd_info;
1712         struct ldaprwmap        *rwmap;
1713 #ifdef ENABLE_REWRITE
1714         char                    *rargv[ 3 ];
1715 #endif /* ENABLE_REWRITE */
1716         int                     rc = 0;
1717
1718         rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
1719
1720 #ifdef ENABLE_REWRITE
1721         rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
1722         if ( rwmap->rwm_rw == NULL ) {
1723                 rc = -1;
1724                 goto error_return;
1725         }
1726
1727         /* this rewriteContext by default must be null;
1728          * rules can be added if required */
1729         rargv[ 0 ] = "rewriteContext";
1730         rargv[ 1 ] = "searchFilter";
1731         rargv[ 2 ] = NULL;
1732         rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
1733
1734         rargv[ 0 ] = "rewriteContext";
1735         rargv[ 1 ] = "default";
1736         rargv[ 2 ] = NULL;
1737         rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
1738 #endif /* ENABLE_REWRITE */
1739
1740 error_return:;
1741         on->on_bi.bi_private = (void *)rwmap;
1742
1743         if ( rc ) {
1744                 (void)rwm_db_destroy( be );
1745         }
1746
1747         return rc;
1748 }
1749
1750 static int
1751 rwm_db_destroy(
1752         BackendDB       *be )
1753 {
1754         slap_overinst   *on = (slap_overinst *) be->bd_info;
1755         int             rc = 0;
1756
1757         if ( on->on_bi.bi_private ) {
1758                 struct ldaprwmap        *rwmap = 
1759                         (struct ldaprwmap *)on->on_bi.bi_private;
1760
1761 #ifdef ENABLE_REWRITE
1762                 if ( rwmap->rwm_rw ) {
1763                         rewrite_info_delete( &rwmap->rwm_rw );
1764                 }
1765 #else /* !ENABLE_REWRITE */
1766                 if ( rwmap->rwm_suffix_massage ) {
1767                         ber_bvarray_free( rwmap->rwm_suffix_massage );
1768                 }
1769 #endif /* !ENABLE_REWRITE */
1770
1771                 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
1772                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
1773                 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
1774                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
1775
1776                 ch_free( rwmap );
1777         }
1778
1779         return rc;
1780 }
1781
1782 static slap_overinst rwm = { { NULL } };
1783
1784 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1785 static
1786 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1787 int
1788 rwm_initialize( void )
1789 {
1790         memset( &rwm, 0, sizeof( slap_overinst ) );
1791
1792         rwm.on_bi.bi_type = "rwm";
1793         rwm.on_bi.bi_flags =
1794                 SLAPO_BFLAG_SINGLE |
1795                 0;
1796
1797         rwm.on_bi.bi_db_init = rwm_db_init;
1798         rwm.on_bi.bi_db_config = rwm_db_config;
1799         rwm.on_bi.bi_db_destroy = rwm_db_destroy;
1800
1801         rwm.on_bi.bi_op_bind = rwm_op_bind;
1802         rwm.on_bi.bi_op_search = rwm_op_search;
1803         rwm.on_bi.bi_op_compare = rwm_op_compare;
1804         rwm.on_bi.bi_op_modify = rwm_op_modify;
1805         rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
1806         rwm.on_bi.bi_op_add = rwm_op_add;
1807         rwm.on_bi.bi_op_delete = rwm_op_delete;
1808         rwm.on_bi.bi_op_unbind = rwm_op_unbind;
1809         rwm.on_bi.bi_extended = rwm_extended;
1810
1811         rwm.on_bi.bi_operational = rwm_operational;
1812         rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
1813
1814 #ifdef ENABLE_REWRITE
1815         rwm.on_bi.bi_connection_init = rwm_conn_init;
1816         rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
1817 #endif /* ENABLE_REWRITE */
1818
1819         rwm.on_response = rwm_response;
1820
1821         return overlay_register( &rwm );
1822 }
1823
1824 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1825 int
1826 init_module( int argc, char *argv[] )
1827 {
1828         return rwm_initialize();
1829 }
1830 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1831
1832 #endif /* SLAPD_OVER_RWM */