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