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