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