]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/rwm.c
959cc4882fdfeb6d2f9071273e461baba3dc436f
[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-2004 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 "slap.h"
25 #include "rwm.h"
26
27 static int
28 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie )
29 {
30         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
31         struct ldaprwmap        *rwmap = 
32                         (struct ldaprwmap *)on->on_bi.bi_private;
33
34         struct berval           dn = BER_BVNULL,
35                                 ndn = BER_BVNULL;
36         int                     rc = 0;
37         dncookie                dc;
38
39         /*
40          * Rewrite the bind dn if needed
41          */
42         dc.rwmap = rwmap;
43 #ifdef ENABLE_REWRITE
44         dc.conn = op->o_conn;
45         dc.rs = rs;
46         dc.ctx = (char *)cookie;
47 #else
48         dc.tofrom = ((int *)cookie)[0];
49         dc.normalized = 0;
50 #endif
51
52         rc = rwm_dn_massage( &dc, &op->o_req_dn, &dn, &ndn );
53         if ( rc != LDAP_SUCCESS ) {
54                 return rc;
55         }
56
57         if ( dn.bv_val == op->o_req_dn.bv_val ) {
58                 return LDAP_SUCCESS;
59         }
60
61         op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
62         op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
63
64         op->o_req_dn = dn;
65         op->o_req_ndn = ndn;
66
67         return LDAP_SUCCESS;
68 }
69
70 static int
71 rwm_add( Operation *op, SlapReply *rs )
72 {
73         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
74         struct ldaprwmap        *rwmap = 
75                         (struct ldaprwmap *)on->on_bi.bi_private;
76
77         int                     rc,
78                                 i,
79                                 isupdate;
80         Attribute               **ap = NULL;
81
82 #ifdef ENABLE_REWRITE
83         rc = rwm_op_dn_massage( op, rs, "addDn" );
84 #else
85         rc = 1;
86         rc = rwm_op_dn_massage( op, rs, &rc );
87 #endif
88         if ( rc != LDAP_SUCCESS ) {
89                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
90                 send_ldap_error( op, rs, rc, "addDn massage error" );
91                 return -1;
92         }
93
94         /* Count number of attributes in entry */ 
95         isupdate = be_shadow_update( op );
96         for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
97                 struct berval   mapped;
98                 Attribute       *a;
99
100                 if ( !isupdate && (*ap)->a_desc->ad_type->sat_no_user_mod ) {
101                         goto cleanup_attr;
102                 }
103
104                 rwm_map( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
105                                 &mapped, RWM_MAP );
106                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
107                         goto cleanup_attr;
108                 }
109
110                 if ( (*ap)->a_desc->ad_type->sat_syntax
111                                 == slap_schema.si_syn_distinguishedName )
112                 {
113                         /*
114                          * FIXME: rewrite could fail; in this case
115                          * the operation should give up, right?
116                          */
117 #ifdef ENABLE_REWRITE
118                         rc = rwm_dnattr_rewrite( op, rs, "addDn", (*ap)->a_vals, NULL );
119 #else
120                         rc = 1;
121                         rc = rwm_dnattr_rewrite( op, rs, &rc, (*ap)->a_vals, NULL );
122 #endif
123                         if ( rc ) {
124                                 goto cleanup_attr;
125                         }
126                 }
127
128                 ap = &(*ap)->a_next;
129                 continue;
130
131 cleanup_attr:;
132                 /* FIXME: leaking attribute/values? */
133                 a = *ap;
134
135                 *ap = (*ap)->a_next;
136                 attr_free( a );
137         }
138
139         /* TODO: map attribute types, values of DN-valued attributes ... */
140         return SLAP_CB_CONTINUE;
141 }
142
143 static int
144 rwm_bind( Operation *op, SlapReply *rs )
145 {
146         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
147         struct ldaprwmap        *rwmap = 
148                         (struct ldaprwmap *)on->on_bi.bi_private;
149         int                     rc;
150
151 #ifdef ENABLE_REWRITE
152         ( void )rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
153         ( void )rewrite_session_init( rwmap->rwm_rw, op->o_conn );
154
155         rc = rwm_op_dn_massage( op, rs, "bindDn" );
156 #else
157         rc = 1;
158         rc = rwm_op_dn_massage( op, rs, &rc );
159 #endif
160         if ( rc != LDAP_SUCCESS ) {
161                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
162                 send_ldap_error( op, rs, rc, "bindDn massage error" );
163                 return -1;
164         }
165
166         return SLAP_CB_CONTINUE;
167 }
168
169 static int
170 rwm_unbind( Operation *op, SlapReply *rs )
171 {
172         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
173         struct ldaprwmap        *rwmap = 
174                         (struct ldaprwmap *)on->on_bi.bi_private;
175
176 #ifdef ENABLE_REWRITE
177         rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
178 #endif
179
180         return SLAP_CB_CONTINUE;
181 }
182
183 static int
184 rwm_compare( 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         struct berval           mapped_at = BER_BVNULL,
192                                 mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
193
194 #ifdef ENABLE_REWRITE
195         rc = rwm_op_dn_massage( op, rs, "compareDn" );
196 #else
197         rc = 1;
198         rc = rwm_op_dn_massage( op, rs, &rc );
199 #endif
200         if ( rc != LDAP_SUCCESS ) {
201                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
202                 send_ldap_error( op, rs, rc, "compareDn massage error" );
203                 return -1;
204         }
205
206         /* if the attribute is an objectClass, try to remap its value */
207         if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
208                         || op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
209         {
210                 rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
211                                 &mapped_vals[0], RWM_MAP );
212                 if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
213                 {
214                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
215                         send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
216                         return -1;
217
218                 } else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
219                         free( op->orc_ava->aa_value.bv_val );
220                         op->orc_ava->aa_value = mapped_vals[0];
221                 }
222                 mapped_at = op->orc_ava->aa_desc->ad_cname;
223
224         } else {
225                 rwm_map( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
226                                 &mapped_at, RWM_MAP );
227                 if ( BER_BVISNULL( &mapped_at ) || BER_BVISEMPTY( &mapped_at ) )
228                 {
229                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
230                         send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
231                         return -1;
232                 }
233                 if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
234                 {
235                         mapped_vals[0] = op->orc_ava->aa_value;
236
237 #ifdef ENABLE_REWRITE
238                         rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", mapped_vals, NULL );
239 #else
240                         rc = 1;
241                         rc = rwm_dnattr_rewrite( op, rs, &rc, mapped_vals, NULL );
242 #endif
243
244                         if ( rc != LDAP_SUCCESS ) {
245                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
246                                 send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
247                                 return -1;
248                         }
249
250                         if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
251                                 free( op->orc_ava->aa_value.bv_val );
252                                 op->orc_ava->aa_value = mapped_vals[0];
253                         }
254                 }
255         }
256
257         return SLAP_CB_CONTINUE;
258 }
259
260 static int
261 rwm_delete( Operation *op, SlapReply *rs )
262 {
263         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
264         int                     rc;
265
266 #ifdef ENABLE_REWRITE
267         rc = rwm_op_dn_massage( op, rs, "deleteDn" );
268 #else
269         rc = 1;
270         rc = rwm_op_dn_massage( op, rs, &rc );
271 #endif
272         if ( rc != LDAP_SUCCESS ) {
273                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
274                 send_ldap_error( op, rs, rc, "deleteDn massage error" );
275                 return rc;
276         }
277
278         return SLAP_CB_CONTINUE;
279 }
280
281 static int
282 rwm_modify( Operation *op, SlapReply *rs )
283 {
284         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
285         struct ldaprwmap        *rwmap = 
286                         (struct ldaprwmap *)on->on_bi.bi_private;
287
288         int                     isupdate;
289         Modifications           **mlp;
290         int                     rc;
291
292 #ifdef ENABLE_REWRITE
293         rc = rwm_op_dn_massage( op, rs, "modifyDn" );
294 #else
295         rc = 1;
296         rc = rwm_op_dn_massage( op, rs, &rc );
297 #endif
298         if ( rc != LDAP_SUCCESS ) {
299                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
300                 send_ldap_error( op, rs, rc, "modifyDn massage error" );
301                 return rc;
302         }
303
304         isupdate = be_shadow_update( op );
305         for ( mlp = &op->oq_modify.rs_modlist; *mlp; ) {
306                 int             is_oc = 0;
307
308                 if ( !isupdate && (*mlp)->sml_desc->ad_type->sat_no_user_mod  ) {
309                         Modifications   *ml;
310
311                         ml = *mlp;
312                         *mlp = (*mlp)->sml_next;
313                         slap_mod_free( &ml->sml_mod, 0 );
314                         free( ml );
315
316                         continue;
317                 }
318
319                 if ( (*mlp)->sml_desc == slap_schema.si_ad_objectClass 
320                                 || (*mlp)->sml_desc == slap_schema.si_ad_structuralObjectClass ) {
321                         is_oc = 1;
322
323                 } else {
324                         struct ldapmapping      *m;
325                         int                     drop_missing;
326
327                         drop_missing = rwm_mapping( &rwmap->rwm_at, &(*mlp)->sml_desc->ad_cname, &m, RWM_MAP );
328                         if ( drop_missing || ( m != NULL && BER_BVISNULL( &m->m_dst ) ) )
329                         {
330                                 Modifications   *ml;
331
332                                 ml = *mlp;
333                                 *mlp = (*mlp)->sml_next;
334                                 slap_mod_free( &ml->sml_mod, 0 );
335                                 free( ml );
336
337                                 continue;
338                         }
339
340                         if ( m ) {
341                                 /* use new attribute description */
342                                 assert( m->m_dst_ad );
343                                 (*mlp)->sml_desc = m->m_dst_ad;
344                         }
345                 }
346
347                 if ( (*mlp)->sml_values != NULL ) {
348                         if ( is_oc ) {
349                                 int     last, j;
350
351                                 for ( last = 0; !BER_BVISNULL( &(*mlp)->sml_values[last] ); last++ )
352                                         /* count values */ ;
353                                 last--;
354
355                                 for ( j = 0; !BER_BVISNULL( &(*mlp)->sml_values[j] ); j++ ) {
356                                         struct berval   mapped = BER_BVNULL;
357
358                                         rwm_map( &rwmap->rwm_oc,
359                                                         &(*mlp)->sml_values[j],
360                                                         &mapped, RWM_MAP );
361                                         if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
362                                                 /* FIXME: we allow to remove objectClasses as well;
363                                                  * if the resulting entry is inconsistent, that's
364                                                  * the relayed database's business...
365                                                  */
366 #if 0
367                                                 Modifications   *ml;
368
369                                                 ml = *mlp;
370                                                 *mlp = (*mlp)->sml_next;
371                                                 slap_mod_free( &ml->sml_mod, 0 );
372                                                 free( ml );
373
374                                                 continue;
375 #endif
376                                                 if ( last > j ) {
377                                                         (*mlp)->sml_values[j] = (*mlp)->sml_values[last];
378                                                         BER_BVZERO( &(*mlp)->sml_values[last] );
379                                                 }
380                                                 last--;
381
382                                         } else {
383                                                 ch_free( (*mlp)->sml_values[j].bv_val );
384                                                 ber_dupbv( &(*mlp)->sml_values[j], &mapped );
385                                         }
386                                 }
387
388                         } else {
389                                 if ( (*mlp)->sml_desc->ad_type->sat_syntax ==
390                                                 slap_schema.si_syn_distinguishedName )
391                                 {
392 #ifdef ENABLE_REWRITE
393                                         rc = rwm_dnattr_rewrite( op, rs, "modifyDn",
394                                                         (*mlp)->sml_values, &(*mlp)->sml_nvalues );
395 #else
396                                         rc = 1;
397                                         rc = rwm_dnattr_rewrite( op, rs, &rc, 
398                                                         (*mlp)->sml_values, &(*mlp)->sml_nvalues );
399 #endif
400                                 }
401
402                                 if ( rc != LDAP_SUCCESS ) {
403                                         Modifications   *ml;
404
405                                         ml = *mlp;
406                                         *mlp = (*mlp)->sml_next;
407                                         slap_mod_free( &ml->sml_mod, 0 );
408                                         free( ml );
409
410                                         continue;
411                                 }
412                         }
413                 }
414
415                 mlp = &(*mlp)->sml_next;
416         }
417
418         /* TODO: rewrite attribute types, values of DN-valued attributes ... */
419         return SLAP_CB_CONTINUE;
420 }
421
422 static int
423 rwm_modrdn( Operation *op, SlapReply *rs )
424 {
425         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
426         int                     rc;
427
428 #ifdef ENABLE_REWRITE
429         rc = rwm_op_dn_massage( op, rs, "renameDn" );
430 #else
431         rc = 1;
432         rc = rwm_op_dn_massage( op, rs, &rc );
433 #endif
434         if ( rc != LDAP_SUCCESS ) {
435                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
436                 send_ldap_error( op, rs, rc, "renameDn massage error" );
437                 return rc;
438         }
439
440         /* TODO: rewrite attribute types, values of DN-valued attributes ... */
441         return SLAP_CB_CONTINUE;
442 }
443
444 static int
445 rwm_swap_attrs( Operation *op, SlapReply *rs )
446 {
447         slap_callback   *cb = op->o_callback;
448         AttributeName   *an = (AttributeName *)cb->sc_private;
449
450         rs->sr_attrs = an;
451         
452         return SLAP_CB_CONTINUE;
453 }
454
455 static int
456 rwm_search( Operation *op, SlapReply *rs )
457 {
458         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
459         struct ldaprwmap        *rwmap = 
460                         (struct ldaprwmap *)on->on_bi.bi_private;
461
462         int                     rc;
463         dncookie                dc;
464
465         struct berval           fstr = BER_BVNULL;
466         Filter                  *f = NULL;
467
468         slap_callback           *cb;
469         AttributeName           *an = NULL;
470
471         char                    *text = NULL;
472
473 #ifdef ENABLE_REWRITE
474         rc = rwm_op_dn_massage( op, rs, "searchDn" );
475 #else
476         rc = 1;
477         rc = rwm_op_dn_massage( op, rs, &rc );
478 #endif
479         if ( rc != LDAP_SUCCESS ) {
480                 text = "searchDn massage error";
481                 goto error_return;
482         }
483
484         /*
485          * Rewrite the bind dn if needed
486          */
487         dc.rwmap = rwmap;
488 #ifdef ENABLE_REWRITE
489         dc.conn = op->o_conn;
490         dc.rs = rs;
491         dc.ctx = "searchFilterAttrDN";
492 #else
493         dc.tofrom = 0;
494         dc.normalized = 0;
495 #endif
496
497         rc = rwm_filter_map_rewrite( &dc, op->ors_filter, &fstr );
498         if ( rc != LDAP_SUCCESS ) {
499                 text = "searchFilter/searchFilterAttrDN massage error";
500                 goto error_return;
501         }
502
503         f = str2filter_x( op, fstr.bv_val );
504
505         if ( f == NULL ) {
506                 text = "massaged filter parse error";
507                 goto error_return;
508         }
509
510         if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
511                 ch_free( op->ors_filterstr.bv_val );
512         }
513
514         if( op->ors_filter ) {
515                 filter_free_x( op, op->ors_filter );
516         }
517
518         op->ors_filter = f;
519         op->ors_filterstr = fstr;
520
521         rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
522                         op->ors_attrs, &an, RWM_MAP );
523         if ( rc != LDAP_SUCCESS ) {
524                 text = "attribute list mapping error";
525                 goto error_return;
526         }
527
528         cb = (slap_callback *)ch_malloc( sizeof( slap_callback ) );
529         if ( cb == NULL ) {
530                 rc = LDAP_NO_MEMORY;
531                 goto error_return;
532         }
533
534         cb->sc_response = rwm_swap_attrs;
535         cb->sc_cleanup = NULL;
536         cb->sc_private = (void *)op->ors_attrs;
537         cb->sc_next = op->o_callback;
538
539         op->o_callback = cb;
540         op->ors_attrs = an;
541
542         /* TODO: rewrite/map filter & attrs */
543         return SLAP_CB_CONTINUE;
544
545 error_return:;
546         if ( an != NULL ) {
547                 ch_free( an );
548         }
549
550         if ( f != NULL ) {
551                 filter_free_x( op, f );
552         }
553
554         if ( !BER_BVISNULL( &fstr ) ) {
555                 ch_free( fstr.bv_val );
556         }
557
558         op->o_bd->bd_info = (BackendInfo *)on->on_info;
559         send_ldap_error( op, rs, rc, text );
560
561         return 1;
562
563 }
564
565 static int
566 rwm_extended( Operation *op, SlapReply *rs )
567 {
568         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
569         int                     rc;
570
571 #ifdef ENABLE_REWRITE
572         rc = rwm_op_dn_massage( op, rs, "extendedDn" );
573 #else
574         rc = 1;
575         rc = rwm_op_dn_massage( op, rs, &rc );
576 #endif
577         if ( rc != LDAP_SUCCESS ) {
578                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
579                 send_ldap_error( op, rs, rc, "extendedDn massage error" );
580                 return rc;
581         }
582
583         /* TODO: rewrite/map extended data ? ... */
584         return 0;
585 }
586
587 static int
588 rwm_matched( Operation *op, SlapReply *rs )
589 {
590         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
591         struct ldaprwmap        *rwmap = 
592                         (struct ldaprwmap *)on->on_bi.bi_private;
593
594         struct berval           dn, mdn;
595         dncookie                dc;
596         int                     rc;
597
598         if ( rs->sr_matched == NULL ) {
599                 return SLAP_CB_CONTINUE;
600         }
601
602         dc.rwmap = rwmap;
603 #ifdef ENABLE_REWRITE
604         dc.conn = op->o_conn;
605         dc.rs = rs;
606         dc.ctx = "matchedDN";
607 #else
608         dc.tofrom = 0;
609         dc.normalized = 0;
610 #endif
611         ber_str2bv( rs->sr_matched, 0, 0, &dn );
612         rc = rwm_dn_massage( &dc, &dn, &mdn, NULL );
613         if ( rc != LDAP_SUCCESS ) {
614                 rs->sr_err = rc;
615                 rs->sr_text = "Rewrite error";
616                 return 1;
617         }
618
619         if ( mdn.bv_val != dn.bv_val ) {
620                 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
621                         ch_free( (void *)rs->sr_matched );
622
623                 } else {
624                         rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
625                 }
626                 rs->sr_matched = mdn.bv_val;
627         }
628         
629         return SLAP_CB_CONTINUE;
630 }
631
632 static int
633 rwm_send_entry( Operation *op, SlapReply *rs )
634 {
635         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
636         struct ldaprwmap        *rwmap = 
637                         (struct ldaprwmap *)on->on_bi.bi_private;
638
639         Entry           *e = NULL;
640         struct berval   dn = BER_BVNULL,
641                         ndn = BER_BVNULL;
642         dncookie        dc;
643         int             rc;
644         Attribute       **ap;
645
646         assert( rs->sr_entry );
647
648         e = rs->sr_entry;
649
650         /*
651          * Rewrite the dn of the result, if needed
652          */
653         dc.rwmap = rwmap;
654 #ifdef ENABLE_REWRITE
655         dc.conn = op->o_conn;
656         dc.rs = NULL; 
657         dc.ctx = "searchResult";
658 #else
659         dc.tofrom = 0;
660         dc.normalized = 0;
661 #endif
662
663         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
664                 /* FIXME: all we need to duplicate are:
665                  * - dn
666                  * - ndn
667                  * - attributes that are requested
668                  * - no values if attrsonly is set
669                  */
670
671                 e = entry_dup( e );
672                 if ( e == NULL ) {
673                         rc = LDAP_NO_MEMORY;
674                         goto fail;
675                 }
676
677                 rs->sr_flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
678         }
679
680         /*
681          * Note: this may fail if the target host(s) schema differs
682          * from the one known to the meta, and a DN with unknown
683          * attributes is returned.
684          */
685         rc = rwm_dn_massage( &dc, &e->e_name, &dn, &ndn );
686         if ( rc != LDAP_SUCCESS ) {
687                 goto fail;
688         }
689
690         if ( e->e_name.bv_val != dn.bv_val ) {
691                 free( e->e_name.bv_val );
692                 free( e->e_nname.bv_val );
693
694                 e->e_name = dn;
695                 e->e_nname = ndn;
696         }
697
698         /* TODO: map entry attribute types, objectclasses 
699          * and dn-valued attribute values */
700
701         /* FIXME: the entries are in the remote mapping form;
702          * so we need to select those attributes we are willing
703          * to return, and remap them accordingly */
704
705         for ( ap = &e->e_attrs; *ap; ) {
706                 struct ldapmapping      *m;
707                 int                     drop_missing;
708                 int                     last;
709
710                 if ( op->ors_attrs != NULL && !ad_inlist( (*ap)->a_desc, op->ors_attrs ) ) {
711                         Attribute       *a;
712
713                         a = *ap;
714                         *ap = (*ap)->a_next;
715
716                         attr_free( a );
717                         continue;
718                 }
719
720                 drop_missing = rwm_mapping( &rwmap->rwm_at,
721                                 &(*ap)->a_desc->ad_cname, &m, RWM_REMAP );
722                 if ( drop_missing || ( m != NULL && BER_BVISEMPTY( &m->m_dst ) ) ) {
723                         Attribute       *a;
724
725                         a = *ap;
726                         *ap = (*ap)->a_next;
727
728                         attr_free( a );
729                         continue;
730                 }
731
732                 /* no subschemaSubentry */
733                 if ( (*ap)->a_desc == slap_schema.si_ad_subschemaSubentry ) {
734
735                         /* 
736                          * We eat target's subschemaSubentry because
737                          * a search for this value is likely not
738                          * to resolve to the appropriate backend;
739                          * later, the local subschemaSubentry is
740                          * added.
741                          */
742                         Attribute       *a;
743
744                         a = *ap;
745                         *ap = (*ap)->a_next;
746
747                         attr_free( a );
748                         continue;
749                 }
750                 
751                 for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ )
752                         /* just count */ ;
753
754                 if ( last == 0 ) {
755                         /* empty? for now, we leave it in place */
756                         goto next_attr;
757                 }
758                 last--;
759
760                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
761                                 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
762                 {
763                         struct berval   *bv;
764                         
765                         for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
766                                 struct berval   mapped;
767
768                                 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
769                                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
770                                         ch_free( bv[0].bv_val );
771                                         BER_BVZERO( &bv[0] );
772                                         if ( &(*ap)->a_vals[last] > &bv[0] ) {
773                                                 bv[0] = (*ap)->a_vals[last];
774                                                 BER_BVZERO( &(*ap)->a_vals[last] );
775                                         }
776                                         last--;
777                                         bv--;
778
779                                 } else if ( mapped.bv_val != bv[0].bv_val ) {
780                                         /*
781                                          * FIXME: after LBER_FREEing
782                                          * the value is replaced by
783                                          * ch_alloc'ed memory
784                                          */
785                                         free( bv[0].bv_val );
786                                         ber_dupbv( &bv[0], &mapped );
787                                 }
788                         }
789
790                 /*
791                  * It is necessary to try to rewrite attributes with
792                  * dn syntax because they might be used in ACLs as
793                  * members of groups; since ACLs are applied to the
794                  * rewritten stuff, no dn-based subject clause could
795                  * be used at the ldap backend side (see
796                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
797                  * The problem can be overcome by moving the dn-based
798                  * ACLs to the target directory server, and letting
799                  * everything pass thru the ldap backend.
800                  */
801                 } else if ( (*ap)->a_desc->ad_type->sat_syntax ==
802                                 slap_schema.si_syn_distinguishedName )
803                 {
804                         rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
805                         if ( rc != LDAP_SUCCESS ) {
806                                 Attribute       *a;
807
808                                 a = *ap;
809                                 *ap = (*ap)->a_next;
810
811                                 attr_free( a );
812                                 continue;
813                         }
814                 }
815
816                 if ( m != NULL ) {
817                         /* rewrite the attribute description */
818                         assert( m->m_dst_ad );
819                         (*ap)->a_desc = m->m_dst_ad;
820                 }
821
822 next_attr:;
823                 ap = &(*ap)->a_next;
824         }
825
826
827         rs->sr_entry = e;
828
829         return SLAP_CB_CONTINUE;
830
831 fail:;
832         if ( !BER_BVISNULL( &dn ) ) {
833                 ch_free( dn.bv_val );
834         }
835
836         if ( !BER_BVISNULL( &ndn ) ) {
837                 ch_free( ndn.bv_val );
838         }
839
840         if ( e != NULL && e != rs->sr_entry ) {
841                 entry_free( e );
842         }
843
844         return rc;
845 }
846
847 static int
848 rwm_rw_config(
849     BackendDB   *be,
850     const char  *fname,
851     int         lineno,
852     int         argc,
853     char        **argv
854 )
855 {
856 #ifdef ENABLE_REWRITE
857         slap_overinst           *on = (slap_overinst *) be->bd_info;
858         struct ldaprwmap        *rwmap = 
859                         (struct ldaprwmap *)on->on_bi.bi_private;
860
861         return rewrite_parse( rwmap->rwm_rw,
862                                 fname, lineno, argc, argv );
863
864 #else /* !ENABLE_REWRITE */
865         fprintf( stderr, "%s: line %d: rewrite capabilities "
866                         "are not enabled\n", fname, lineno );
867 #endif /* !ENABLE_REWRITE */
868                 
869         return 0;
870 }
871
872 static int
873 rwm_suffixmassage_config(
874     BackendDB   *be,
875     const char  *fname,
876     int         lineno,
877     int         argc,
878     char        **argv
879 )
880 {
881         slap_overinst           *on = (slap_overinst *) be->bd_info;
882         struct ldaprwmap        *rwmap = 
883                         (struct ldaprwmap *)on->on_bi.bi_private;
884
885         struct berval   bvnc, nvnc, pvnc, brnc, nrnc, prnc;
886 #ifdef ENABLE_REWRITE
887         int             rc;
888 #endif /* ENABLE_REWRITE */
889                 
890         /*
891          * syntax:
892          * 
893          *      suffixmassage <suffix> <massaged suffix>
894          *
895          * the <suffix> field must be defined as a valid suffix
896          * (or suffixAlias?) for the current database;
897          * the <massaged suffix> shouldn't have already been
898          * defined as a valid suffix or suffixAlias for the 
899          * current server
900          */
901         if ( argc != 3 ) {
902                 fprintf( stderr, "%s: line %d: syntax is"
903                                " \"suffixMassage <suffix>"
904                                " <massaged suffix>\"\n",
905                         fname, lineno );
906                 return 1;
907         }
908                 
909         ber_str2bv( argv[1], 0, 0, &bvnc );
910         if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
911                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
912                         fname, lineno, bvnc.bv_val );
913                 return 1;
914         }
915
916         ber_str2bv( argv[2], 0, 0, &brnc );
917         if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
918                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
919                                 fname, lineno, brnc.bv_val );
920                 free( nvnc.bv_val );
921                 free( pvnc.bv_val );
922                 return 1;
923         }
924
925 #ifdef ENABLE_REWRITE
926         /*
927          * The suffix massaging is emulated 
928          * by means of the rewrite capabilities
929          */
930         rc = rwm_suffix_massage_config( rwmap->rwm_rw,
931                         &pvnc, &nvnc, &prnc, &nrnc );
932         free( nvnc.bv_val );
933         free( pvnc.bv_val );
934         free( nrnc.bv_val );
935         free( prnc.bv_val );
936
937         return( rc );
938
939 #else /* !ENABLE_REWRITE */
940         ber_bvarray_add( &rwmap->rwm_suffix_massage, &pvnc );
941         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nvnc );
942                 
943         ber_bvarray_add( &rwmap->rwm_suffix_massage, &prnc );
944         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nrnc );
945 #endif /* !ENABLE_REWRITE */
946
947         return 0;
948 }
949
950 static int
951 rwm_m_config(
952     BackendDB   *be,
953     const char  *fname,
954     int         lineno,
955     int         argc,
956     char        **argv
957 )
958 {
959         slap_overinst           *on = (slap_overinst *) be->bd_info;
960         struct ldaprwmap        *rwmap = 
961                         (struct ldaprwmap *)on->on_bi.bi_private;
962
963         /* objectclass/attribute mapping */
964         return rwm_map_config( &rwmap->rwm_oc,
965                         &rwmap->rwm_at,
966                         fname, lineno, argc, argv );
967 }
968
969 static int
970 rwm_response( Operation *op, SlapReply *rs )
971 {
972         int             rc;
973
974         if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
975                 return rwm_send_entry( op, rs );
976         }
977
978         switch( op->o_tag ) {
979         case LDAP_REQ_SEARCH:
980                 /* Note: the operation attrs are remapped */
981                 if ( op->ors_attrs != NULL && op->ors_attrs != rs->sr_attrs )
982                 {
983                         ch_free( op->ors_attrs );
984                         op->ors_attrs = rs->sr_attrs;
985                 }
986                 /* fall thru */
987
988         case LDAP_REQ_BIND:
989         case LDAP_REQ_ADD:
990         case LDAP_REQ_DELETE:
991         case LDAP_REQ_MODRDN:
992         case LDAP_REQ_MODIFY:
993         case LDAP_REQ_COMPARE:
994         case LDAP_REQ_EXTENDED:
995                 rc = rwm_matched( op, rs );
996                 break;
997
998         default:
999                 rc = SLAP_CB_CONTINUE;
1000                 break;
1001         }
1002
1003         return rc;
1004 }
1005
1006 static int
1007 rwm_config(
1008     BackendDB   *be,
1009     const char  *fname,
1010     int         lineno,
1011     int         argc,
1012     char        **argv
1013 )
1014 {
1015         int             rc = 0;
1016         char            *argv0 = NULL;
1017
1018         if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1019                 argv0 = argv[ 0 ];
1020                 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1021         }
1022
1023         if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1024                 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1025
1026         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1027                 rc = rwm_m_config( be, fname, lineno, argc, argv );
1028
1029         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1030                 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1031
1032         } else {
1033                 rc = SLAP_CONF_UNKNOWN;
1034         }
1035
1036         if ( argv0 ) {
1037                 argv[ 0 ] = argv0;
1038         }
1039
1040         return rc;
1041 }
1042
1043 static int
1044 rwm_over_init(
1045         BackendDB *be
1046 )
1047 {
1048         slap_overinst           *on = (slap_overinst *) be->bd_info;
1049         struct ldapmapping      *mapping = NULL;
1050         struct ldaprwmap        *rwmap;
1051
1052         rwmap = (struct ldaprwmap *)ch_malloc(sizeof(struct ldaprwmap));
1053         memset(rwmap, 0, sizeof(struct ldaprwmap));
1054
1055 #ifdef ENABLE_REWRITE
1056         rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
1057         if ( rwmap->rwm_rw == NULL ) {
1058                 ch_free( rwmap );
1059                 return -1;
1060         }
1061
1062         {
1063                 char    *rargv[3];
1064
1065                 /* this rewriteContext by default must be null;
1066                  * rules can be added if required */
1067                 rargv[ 0 ] = "rewriteContext";
1068                 rargv[ 1 ] = "searchFilter";
1069                 rargv[ 2 ] = NULL;
1070                 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
1071
1072                 rargv[ 0 ] = "rewriteContext";
1073                 rargv[ 1 ] = "default";
1074                 rargv[ 2 ] = NULL;
1075                 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
1076         }
1077         
1078 #endif /* ENABLE_REWRITE */
1079
1080         if ( rwm_map_init( &rwmap->rwm_oc, &mapping ) != LDAP_SUCCESS ||
1081                         rwm_map_init( &rwmap->rwm_at, &mapping ) != LDAP_SUCCESS )
1082         {
1083                 return 1;
1084         }
1085
1086         on->on_bi.bi_private = (void *)rwmap;
1087
1088         return 0;
1089 }
1090
1091 static int
1092 rwm_destroy(
1093         BackendDB *be
1094 )
1095 {
1096         slap_overinst   *on = (slap_overinst *) be->bd_info;
1097         int             rc = 0;
1098
1099         if ( on->on_bi.bi_private ) {
1100                 struct ldaprwmap        *rwmap = 
1101                         (struct ldaprwmap *)on->on_bi.bi_private;
1102
1103 #ifdef ENABLE_REWRITE
1104                 if (rwmap->rwm_rw) {
1105                         rewrite_info_delete( &rwmap->rwm_rw );
1106                 }
1107 #else /* !ENABLE_REWRITE */
1108                 if ( rwmap->rwm_suffix_massage ) {
1109                         ber_bvarray_free( rwmap->rwm_suffix_massage );
1110                 }
1111 #endif /* !ENABLE_REWRITE */
1112
1113                 avl_free( rwmap->rwm_oc.remap, NULL );
1114                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
1115                 avl_free( rwmap->rwm_at.remap, NULL );
1116                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
1117         }
1118
1119         return rc;
1120 }
1121
1122 static slap_overinst rwm = { { NULL } };
1123
1124 int
1125 rwm_init(void)
1126 {
1127         memset( &rwm, 0, sizeof(slap_overinst) );
1128
1129         rwm.on_bi.bi_type = "rwm";
1130         rwm.on_bi.bi_db_init = rwm_over_init;
1131         rwm.on_bi.bi_db_config = rwm_config;
1132         rwm.on_bi.bi_db_destroy = rwm_destroy;
1133
1134         rwm.on_bi.bi_op_bind = rwm_bind;
1135         rwm.on_bi.bi_op_search = rwm_search;
1136         rwm.on_bi.bi_op_compare = rwm_compare;
1137         rwm.on_bi.bi_op_modify = rwm_modify;
1138         rwm.on_bi.bi_op_modrdn = rwm_modrdn;
1139         rwm.on_bi.bi_op_add = rwm_add;
1140         rwm.on_bi.bi_op_delete = rwm_delete;
1141         rwm.on_bi.bi_op_unbind = rwm_unbind;
1142         rwm.on_bi.bi_extended = rwm_extended;
1143
1144         rwm.on_response = rwm_response;
1145
1146         return overlay_register( &rwm );
1147 }
1148
1149 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1150 int init_module(int argc, char *argv[]) {
1151         return rwm_init();
1152 }
1153 #endif
1154
1155 #endif /* SLAPD_OVER_RWM */