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