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