]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/rwm.c
cleanup
[openldap] / servers / slapd / overlays / rwm.c
1 /* rwm.c - rewrite/remap operations */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-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 rwm_freeself( Operation *op, SlapReply *rs )
458 {
459         if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_RESULT ) {
460                 assert( op->o_callback );
461
462                 op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
463                 op->o_callback = NULL;
464         }
465
466         return SLAP_CB_CONTINUE;
467 }
468
469 static int
470 rwm_search( Operation *op, SlapReply *rs )
471 {
472         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
473         struct ldaprwmap        *rwmap = 
474                         (struct ldaprwmap *)on->on_bi.bi_private;
475
476         int                     rc;
477         dncookie                dc;
478
479         struct berval           fstr = BER_BVNULL;
480         Filter                  *f = NULL;
481
482         slap_callback           *cb;
483         AttributeName           *an = NULL;
484
485         char                    *text = NULL;
486
487 #ifdef ENABLE_REWRITE
488         rc = rwm_op_dn_massage( op, rs, "searchDn" );
489 #else
490         rc = 1;
491         rc = rwm_op_dn_massage( op, rs, &rc );
492 #endif
493         if ( rc != LDAP_SUCCESS ) {
494                 text = "searchDn massage error";
495                 goto error_return;
496         }
497
498         /*
499          * Rewrite the bind dn if needed
500          */
501         dc.rwmap = rwmap;
502 #ifdef ENABLE_REWRITE
503         dc.conn = op->o_conn;
504         dc.rs = rs;
505         dc.ctx = "searchFilterAttrDN";
506 #else
507         dc.tofrom = 0;
508         dc.normalized = 0;
509 #endif
510
511         rc = rwm_filter_map_rewrite( &dc, op->ors_filter, &fstr );
512         if ( rc != LDAP_SUCCESS ) {
513                 text = "searchFilter/searchFilterAttrDN massage error";
514                 goto error_return;
515         }
516
517         f = str2filter_x( op, fstr.bv_val );
518
519         if ( f == NULL ) {
520                 text = "massaged filter parse error";
521                 goto error_return;
522         }
523
524         if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
525                 ch_free( op->ors_filterstr.bv_val );
526         }
527
528         if( op->ors_filter ) {
529                 filter_free_x( op, op->ors_filter );
530         }
531
532         op->ors_filter = f;
533         op->ors_filterstr = fstr;
534
535         rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
536                         op->ors_attrs, &an, RWM_MAP );
537         if ( rc != LDAP_SUCCESS ) {
538                 text = "attribute list mapping error";
539                 goto error_return;
540         }
541
542         cb = (slap_callback *) op->o_tmpcalloc( sizeof( slap_callback ),
543                         1, op->o_tmpmemctx );
544         if ( cb == NULL ) {
545                 rc = LDAP_NO_MEMORY;
546                 goto error_return;
547         }
548
549         cb->sc_response = rwm_swap_attrs;
550         cb->sc_cleanup = rwm_freeself;
551         cb->sc_private = (void *)op->ors_attrs;
552         cb->sc_next = op->o_callback;
553
554         op->o_callback = cb;
555         op->ors_attrs = an;
556
557         return SLAP_CB_CONTINUE;
558
559 error_return:;
560         if ( an != NULL ) {
561                 ch_free( an );
562         }
563
564         if ( f != NULL ) {
565                 filter_free_x( op, f );
566         }
567
568         if ( !BER_BVISNULL( &fstr ) ) {
569                 ch_free( fstr.bv_val );
570         }
571
572         op->o_bd->bd_info = (BackendInfo *)on->on_info;
573         send_ldap_error( op, rs, rc, text );
574
575         return 1;
576
577 }
578
579 static int
580 rwm_extended( Operation *op, SlapReply *rs )
581 {
582         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
583         int                     rc;
584
585 #ifdef ENABLE_REWRITE
586         rc = rwm_op_dn_massage( op, rs, "extendedDn" );
587 #else
588         rc = 1;
589         rc = rwm_op_dn_massage( op, rs, &rc );
590 #endif
591         if ( rc != LDAP_SUCCESS ) {
592                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
593                 send_ldap_error( op, rs, rc, "extendedDn massage error" );
594                 return rc;
595         }
596
597         /* TODO: rewrite/map extended data ? ... */
598         return 0;
599 }
600
601 static int
602 rwm_matched( Operation *op, SlapReply *rs )
603 {
604         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
605         struct ldaprwmap        *rwmap = 
606                         (struct ldaprwmap *)on->on_bi.bi_private;
607
608         struct berval           dn, mdn;
609         dncookie                dc;
610         int                     rc;
611
612         if ( rs->sr_matched == NULL ) {
613                 return SLAP_CB_CONTINUE;
614         }
615
616         dc.rwmap = rwmap;
617 #ifdef ENABLE_REWRITE
618         dc.conn = op->o_conn;
619         dc.rs = rs;
620         dc.ctx = "matchedDN";
621 #else
622         dc.tofrom = 0;
623         dc.normalized = 0;
624 #endif
625         ber_str2bv( rs->sr_matched, 0, 0, &dn );
626         rc = rwm_dn_massage( &dc, &dn, &mdn, NULL );
627         if ( rc != LDAP_SUCCESS ) {
628                 rs->sr_err = rc;
629                 rs->sr_text = "Rewrite error";
630                 return 1;
631         }
632
633         if ( mdn.bv_val != dn.bv_val ) {
634                 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
635                         ch_free( (void *)rs->sr_matched );
636
637                 } else {
638                         rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
639                 }
640                 rs->sr_matched = mdn.bv_val;
641         }
642         
643         return SLAP_CB_CONTINUE;
644 }
645
646 static int
647 rwm_send_entry( Operation *op, SlapReply *rs )
648 {
649         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
650         struct ldaprwmap        *rwmap = 
651                         (struct ldaprwmap *)on->on_bi.bi_private;
652
653         Entry           *e = NULL;
654         int             flags;
655         struct berval   dn = BER_BVNULL,
656                         ndn = BER_BVNULL;
657         dncookie        dc;
658         int             rc;
659         Attribute       **ap;
660
661         assert( rs->sr_entry );
662
663         /*
664          * Rewrite the dn of the result, if needed
665          */
666         dc.rwmap = rwmap;
667 #ifdef ENABLE_REWRITE
668         dc.conn = op->o_conn;
669         dc.rs = NULL; 
670         dc.ctx = "searchResult";
671 #else
672         dc.tofrom = 0;
673         dc.normalized = 0;
674 #endif
675
676         e = rs->sr_entry;
677         flags = rs->sr_flags;
678         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
679                 /* FIXME: all we need to duplicate are:
680                  * - dn
681                  * - ndn
682                  * - attributes that are requested
683                  * - no values if attrsonly is set
684                  */
685
686                 e = entry_dup( e );
687                 if ( e == NULL ) {
688                         rc = LDAP_NO_MEMORY;
689                         goto fail;
690                 }
691
692                 flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
693         }
694
695         /*
696          * Note: this may fail if the target host(s) schema differs
697          * from the one known to the meta, and a DN with unknown
698          * attributes is returned.
699          */
700         rc = rwm_dn_massage( &dc, &e->e_name, &dn, &ndn );
701         if ( rc != LDAP_SUCCESS ) {
702                 goto fail;
703         }
704
705         if ( e->e_name.bv_val != dn.bv_val ) {
706                 free( e->e_name.bv_val );
707                 free( e->e_nname.bv_val );
708
709                 e->e_name = dn;
710                 e->e_nname = ndn;
711         }
712
713         /* TODO: map entry attribute types, objectclasses 
714          * and dn-valued attribute values */
715
716         /* FIXME: the entries are in the remote mapping form;
717          * so we need to select those attributes we are willing
718          * to return, and remap them accordingly */
719
720         for ( ap = &e->e_attrs; *ap; ) {
721                 struct ldapmapping      *m;
722                 int                     drop_missing;
723                 int                     last;
724
725                 if ( op->ors_attrs != NULL && !ad_inlist( (*ap)->a_desc, op->ors_attrs ) ) {
726                         Attribute       *a;
727
728                         a = *ap;
729                         *ap = (*ap)->a_next;
730
731                         attr_free( a );
732                         continue;
733                 }
734
735                 drop_missing = rwm_mapping( &rwmap->rwm_at,
736                                 &(*ap)->a_desc->ad_cname, &m, RWM_REMAP );
737                 if ( drop_missing || ( m != NULL && BER_BVISEMPTY( &m->m_dst ) ) ) {
738                         Attribute       *a;
739
740                         a = *ap;
741                         *ap = (*ap)->a_next;
742
743                         attr_free( a );
744                         continue;
745                 }
746
747                 for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ )
748                         /* just count */ ;
749
750                 if ( last == 0 ) {
751                         /* empty? for now, we leave it in place */
752                         goto next_attr;
753                 }
754                 last--;
755
756                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
757                                 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
758                 {
759                         struct berval   *bv;
760                         
761                         for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
762                                 struct berval   mapped;
763
764                                 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
765                                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
766                                         ch_free( bv[0].bv_val );
767                                         BER_BVZERO( &bv[0] );
768                                         if ( &(*ap)->a_vals[last] > &bv[0] ) {
769                                                 bv[0] = (*ap)->a_vals[last];
770                                                 BER_BVZERO( &(*ap)->a_vals[last] );
771                                         }
772                                         last--;
773                                         bv--;
774
775                                 } else if ( mapped.bv_val != bv[0].bv_val ) {
776                                         /*
777                                          * FIXME: after LBER_FREEing
778                                          * the value is replaced by
779                                          * ch_alloc'ed memory
780                                          */
781                                         free( bv[0].bv_val );
782                                         ber_dupbv( &bv[0], &mapped );
783                                 }
784                         }
785
786                 /*
787                  * It is necessary to try to rewrite attributes with
788                  * dn syntax because they might be used in ACLs as
789                  * members of groups; since ACLs are applied to the
790                  * rewritten stuff, no dn-based subject clause could
791                  * be used at the ldap backend side (see
792                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
793                  * The problem can be overcome by moving the dn-based
794                  * ACLs to the target directory server, and letting
795                  * everything pass thru the ldap backend. */
796                 /* FIXME: handle distinguishedName-like syntaxes, like
797                  * nameAndOptionalUID */
798                 } else if ( (*ap)->a_desc->ad_type->sat_syntax ==
799                                 slap_schema.si_syn_distinguishedName )
800                 {
801                         rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
802                         if ( rc != LDAP_SUCCESS ) {
803                                 Attribute       *a;
804
805                                 a = *ap;
806                                 *ap = (*ap)->a_next;
807
808                                 attr_free( a );
809                                 continue;
810                         }
811                 }
812
813                 if ( m != NULL ) {
814                         /* rewrite the attribute description */
815                         assert( m->m_dst_ad );
816                         (*ap)->a_desc = m->m_dst_ad;
817                 }
818
819 next_attr:;
820                 ap = &(*ap)->a_next;
821         }
822
823
824         rs->sr_entry = e;
825         rs->sr_flags = flags;
826
827         return SLAP_CB_CONTINUE;
828
829 fail:;
830         if ( !BER_BVISNULL( &dn ) ) {
831                 ch_free( dn.bv_val );
832         }
833
834         if ( !BER_BVISNULL( &ndn ) ) {
835                 ch_free( ndn.bv_val );
836         }
837
838         if ( e != NULL && e != rs->sr_entry ) {
839                 entry_free( e );
840         }
841
842         return rc;
843 }
844
845 static int
846 rwm_rw_config(
847     BackendDB   *be,
848     const char  *fname,
849     int         lineno,
850     int         argc,
851     char        **argv
852 )
853 {
854 #ifdef ENABLE_REWRITE
855         slap_overinst           *on = (slap_overinst *) be->bd_info;
856         struct ldaprwmap        *rwmap = 
857                         (struct ldaprwmap *)on->on_bi.bi_private;
858
859         return rewrite_parse( rwmap->rwm_rw,
860                                 fname, lineno, argc, argv );
861
862 #else /* !ENABLE_REWRITE */
863         fprintf( stderr, "%s: line %d: rewrite capabilities "
864                         "are not enabled\n", fname, lineno );
865 #endif /* !ENABLE_REWRITE */
866                 
867         return 0;
868 }
869
870 static int
871 rwm_suffixmassage_config(
872     BackendDB   *be,
873     const char  *fname,
874     int         lineno,
875     int         argc,
876     char        **argv
877 )
878 {
879         slap_overinst           *on = (slap_overinst *) be->bd_info;
880         struct ldaprwmap        *rwmap = 
881                         (struct ldaprwmap *)on->on_bi.bi_private;
882
883         struct berval   bvnc, nvnc, pvnc, brnc, nrnc, prnc;
884 #ifdef ENABLE_REWRITE
885         int             rc;
886 #endif /* ENABLE_REWRITE */
887                 
888         /*
889          * syntax:
890          * 
891          *      suffixmassage <suffix> <massaged suffix>
892          *
893          * the <suffix> field must be defined as a valid suffix
894          * (or suffixAlias?) for the current database;
895          * the <massaged suffix> shouldn't have already been
896          * defined as a valid suffix or suffixAlias for the 
897          * current server
898          */
899         if ( argc != 3 ) {
900                 fprintf( stderr, "%s: line %d: syntax is"
901                                " \"suffixMassage <suffix>"
902                                " <massaged suffix>\"\n",
903                         fname, lineno );
904                 return 1;
905         }
906                 
907         ber_str2bv( argv[1], 0, 0, &bvnc );
908         if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
909                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
910                         fname, lineno, bvnc.bv_val );
911                 return 1;
912         }
913
914         ber_str2bv( argv[2], 0, 0, &brnc );
915         if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
916                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
917                                 fname, lineno, brnc.bv_val );
918                 free( nvnc.bv_val );
919                 free( pvnc.bv_val );
920                 return 1;
921         }
922
923 #ifdef ENABLE_REWRITE
924         /*
925          * The suffix massaging is emulated 
926          * by means of the rewrite capabilities
927          */
928         rc = rwm_suffix_massage_config( rwmap->rwm_rw,
929                         &pvnc, &nvnc, &prnc, &nrnc );
930         free( nvnc.bv_val );
931         free( pvnc.bv_val );
932         free( nrnc.bv_val );
933         free( prnc.bv_val );
934
935         return( rc );
936
937 #else /* !ENABLE_REWRITE */
938         ber_bvarray_add( &rwmap->rwm_suffix_massage, &pvnc );
939         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nvnc );
940                 
941         ber_bvarray_add( &rwmap->rwm_suffix_massage, &prnc );
942         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nrnc );
943 #endif /* !ENABLE_REWRITE */
944
945         return 0;
946 }
947
948 static int
949 rwm_m_config(
950     BackendDB   *be,
951     const char  *fname,
952     int         lineno,
953     int         argc,
954     char        **argv
955 )
956 {
957         slap_overinst           *on = (slap_overinst *) be->bd_info;
958         struct ldaprwmap        *rwmap = 
959                         (struct ldaprwmap *)on->on_bi.bi_private;
960
961         /* objectclass/attribute mapping */
962         return rwm_map_config( &rwmap->rwm_oc,
963                         &rwmap->rwm_at,
964                         fname, lineno, argc, argv );
965 }
966
967 static int
968 rwm_response( Operation *op, SlapReply *rs )
969 {
970         int             rc;
971
972         if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
973                 return rwm_send_entry( op, rs );
974         }
975
976         switch( op->o_tag ) {
977         case LDAP_REQ_SEARCH:
978                 /* Note: the operation attrs are remapped */
979                 if ( op->ors_attrs != NULL && op->ors_attrs != rs->sr_attrs )
980                 {
981                         ch_free( op->ors_attrs );
982                         op->ors_attrs = rs->sr_attrs;
983                 }
984                 /* fall thru */
985
986         case LDAP_REQ_BIND:
987         case LDAP_REQ_ADD:
988         case LDAP_REQ_DELETE:
989         case LDAP_REQ_MODRDN:
990         case LDAP_REQ_MODIFY:
991         case LDAP_REQ_COMPARE:
992         case LDAP_REQ_EXTENDED:
993                 rc = rwm_matched( op, rs );
994                 break;
995
996         default:
997                 rc = SLAP_CB_CONTINUE;
998                 break;
999         }
1000
1001         return rc;
1002 }
1003
1004 static int
1005 rwm_config(
1006     BackendDB   *be,
1007     const char  *fname,
1008     int         lineno,
1009     int         argc,
1010     char        **argv
1011 )
1012 {
1013         int             rc = 0;
1014         char            *argv0 = NULL;
1015
1016         if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1017                 argv0 = argv[ 0 ];
1018                 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1019         }
1020
1021         if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1022                 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1023
1024         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1025                 rc = rwm_m_config( be, fname, lineno, argc, argv );
1026
1027         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1028                 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1029
1030         } else {
1031                 rc = SLAP_CONF_UNKNOWN;
1032         }
1033
1034         if ( argv0 ) {
1035                 argv[ 0 ] = argv0;
1036         }
1037
1038         return rc;
1039 }
1040
1041 static int
1042 rwm_over_init(
1043         BackendDB *be
1044 )
1045 {
1046         slap_overinst           *on = (slap_overinst *) be->bd_info;
1047         struct ldapmapping      *mapping = NULL;
1048         struct ldaprwmap        *rwmap;
1049
1050         rwmap = (struct ldaprwmap *)ch_malloc(sizeof(struct ldaprwmap));
1051         memset(rwmap, 0, sizeof(struct ldaprwmap));
1052
1053 #ifdef ENABLE_REWRITE
1054         rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
1055         if ( rwmap->rwm_rw == NULL ) {
1056                 ch_free( rwmap );
1057                 return -1;
1058         }
1059
1060         {
1061                 char    *rargv[3];
1062
1063                 /* this rewriteContext by default must be null;
1064                  * rules can be added if required */
1065                 rargv[ 0 ] = "rewriteContext";
1066                 rargv[ 1 ] = "searchFilter";
1067                 rargv[ 2 ] = NULL;
1068                 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
1069
1070                 rargv[ 0 ] = "rewriteContext";
1071                 rargv[ 1 ] = "default";
1072                 rargv[ 2 ] = NULL;
1073                 rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
1074         }
1075         
1076 #endif /* ENABLE_REWRITE */
1077
1078         if ( rwm_map_init( &rwmap->rwm_oc, &mapping ) != LDAP_SUCCESS ||
1079                         rwm_map_init( &rwmap->rwm_at, &mapping ) != LDAP_SUCCESS )
1080         {
1081                 return 1;
1082         }
1083
1084         on->on_bi.bi_private = (void *)rwmap;
1085
1086         return 0;
1087 }
1088
1089 static int
1090 rwm_destroy(
1091         BackendDB *be
1092 )
1093 {
1094         slap_overinst   *on = (slap_overinst *) be->bd_info;
1095         int             rc = 0;
1096
1097         if ( on->on_bi.bi_private ) {
1098                 struct ldaprwmap        *rwmap = 
1099                         (struct ldaprwmap *)on->on_bi.bi_private;
1100
1101 #ifdef ENABLE_REWRITE
1102                 if (rwmap->rwm_rw) {
1103                         rewrite_info_delete( &rwmap->rwm_rw );
1104                 }
1105 #else /* !ENABLE_REWRITE */
1106                 if ( rwmap->rwm_suffix_massage ) {
1107                         ber_bvarray_free( rwmap->rwm_suffix_massage );
1108                 }
1109 #endif /* !ENABLE_REWRITE */
1110
1111                 avl_free( rwmap->rwm_oc.remap, NULL );
1112                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
1113                 avl_free( rwmap->rwm_at.remap, NULL );
1114                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
1115         }
1116
1117         return rc;
1118 }
1119
1120 static slap_overinst rwm = { { NULL } };
1121
1122 int
1123 rwm_init(void)
1124 {
1125         memset( &rwm, 0, sizeof(slap_overinst) );
1126
1127         rwm.on_bi.bi_type = "rwm";
1128         rwm.on_bi.bi_db_init = rwm_over_init;
1129         rwm.on_bi.bi_db_config = rwm_config;
1130         rwm.on_bi.bi_db_destroy = rwm_destroy;
1131
1132         rwm.on_bi.bi_op_bind = rwm_bind;
1133         rwm.on_bi.bi_op_search = rwm_search;
1134         rwm.on_bi.bi_op_compare = rwm_compare;
1135         rwm.on_bi.bi_op_modify = rwm_modify;
1136         rwm.on_bi.bi_op_modrdn = rwm_modrdn;
1137         rwm.on_bi.bi_op_add = rwm_add;
1138         rwm.on_bi.bi_op_delete = rwm_delete;
1139         rwm.on_bi.bi_op_unbind = rwm_unbind;
1140         rwm.on_bi.bi_extended = rwm_extended;
1141
1142         rwm.on_response = rwm_response;
1143
1144         return overlay_register( &rwm );
1145 }
1146
1147 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1148 int init_module(int argc, char *argv[]) {
1149         return rwm_init();
1150 }
1151 #endif
1152
1153 #endif /* SLAPD_OVER_RWM */