]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/rwm.c
ITS#4788 don't return auditContext attr on syncrepl searches
[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-2006 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 typedef struct rwm_op_state {
30         ber_tag_t r_tag;
31         struct berval ro_dn;
32         struct berval ro_ndn;
33         struct berval r_dn;
34         struct berval r_ndn;
35         OpRequest o_request;
36 } rwm_op_state;
37
38 static int
39 rwm_db_destroy( BackendDB *be );
40
41 typedef struct rwm_op_cb {
42         slap_callback cb;
43         rwm_op_state ros;
44 } rwm_op_cb;
45
46 static int
47 rwm_op_cleanup( Operation *op, SlapReply *rs )
48 {
49         slap_callback   *cb = op->o_callback;
50         rwm_op_state *ros = cb->sc_private;
51
52         if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
53                 op->o_abandon || rs->sr_err == SLAPD_ABANDON ) {
54
55                 op->o_req_dn = ros->ro_dn;
56                 op->o_req_ndn = ros->ro_ndn;
57
58                 if ( !BER_BVISEMPTY( &ros->r_dn )) ch_free( ros->r_dn.bv_val );
59                 if ( !BER_BVISEMPTY( &ros->r_ndn )) ch_free( ros->r_ndn.bv_val );
60
61                 switch( ros->r_tag ) {
62                 case LDAP_REQ_COMPARE:
63                         if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
64                                 op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
65                         op->orc_ava = ros->orc_ava;
66                         break;
67                 case LDAP_REQ_MODIFY:
68                         slap_mods_free( op->orm_modlist, 1 );
69                         op->orm_modlist = ros->orm_modlist;
70                         break;
71                 case LDAP_REQ_MODRDN:
72                         if ( op->orr_newSup != ros->orr_newSup ) {
73                                 ch_free( op->orr_newSup->bv_val );
74                                 ch_free( op->orr_nnewSup->bv_val );
75                                 op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
76                                 op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
77                                 op->orr_newSup = ros->orr_newSup;
78                                 op->orr_nnewSup = ros->orr_nnewSup;
79                         }
80                         break;
81                 case LDAP_REQ_SEARCH:
82                         ch_free( op->ors_attrs );
83                         filter_free_x( op, op->ors_filter );
84                         ch_free( op->ors_filterstr.bv_val );
85                         op->ors_attrs = ros->ors_attrs;
86                         op->ors_filter = ros->ors_filter;
87                         op->ors_filterstr = ros->ors_filterstr;
88                         break;
89                 case LDAP_REQ_EXTENDED:
90                         if ( op->ore_reqdata != ros->ore_reqdata ) {
91                                 ber_bvfree( op->ore_reqdata );
92                                 op->ore_reqdata = ros->ore_reqdata;
93                         }
94                         break;
95                 default:        break;
96                 }
97                 op->o_callback = op->o_callback->sc_next;
98                 op->o_tmpfree( cb, op->o_tmpmemctx );
99         }
100
101         return SLAP_CB_CONTINUE;
102 }
103
104 static rwm_op_cb *
105 rwm_callback_get( Operation *op, SlapReply *rs )
106 {
107         rwm_op_cb       *roc = NULL;
108
109         roc = op->o_tmpalloc( sizeof( struct rwm_op_cb ), op->o_tmpmemctx );
110         roc->cb.sc_cleanup = rwm_op_cleanup;
111         roc->cb.sc_response = NULL;
112         roc->cb.sc_next = op->o_callback;
113         roc->cb.sc_private = &roc->ros;
114         roc->ros.r_tag = op->o_tag;
115         roc->ros.ro_dn = op->o_req_dn;
116         roc->ros.ro_ndn = op->o_req_ndn;
117         roc->ros.o_request = op->o_request;
118         BER_BVZERO( &roc->ros.r_dn );
119         BER_BVZERO( &roc->ros.r_ndn );
120
121         return roc;
122 }
123
124
125 static int
126 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
127         rwm_op_state *ros )
128 {
129         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
130         struct ldaprwmap        *rwmap = 
131                         (struct ldaprwmap *)on->on_bi.bi_private;
132
133         struct berval           dn = BER_BVNULL,
134                                 ndn = BER_BVNULL;
135         int                     rc = 0;
136         dncookie                dc;
137
138         /*
139          * Rewrite the dn if needed
140          */
141         dc.rwmap = rwmap;
142 #ifdef ENABLE_REWRITE
143         dc.conn = op->o_conn;
144         dc.rs = rs;
145         dc.ctx = (char *)cookie;
146 #else /* ! ENABLE_REWRITE */
147         dc.tofrom = ((int *)cookie)[0];
148         dc.normalized = 0;
149 #endif /* ! ENABLE_REWRITE */
150
151         /* NOTE: in those cases where only the ndn is available,
152          * and the caller sets op->o_req_dn = op->o_req_ndn,
153          * only rewrite the op->o_req_ndn and use it as 
154          * op->o_req_dn as well */
155         ndn = op->o_req_ndn;
156         if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
157                 dn = op->o_req_dn;
158                 rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
159         } else {
160                 rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
161         }
162
163         if ( rc != LDAP_SUCCESS ) {
164                 return rc;
165         }
166
167         if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
168                         || ndn.bv_val == op->o_req_ndn.bv_val )
169         {
170                 return LDAP_SUCCESS;
171         }
172
173         if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
174                 op->o_req_dn = dn;
175                 ros->r_dn  = dn;
176         } else {
177                 op->o_req_dn = ndn;
178         }
179         ros->r_ndn = ndn;
180         op->o_req_ndn = ndn;
181
182         return LDAP_SUCCESS;
183 }
184
185 static int
186 rwm_op_add( 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                                 i;
194         Attribute               **ap = NULL;
195         char                    *olddn = op->o_req_dn.bv_val;
196         int                     isupdate;
197
198         rwm_op_cb *roc = rwm_callback_get( op, rs );
199
200 #ifdef ENABLE_REWRITE
201         rc = rwm_op_dn_massage( op, rs, "addDN", &roc->ros );
202 #else /* ! ENABLE_REWRITE */
203         rc = 1;
204         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
205 #endif /* ! ENABLE_REWRITE */
206         if ( rc != LDAP_SUCCESS ) {
207                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
208                 send_ldap_error( op, rs, rc, "addDN massage error" );
209                 return -1;
210         }
211
212         if ( olddn != op->o_req_dn.bv_val ) {
213                 ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
214                 ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
215         }
216
217         /* Count number of attributes in entry */ 
218         isupdate = be_shadow_update( op );
219         for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
220                 Attribute       *a;
221
222                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
223                                 (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
224                 {
225                         int             j, last;
226
227                         for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[ last ] ); last++ )
228                                         /* count values */ ;
229                         last--;
230                         for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
231                                 struct ldapmapping      *mapping = NULL;
232
233                                 ( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
234                                                 &mapping, RWM_MAP );
235                                 if ( mapping == NULL ) {
236                                         if ( rwmap->rwm_at.drop_missing ) {
237                                                 /* FIXME: we allow to remove objectClasses as well;
238                                                  * if the resulting entry is inconsistent, that's
239                                                  * the relayed database's business...
240                                                  */
241                                                 ch_free( (*ap)->a_vals[ j ].bv_val );
242                                                 if ( last > j ) {
243                                                         (*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
244                                                 }
245                                                 BER_BVZERO( &(*ap)->a_vals[ last ] );
246                                                 last--;
247                                                 j--;
248                                         }
249
250                                 } else {
251                                         ch_free( (*ap)->a_vals[ j ].bv_val );
252                                         ber_dupbv( &(*ap)->a_vals[ j ], &mapping->m_dst );
253                                 }
254                         }
255
256                 } else if ( !isupdate && !get_relax( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
257                 {
258                         goto next_attr;
259
260                 } else {
261                         struct ldapmapping      *mapping = NULL;
262
263                         ( void )rwm_mapping( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
264                                         &mapping, RWM_MAP );
265                         if ( mapping == NULL ) {
266                                 if ( rwmap->rwm_at.drop_missing ) {
267                                         goto cleanup_attr;
268                                 }
269                         }
270
271                         if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
272                                         || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
273                         {
274                                 /*
275                                  * FIXME: rewrite could fail; in this case
276                                  * the operation should give up, right?
277                                  */
278 #ifdef ENABLE_REWRITE
279                                 rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
280                                                 (*ap)->a_vals,
281                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
282 #else /* ! ENABLE_REWRITE */
283                                 rc = 1;
284                                 rc = rwm_dnattr_rewrite( op, rs, &rc, (*ap)->a_vals,
285                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
286 #endif /* ! ENABLE_REWRITE */
287                                 if ( rc ) {
288                                         goto cleanup_attr;
289                                 }
290
291                         } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
292 #ifdef ENABLE_REWRITE
293                                 rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
294                                                 (*ap)->a_vals,
295                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
296 #else /* ! ENABLE_REWRITE */
297                                 rc = 1;
298                                 rc = rwm_referral_rewrite( op, rs, &rc, (*ap)->a_vals,
299                                                 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
300 #endif /* ! ENABLE_REWRITE */
301                                 if ( rc != LDAP_SUCCESS ) {
302                                         goto cleanup_attr;
303                                 }
304                         }
305                 
306                         if ( mapping != NULL ) {
307                                 assert( mapping->m_dst_ad != NULL );
308                                 (*ap)->a_desc = mapping->m_dst_ad;
309                         }
310                 }
311
312 next_attr:;
313                 ap = &(*ap)->a_next;
314                 continue;
315
316 cleanup_attr:;
317                 /* FIXME: leaking attribute/values? */
318                 a = *ap;
319
320                 *ap = (*ap)->a_next;
321                 attr_free( a );
322         }
323
324         op->o_callback = &roc->cb;
325
326         return SLAP_CB_CONTINUE;
327 }
328
329 #ifdef ENABLE_REWRITE
330 static int
331 rwm_conn_init( BackendDB *be, Connection *conn )
332 {
333         slap_overinst           *on = (slap_overinst *) be->bd_info;
334         struct ldaprwmap        *rwmap = 
335                         (struct ldaprwmap *)on->on_bi.bi_private;
336
337         ( void )rewrite_session_init( rwmap->rwm_rw, conn );
338
339         return SLAP_CB_CONTINUE;
340 }
341
342 static int
343 rwm_conn_destroy( BackendDB *be, Connection *conn )
344 {
345         slap_overinst           *on = (slap_overinst *) be->bd_info;
346         struct ldaprwmap        *rwmap = 
347                         (struct ldaprwmap *)on->on_bi.bi_private;
348
349         ( void )rewrite_session_delete( rwmap->rwm_rw, conn );
350
351         return SLAP_CB_CONTINUE;
352 }
353 #endif /* ENABLE_REWRITE */
354
355 static int
356 rwm_op_bind( Operation *op, SlapReply *rs )
357 {
358         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
359         int                     rc;
360
361         rwm_op_cb *roc = rwm_callback_get( op, rs );
362
363 #ifdef ENABLE_REWRITE
364         rc = rwm_op_dn_massage( op, rs, "bindDN", &roc->ros );
365 #else /* ! ENABLE_REWRITE */
366         rc = 1;
367         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
368 #endif /* ! ENABLE_REWRITE */
369         if ( rc != LDAP_SUCCESS ) {
370                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
371                 send_ldap_error( op, rs, rc, "bindDN massage error" );
372                 return -1;
373         }
374
375         op->o_callback = &roc->cb;
376
377         return SLAP_CB_CONTINUE;
378 }
379
380 static int
381 rwm_op_unbind( Operation *op, SlapReply *rs )
382 {
383         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
384         struct ldaprwmap        *rwmap = 
385                         (struct ldaprwmap *)on->on_bi.bi_private;
386
387 #ifdef ENABLE_REWRITE
388         rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
389 #endif /* ENABLE_REWRITE */
390
391         return SLAP_CB_CONTINUE;
392 }
393
394 static int
395 rwm_op_compare( Operation *op, SlapReply *rs )
396 {
397         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
398         struct ldaprwmap        *rwmap = 
399                         (struct ldaprwmap *)on->on_bi.bi_private;
400
401         int                     rc;
402         struct berval mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
403
404         rwm_op_cb *roc = rwm_callback_get( op, rs );
405
406 #ifdef ENABLE_REWRITE
407         rc = rwm_op_dn_massage( op, rs, "compareDN", &roc->ros );
408 #else /* ! ENABLE_REWRITE */
409         rc = 1;
410         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
411 #endif /* ! ENABLE_REWRITE */
412         if ( rc != LDAP_SUCCESS ) {
413                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
414                 send_ldap_error( op, rs, rc, "compareDN massage error" );
415                 return -1;
416         }
417
418         /* if the attribute is an objectClass, try to remap its value */
419         if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
420                         || op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
421         {
422                 rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
423                                 &mapped_vals[0], RWM_MAP );
424                 if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
425                 {
426                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
427                         send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
428                         return -1;
429
430                 } else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
431                         ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
432                                 op->o_tmpmemctx );
433                 }
434
435         } else {
436                 struct ldapmapping      *mapping = NULL;
437                 AttributeDescription    *ad = op->orc_ava->aa_desc;
438
439                 ( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
440                                 &mapping, RWM_MAP );
441                 if ( mapping == NULL ) {
442                         if ( rwmap->rwm_at.drop_missing ) {
443                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
444                                 send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
445                                 return -1;
446                         }
447
448                 } else {
449                         assert( mapping->m_dst_ad != NULL );
450                         ad = mapping->m_dst_ad;
451                 }
452
453                 if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
454                                 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
455                 {
456                         struct berval   *mapped_valsp[2];
457                         
458                         mapped_valsp[0] = &mapped_vals[0];
459                         mapped_valsp[1] = &mapped_vals[1];
460
461                         mapped_vals[0] = op->orc_ava->aa_value;
462
463 #ifdef ENABLE_REWRITE
464                         rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
465 #else /* ! ENABLE_REWRITE */
466                         rc = 1;
467                         rc = rwm_dnattr_rewrite( op, rs, &rc, NULL, mapped_valsp );
468 #endif /* ! ENABLE_REWRITE */
469
470                         if ( rc != LDAP_SUCCESS ) {
471                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
472                                 send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
473                                 return -1;
474                         }
475
476                         if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
477                                 /* NOTE: if we get here, rwm_dnattr_rewrite()
478                                  * already freed the old value, so now 
479                                  * it's invalid */
480                                 ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
481                                         op->o_tmpmemctx );
482                                 ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
483                         }
484                 }
485                 op->orc_ava->aa_desc = ad;
486         }
487
488         op->o_callback = &roc->cb;
489
490         return SLAP_CB_CONTINUE;
491 }
492
493 static int
494 rwm_op_delete( Operation *op, SlapReply *rs )
495 {
496         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
497         int                     rc;
498
499         rwm_op_cb *roc = rwm_callback_get( op, rs );
500
501 #ifdef ENABLE_REWRITE
502         rc = rwm_op_dn_massage( op, rs, "deleteDN", &roc->ros );
503 #else /* ! ENABLE_REWRITE */
504         rc = 1;
505         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
506 #endif /* ! ENABLE_REWRITE */
507         if ( rc != LDAP_SUCCESS ) {
508                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
509                 send_ldap_error( op, rs, rc, "deleteDN massage error" );
510                 return -1;
511         }
512
513         op->o_callback = &roc->cb;
514
515         return SLAP_CB_CONTINUE;
516 }
517
518 static int
519 rwm_op_modify( Operation *op, SlapReply *rs )
520 {
521         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
522         struct ldaprwmap        *rwmap = 
523                         (struct ldaprwmap *)on->on_bi.bi_private;
524
525         int                     isupdate;
526         Modifications           **mlp;
527         int                     rc;
528
529         rwm_op_cb *roc = rwm_callback_get( op, rs );
530
531 #ifdef ENABLE_REWRITE
532         rc = rwm_op_dn_massage( op, rs, "modifyDN", &roc->ros );
533 #else /* ! ENABLE_REWRITE */
534         rc = 1;
535         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
536 #endif /* ! ENABLE_REWRITE */
537         if ( rc != LDAP_SUCCESS ) {
538                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
539                 send_ldap_error( op, rs, rc, "modifyDN massage error" );
540                 return -1;
541         }
542
543         isupdate = be_shadow_update( op );
544         for ( mlp = &op->oq_modify.rs_modlist; *mlp; ) {
545                 int                     is_oc = 0;
546                 Modifications           *ml;
547                 struct ldapmapping      *mapping = NULL;
548
549                 /* duplicate the modlist */
550                 ml = ch_malloc( sizeof( Modifications ));
551                 *ml = **mlp;
552                 *mlp = ml;
553
554                 if ( ml->sml_desc == slap_schema.si_ad_objectClass 
555                                 || ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
556                 {
557                         is_oc = 1;
558
559                 } else if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
560                 {
561                         goto next_mod;
562
563                 } else {
564                         int                     drop_missing;
565
566                         drop_missing = rwm_mapping( &rwmap->rwm_at,
567                                         &ml->sml_desc->ad_cname,
568                                         &mapping, RWM_MAP );
569                         if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
570                         {
571                                 goto cleanup_mod;
572                         }
573                 }
574
575                 if ( ml->sml_values != NULL ) {
576                         int i, num;
577                         struct berval *bva;
578
579                         for ( num = 0; !BER_BVISNULL( &ml->sml_values[ num ] ); num++ )
580                                 /* count values */ ;
581
582                         bva = ch_malloc( (num+1) * sizeof( struct berval ));
583                         for (i=0; i<num; i++)
584                                 ber_dupbv( &bva[i], &ml->sml_values[i] );
585                         BER_BVZERO( &bva[i] );
586                         ml->sml_values = bva;
587
588                         if ( ml->sml_nvalues ) {
589                                 bva = ch_malloc( (num+1) * sizeof( struct berval ));
590                                 for (i=0; i<num; i++)
591                                         ber_dupbv( &bva[i], &ml->sml_nvalues[i] );
592                                 BER_BVZERO( &bva[i] );
593                                 ml->sml_nvalues = bva;
594                         }
595
596                         if ( is_oc ) {
597                                 int     last, j;
598
599                                 last = num-1;
600
601                                 for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
602                                         struct ldapmapping      *oc_mapping = NULL;
603                 
604                                         ( void )rwm_mapping( &rwmap->rwm_oc, &ml->sml_values[ j ],
605                                                         &oc_mapping, RWM_MAP );
606                                         if ( oc_mapping == NULL ) {
607                                                 if ( rwmap->rwm_at.drop_missing ) {
608                                                         /* FIXME: we allow to remove objectClasses as well;
609                                                          * if the resulting entry is inconsistent, that's
610                                                          * the relayed database's business...
611                                                          */
612                                                         if ( last > j ) {
613                                                                 ch_free( ml->sml_values[ j ].bv_val );
614                                                                 ml->sml_values[ j ] = ml->sml_values[ last ];
615                                                         }
616                                                         BER_BVZERO( &ml->sml_values[ last ] );
617                                                         last--;
618                                                         j--;
619                                                 }
620         
621                                         } else {
622                                                 ch_free( ml->sml_values[ j ].bv_val );
623                                                 ber_dupbv( &ml->sml_values[ j ], &oc_mapping->m_dst );
624                                         }
625                                 }
626
627                         } else {
628                                 if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
629                                                 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
630                                 {
631 #ifdef ENABLE_REWRITE
632                                         rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
633                                                         ml->sml_values,
634                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
635 #else /* ! ENABLE_REWRITE */
636                                         rc = 1;
637                                         rc = rwm_dnattr_rewrite( op, rs, &rc, 
638                                                         ml->sml_values,
639                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
640 #endif /* ! ENABLE_REWRITE */
641
642                                 } else if ( ml->sml_desc == slap_schema.si_ad_ref ) {
643 #ifdef ENABLE_REWRITE
644                                         rc = rwm_referral_rewrite( op, rs,
645                                                         "referralAttrDN",
646                                                         ml->sml_values,
647                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
648 #else /* ! ENABLE_REWRITE */
649                                         rc = 1;
650                                         rc = rwm_referral_rewrite( op, rs, &rc,
651                                                         ml->sml_values,
652                                                         ml->sml_nvalues ? &ml->sml_nvalues : NULL );
653 #endif /* ! ENABLE_REWRITE */
654                                         if ( rc != LDAP_SUCCESS ) {
655                                                 goto cleanup_mod;
656                                         }
657                                 }
658
659                                 if ( rc != LDAP_SUCCESS ) {
660                                         goto cleanup_mod;
661                                 }
662                         }
663                 }
664
665 next_mod:;
666                 if ( mapping != NULL ) {
667                         /* use new attribute description */
668                         assert( mapping->m_dst_ad != NULL );
669                         ml->sml_desc = mapping->m_dst_ad;
670                 }
671
672                 mlp = &ml->sml_next;
673                 continue;
674
675 cleanup_mod:;
676                 ml = *mlp;
677                 *mlp = (*mlp)->sml_next;
678                 slap_mod_free( &ml->sml_mod, 0 );
679                 free( ml );
680         }
681
682         op->o_callback = &roc->cb;
683
684         return SLAP_CB_CONTINUE;
685 }
686
687 static int
688 rwm_op_modrdn( Operation *op, SlapReply *rs )
689 {
690         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
691         struct ldaprwmap        *rwmap = 
692                         (struct ldaprwmap *)on->on_bi.bi_private;
693         
694         int                     rc;
695
696         rwm_op_cb *roc = rwm_callback_get( op, rs );
697
698         if ( op->orr_newSup ) {
699                 dncookie        dc;
700                 struct berval   nnewSup = BER_BVNULL;
701                 struct berval   newSup = BER_BVNULL;
702
703                 /*
704                  * Rewrite the new superior, if defined and required
705                  */
706                 dc.rwmap = rwmap;
707 #ifdef ENABLE_REWRITE
708                 dc.conn = op->o_conn;
709                 dc.rs = rs;
710                 dc.ctx = "newSuperiorDN";
711 #else /* ! ENABLE_REWRITE */
712                 dc.tofrom = 0;
713                 dc.normalized = 0;
714 #endif /* ! ENABLE_REWRITE */
715                 newSup = *op->orr_newSup;
716                 nnewSup = *op->orr_nnewSup;
717                 rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
718                 if ( rc != LDAP_SUCCESS ) {
719                         op->o_bd->bd_info = (BackendInfo *)on->on_info;
720                         send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
721                         return -1;
722                 }
723
724                 if ( op->orr_newSup->bv_val != newSup.bv_val ) {
725                         op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ),
726                                 op->o_tmpmemctx );
727                         op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ),
728                                 op->o_tmpmemctx );
729                         *op->orr_newSup = newSup;
730                         *op->orr_nnewSup = nnewSup;
731                 }
732         }
733
734         /*
735          * Rewrite the dn, if needed
736          */
737 #ifdef ENABLE_REWRITE
738         rc = rwm_op_dn_massage( op, rs, "renameDN", &roc->ros );
739 #else /* ! ENABLE_REWRITE */
740         rc = 1;
741         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
742 #endif /* ! ENABLE_REWRITE */
743         if ( rc != LDAP_SUCCESS ) {
744                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
745                 send_ldap_error( op, rs, rc, "renameDN massage error" );
746                 if ( op->orr_newSup != roc->ros.orr_newSup ) {
747                         ch_free( op->orr_newSup->bv_val );
748                         ch_free( op->orr_nnewSup->bv_val );
749                         op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
750                         op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
751                         op->orr_newSup = roc->ros.orr_newSup;
752                         op->orr_nnewSup = roc->ros.orr_nnewSup;
753                 }
754                 return -1;
755         }
756
757         /* TODO: rewrite newRDN, attribute types, 
758          * values of DN-valued attributes ... */
759
760         op->o_callback = &roc->cb;
761
762         return SLAP_CB_CONTINUE;
763 }
764
765
766 static int
767 rwm_swap_attrs( Operation *op, SlapReply *rs )
768 {
769         slap_callback   *cb = op->o_callback;
770         rwm_op_state *ros = cb->sc_private;
771
772         rs->sr_attrs = ros->ors_attrs;
773         
774         return SLAP_CB_CONTINUE;
775 }
776
777 static int
778 rwm_op_search( Operation *op, SlapReply *rs )
779 {
780         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
781         struct ldaprwmap        *rwmap = 
782                         (struct ldaprwmap *)on->on_bi.bi_private;
783
784         int                     rc;
785         dncookie                dc;
786
787         struct berval           fstr = BER_BVNULL;
788         Filter                  *f = NULL;
789
790         AttributeName           *an = NULL;
791
792         char                    *text = NULL;
793
794         rwm_op_cb *roc = rwm_callback_get( op, rs );
795
796 #ifdef ENABLE_REWRITE
797         rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
798                 "searchFilter", op->ors_filterstr.bv_val );
799         if ( rc == LDAP_SUCCESS )
800                 rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
801 #else /* ! ENABLE_REWRITE */
802         rc = 1;
803         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
804 #endif /* ! ENABLE_REWRITE */
805         if ( rc != LDAP_SUCCESS ) {
806                 text = "searchDN massage error";
807                 goto error_return;
808         }
809
810         /*
811          * Rewrite the dn if needed
812          */
813         dc.rwmap = rwmap;
814 #ifdef ENABLE_REWRITE
815         dc.conn = op->o_conn;
816         dc.rs = rs;
817         dc.ctx = "searchFilterAttrDN";
818 #else /* ! ENABLE_REWRITE */
819         dc.tofrom = 0;
820         dc.normalized = 0;
821 #endif /* ! ENABLE_REWRITE */
822
823         rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
824         if ( rc != LDAP_SUCCESS ) {
825                 text = "searchFilter/searchFilterAttrDN massage error";
826                 goto error_return;
827         }
828
829         f = str2filter_x( op, fstr.bv_val );
830
831         if ( f == NULL ) {
832                 text = "massaged filter parse error";
833                 goto error_return;
834         }
835
836         op->ors_filter = f;
837         op->ors_filterstr = fstr;
838
839         rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
840                         op->ors_attrs, &an, RWM_MAP );
841         if ( rc != LDAP_SUCCESS ) {
842                 text = "attribute list mapping error";
843                 goto error_return;
844         }
845
846         op->ors_attrs = an;
847         roc->cb.sc_response = rwm_swap_attrs;
848
849         op->o_callback = &roc->cb;
850
851         return SLAP_CB_CONTINUE;
852
853 error_return:;
854         if ( an != NULL ) {
855                 ch_free( an );
856         }
857
858         if ( f != NULL ) {
859                 filter_free_x( op, f );
860         }
861
862         if ( !BER_BVISNULL( &fstr ) ) {
863                 ch_free( fstr.bv_val );
864         }
865
866         op->oq_search = roc->ros.oq_search;
867
868         op->o_bd->bd_info = (BackendInfo *)on->on_info;
869         send_ldap_error( op, rs, rc, text );
870
871         return -1;
872
873 }
874
875 static int
876 rwm_exop_passwd( Operation *op, SlapReply *rs )
877 {
878         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
879         int                     rc;
880         rwm_op_cb *roc;
881
882         struct berval   id = BER_BVNULL,
883                         pwold = BER_BVNULL,
884                         pwnew = BER_BVNULL;
885         BerElement *ber = NULL;
886
887         if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
888                 return LDAP_SUCCESS;
889         }
890
891         if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
892                 rs->sr_err = LDAP_OTHER;
893                 return rs->sr_err;
894         }
895
896         rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
897                 &pwold, &pwnew, &rs->sr_text );
898         if ( rs->sr_err != LDAP_SUCCESS ) {
899                 return rs->sr_err;
900         }
901
902         if ( !BER_BVISNULL( &id ) ) {
903                 rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
904                                 &op->o_req_ndn, op->o_tmpmemctx );
905                 if ( rs->sr_err != LDAP_SUCCESS ) {
906                         rs->sr_text = "Invalid DN";
907                         return rs->sr_err;
908                 }
909
910         } else {
911                 ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
912                 ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
913         }
914
915         roc = rwm_callback_get( op, rs );
916
917 #ifdef ENABLE_REWRITE
918         rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
919 #else /* ! ENABLE_REWRITE */
920         rc = 1;
921         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
922 #endif /* ! ENABLE_REWRITE */
923         if ( rc != LDAP_SUCCESS ) {
924                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
925                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
926                 return -1;
927         }
928
929         ber = ber_alloc_t( LBER_USE_DER );
930         if ( !ber ) {
931                 rs->sr_err = LDAP_OTHER;
932                 rs->sr_text = "No memory";
933                 return rs->sr_err;
934         }
935         ber_printf( ber, "{" );
936         if ( !BER_BVISNULL( &id )) {
937                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, 
938                         &op->o_req_dn );
939         }
940         if ( !BER_BVISNULL( &pwold )) {
941                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &pwold );
942         }
943         if ( !BER_BVISNULL( &pwnew )) {
944                 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &pwnew );
945         }
946         ber_printf( ber, "N}" );
947         ber_flatten( ber, &op->ore_reqdata );
948         ber_free( ber, 1 );
949
950         op->o_callback = &roc->cb;
951
952         return SLAP_CB_CONTINUE;
953 }
954
955 static struct exop {
956         struct berval   oid;
957         BI_op_extended  *extended;
958 } exop_table[] = {
959         { BER_BVC(LDAP_EXOP_MODIFY_PASSWD),     rwm_exop_passwd },
960         { BER_BVNULL, NULL }
961 };
962
963 static int
964 rwm_extended( Operation *op, SlapReply *rs )
965 {
966         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
967         int                     rc;
968         rwm_op_cb *roc;
969
970         int     i;
971
972         for ( i = 0; exop_table[i].extended != NULL; i++ ) {
973                 if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
974                 {
975                         rc = exop_table[i].extended( op, rs );
976                         switch ( rc ) {
977                         case LDAP_SUCCESS:
978                                 break;
979
980                         case SLAP_CB_CONTINUE:
981                         case SLAPD_ABANDON:
982                                 return rc;
983
984                         default:
985                                 send_ldap_result( op, rs );
986                                 return rc;
987                         }
988                         break;
989                 }
990         }
991
992         roc = rwm_callback_get( op, rs );
993
994 #ifdef ENABLE_REWRITE
995         rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
996 #else /* ! ENABLE_REWRITE */
997         rc = 1;
998         rc = rwm_op_dn_massage( op, rs, &rc, &roc->ros );
999 #endif /* ! ENABLE_REWRITE */
1000         if ( rc != LDAP_SUCCESS ) {
1001                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1002                 send_ldap_error( op, rs, rc, "extendedDN massage error" );
1003                 return -1;
1004         }
1005
1006         /* TODO: rewrite/map extended data ? ... */
1007         op->o_callback = &roc->cb;
1008
1009         return SLAP_CB_CONTINUE;
1010 }
1011
1012 static int
1013 rwm_matched( Operation *op, SlapReply *rs )
1014 {
1015         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1016         struct ldaprwmap        *rwmap = 
1017                         (struct ldaprwmap *)on->on_bi.bi_private;
1018
1019         struct berval           dn, mdn;
1020         dncookie                dc;
1021         int                     rc;
1022
1023         if ( rs->sr_matched == NULL ) {
1024                 return SLAP_CB_CONTINUE;
1025         }
1026
1027         dc.rwmap = rwmap;
1028 #ifdef ENABLE_REWRITE
1029         dc.conn = op->o_conn;
1030         dc.rs = rs;
1031         dc.ctx = "matchedDN";
1032 #else /* ! ENABLE_REWRITE */
1033         dc.tofrom = 0;
1034         dc.normalized = 0;
1035 #endif /* ! ENABLE_REWRITE */
1036         ber_str2bv( rs->sr_matched, 0, 0, &dn );
1037         mdn = dn;
1038         rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
1039         if ( rc != LDAP_SUCCESS ) {
1040                 rs->sr_err = rc;
1041                 rs->sr_text = "Rewrite error";
1042                 return 1;
1043         }
1044
1045         if ( mdn.bv_val != dn.bv_val ) {
1046                 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
1047                         ch_free( (void *)rs->sr_matched );
1048
1049                 } else {
1050                         rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
1051                 }
1052                 rs->sr_matched = mdn.bv_val;
1053         }
1054         
1055         return SLAP_CB_CONTINUE;
1056 }
1057
1058 static int
1059 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
1060 {
1061         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1062         struct ldaprwmap        *rwmap = 
1063                         (struct ldaprwmap *)on->on_bi.bi_private;
1064
1065         dncookie                dc;
1066         int                     rc;
1067         Attribute               **ap;
1068         int                     isupdate;
1069
1070         /*
1071          * Rewrite the dn attrs, if needed
1072          */
1073         dc.rwmap = rwmap;
1074 #ifdef ENABLE_REWRITE
1075         dc.conn = op->o_conn;
1076         dc.rs = NULL; 
1077 #else /* ! ENABLE_REWRITE */
1078         dc.tofrom = 0;
1079         dc.normalized = 0;
1080 #endif /* ! ENABLE_REWRITE */
1081
1082         /* FIXME: the entries are in the remote mapping form;
1083          * so we need to select those attributes we are willing
1084          * to return, and remap them accordingly */
1085
1086         /* FIXME: in principle, one could map an attribute
1087          * on top of another, which already exists.
1088          * As such, in the end there might exist more than
1089          * one instance of an attribute.
1090          * We should at least check if this occurs, and issue
1091          * an error (because multiple instances of attrs in 
1092          * response are not valid), or merge the values (what
1093          * about duplicate values?) */
1094         isupdate = be_shadow_update( op );
1095         for ( ap = a_first; *ap; ) {
1096                 struct ldapmapping      *mapping = NULL;
1097                 int                     drop_missing;
1098                 int                     last;
1099                 Attribute               *a;
1100
1101                 if ( SLAP_OPATTRS( rs->sr_attr_flags ) && is_at_operational( (*ap)->a_desc->ad_type ) )
1102                 {
1103                         /* go on */ ;
1104                         
1105                 } else {
1106                         if ( op->ors_attrs != NULL && 
1107                                         !SLAP_USERATTRS( rs->sr_attr_flags ) &&
1108                                         !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
1109                         {
1110                                 goto cleanup_attr;
1111                         }
1112
1113                         drop_missing = rwm_mapping( &rwmap->rwm_at,
1114                                         &(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
1115                         if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
1116                         {
1117                                 goto cleanup_attr;
1118                         }
1119
1120                         if ( mapping != NULL ) {
1121                                 (*ap)->a_desc = mapping->m_dst_ad;
1122                         }
1123                 }
1124
1125                 if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
1126                         if ( stripEntryDN ) {
1127                                 /* will be generated by frontend */
1128                                 goto cleanup_attr;
1129                         }
1130                         
1131                 } else if ( !isupdate
1132                         && !get_relax( op )
1133                         && (*ap)->a_desc->ad_type->sat_no_user_mod 
1134                         && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
1135                 {
1136                         goto next_attr;
1137                 }
1138
1139                 for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ )
1140                         /* just count */ ;
1141
1142                 if ( last == 0 ) {
1143                         /* empty? leave it in place because of attrsonly and vlv */
1144                         goto next_attr;
1145                 }
1146                 last--;
1147
1148                 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
1149                                 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
1150                 {
1151                         struct berval   *bv;
1152                         
1153                         for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1154                                 struct berval   mapped;
1155
1156                                 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
1157                                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
1158                                         ch_free( bv[0].bv_val );
1159                                         BER_BVZERO( &bv[0] );
1160                                         if ( &(*ap)->a_vals[last] > &bv[0] ) {
1161                                                 bv[0] = (*ap)->a_vals[last];
1162                                                 BER_BVZERO( &(*ap)->a_vals[last] );
1163                                         }
1164                                         last--;
1165                                         bv--;
1166
1167                                 } else if ( mapped.bv_val != bv[0].bv_val ) {
1168                                         /*
1169                                          * FIXME: after LBER_FREEing
1170                                          * the value is replaced by
1171                                          * ch_alloc'ed memory
1172                                          */
1173                                         ber_bvreplace( &bv[0], &mapped );
1174                                 }
1175                         }
1176
1177                 /*
1178                  * It is necessary to try to rewrite attributes with
1179                  * dn syntax because they might be used in ACLs as
1180                  * members of groups; since ACLs are applied to the
1181                  * rewritten stuff, no dn-based subject clause could
1182                  * be used at the ldap backend side (see
1183                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
1184                  * The problem can be overcome by moving the dn-based
1185                  * ACLs to the target directory server, and letting
1186                  * everything pass thru the ldap backend. */
1187                 /* FIXME: handle distinguishedName-like syntaxes, like
1188                  * nameAndOptionalUID */
1189                 } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
1190                                 || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
1191                 {
1192 #ifdef ENABLE_REWRITE
1193                         dc.ctx = "searchAttrDN";
1194 #endif /* ENABLE_REWRITE */
1195                         rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
1196                         if ( rc != LDAP_SUCCESS ) {
1197                                 goto cleanup_attr;
1198                         }
1199
1200                 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
1201 #ifdef ENABLE_REWRITE
1202                         dc.ctx = "searchAttrDN";
1203 #endif /* ENABLE_REWRITE */
1204                         rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
1205                         if ( rc != LDAP_SUCCESS ) {
1206                                 goto cleanup_attr;
1207                         }
1208                 }
1209
1210                 if ( mapping != NULL ) {
1211                         /* rewrite the attribute description */
1212                         assert( mapping->m_dst_ad != NULL );
1213                         (*ap)->a_desc = mapping->m_dst_ad;
1214                 }
1215
1216 next_attr:;
1217                 ap = &(*ap)->a_next;
1218                 continue;
1219
1220 cleanup_attr:;
1221                 a = *ap;
1222                 *ap = (*ap)->a_next;
1223
1224                 attr_free( a );
1225         }
1226
1227         return 0;
1228 }
1229
1230 static int
1231 rwm_send_entry( Operation *op, SlapReply *rs )
1232 {
1233         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1234         struct ldaprwmap        *rwmap = 
1235                         (struct ldaprwmap *)on->on_bi.bi_private;
1236
1237         Entry                   *e = NULL;
1238         slap_mask_t             flags;
1239         struct berval           dn = BER_BVNULL,
1240                                 ndn = BER_BVNULL;
1241         dncookie                dc;
1242         int                     rc;
1243
1244         assert( rs->sr_entry != NULL );
1245
1246         /*
1247          * Rewrite the dn of the result, if needed
1248          */
1249         dc.rwmap = rwmap;
1250 #ifdef ENABLE_REWRITE
1251         dc.conn = op->o_conn;
1252         dc.rs = NULL; 
1253         dc.ctx = "searchEntryDN";
1254 #else /* ! ENABLE_REWRITE */
1255         dc.tofrom = 0;
1256         dc.normalized = 0;
1257 #endif /* ! ENABLE_REWRITE */
1258
1259         e = rs->sr_entry;
1260         flags = rs->sr_flags;
1261         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
1262                 /* FIXME: all we need to duplicate are:
1263                  * - dn
1264                  * - ndn
1265                  * - attributes that are requested
1266                  * - no values if attrsonly is set
1267                  */
1268
1269                 e = entry_dup( e );
1270                 if ( e == NULL ) {
1271                         rc = LDAP_NO_MEMORY;
1272                         goto fail;
1273                 }
1274
1275                 flags &= ~REP_ENTRY_MUSTRELEASE;
1276                 flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
1277         }
1278
1279         /*
1280          * Note: this may fail if the target host(s) schema differs
1281          * from the one known to the meta, and a DN with unknown
1282          * attributes is returned.
1283          */
1284         dn = e->e_name;
1285         ndn = e->e_nname;
1286         rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
1287         if ( rc != LDAP_SUCCESS ) {
1288                 rc = 1;
1289                 goto fail;
1290         }
1291
1292         if ( e->e_name.bv_val != dn.bv_val ) {
1293                 ch_free( e->e_name.bv_val );
1294                 ch_free( e->e_nname.bv_val );
1295
1296                 e->e_name = dn;
1297                 e->e_nname = ndn;
1298         }
1299
1300         /* TODO: map entry attribute types, objectclasses 
1301          * and dn-valued attribute values */
1302
1303         /* FIXME: the entries are in the remote mapping form;
1304          * so we need to select those attributes we are willing
1305          * to return, and remap them accordingly */
1306         (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
1307
1308         if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1309                 be_entry_release_rw( op, rs->sr_entry, 0 );
1310         }
1311
1312         rs->sr_entry = e;
1313         rs->sr_flags = flags;
1314
1315         return SLAP_CB_CONTINUE;
1316
1317 fail:;
1318         if ( e != NULL && e != rs->sr_entry ) {
1319                 if ( e->e_name.bv_val == dn.bv_val ) {
1320                         BER_BVZERO( &e->e_name );
1321                 }
1322
1323                 if ( e->e_nname.bv_val == ndn.bv_val ) {
1324                         BER_BVZERO( &e->e_nname );
1325                 }
1326
1327                 entry_free( e );
1328         }
1329
1330         if ( !BER_BVISNULL( &dn ) ) {
1331                 ch_free( dn.bv_val );
1332         }
1333
1334         if ( !BER_BVISNULL( &ndn ) ) {
1335                 ch_free( ndn.bv_val );
1336         }
1337
1338         return rc;
1339 }
1340
1341 static int
1342 rwm_operational( Operation *op, SlapReply *rs )
1343 {
1344         /* FIXME: the entries are in the remote mapping form;
1345          * so we need to select those attributes we are willing
1346          * to return, and remap them accordingly */
1347         if ( rs->sr_operational_attrs ) {
1348                 rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
1349         }
1350
1351         return SLAP_CB_CONTINUE;
1352 }
1353
1354 #if 0
1355 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1356  * rewritten for subsequent operations; fine for plain suffixmassage,
1357  * but destroys everything else */
1358 static int
1359 rwm_chk_referrals( Operation *op, SlapReply *rs )
1360 {
1361         slap_overinst           *on = (slap_overinst *) op->o_bd->bd_info;
1362         int                     rc;
1363
1364 #ifdef ENABLE_REWRITE
1365         rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1366 #else /* ! ENABLE_REWRITE */
1367         rc = 1;
1368         rc = rwm_op_dn_massage( op, rs, &rc );
1369 #endif /* ! ENABLE_REWRITE */
1370         if ( rc != LDAP_SUCCESS ) {
1371                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1372                 send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1373                 return -1;
1374         }
1375
1376         return SLAP_CB_CONTINUE;
1377 }
1378 #endif
1379
1380 static int
1381 rwm_rw_config(
1382         BackendDB       *be,
1383         const char      *fname,
1384         int             lineno,
1385         int             argc,
1386         char            **argv )
1387 {
1388 #ifdef ENABLE_REWRITE
1389         slap_overinst           *on = (slap_overinst *) be->bd_info;
1390         struct ldaprwmap        *rwmap = 
1391                         (struct ldaprwmap *)on->on_bi.bi_private;
1392
1393         return rewrite_parse( rwmap->rwm_rw,
1394                                 fname, lineno, argc, argv );
1395
1396 #else /* !ENABLE_REWRITE */
1397         fprintf( stderr, "%s: line %d: rewrite capabilities "
1398                         "are not enabled\n", fname, lineno );
1399 #endif /* !ENABLE_REWRITE */
1400                 
1401         return 0;
1402 }
1403
1404 static int
1405 rwm_suffixmassage_config(
1406         BackendDB       *be,
1407         const char      *fname,
1408         int             lineno,
1409         int             argc,
1410         char            **argv )
1411 {
1412         slap_overinst           *on = (slap_overinst *) be->bd_info;
1413         struct ldaprwmap        *rwmap = 
1414                         (struct ldaprwmap *)on->on_bi.bi_private;
1415
1416         struct berval           bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1417         int                     massaged;
1418 #ifdef ENABLE_REWRITE
1419         int                     rc;
1420 #endif /* ENABLE_REWRITE */
1421                 
1422         /*
1423          * syntax:
1424          * 
1425          *      suffixmassage [<suffix>] <massaged suffix>
1426          *
1427          * the [<suffix>] field must be defined as a valid suffix
1428          * for the current database;
1429          * the <massaged suffix> shouldn't have already been
1430          * defined as a valid suffix for the current server
1431          */
1432         if ( argc == 2 ) {
1433                 if ( be->be_suffix == NULL ) {
1434                         fprintf( stderr, "%s: line %d: "
1435                                        " \"suffixMassage [<suffix>]"
1436                                        " <massaged suffix>\" without "
1437                                        "<suffix> part requires database "
1438                                        "suffix be defined first.\n",
1439                                 fname, lineno );
1440                         return 1;
1441                 }
1442                 bvnc = be->be_suffix[ 0 ];
1443                 massaged = 1;
1444
1445         } else if ( argc == 3 ) {
1446                 ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1447                 massaged = 2;
1448
1449         } else  {
1450                 fprintf( stderr, "%s: line %d: syntax is"
1451                                " \"suffixMassage [<suffix>]"
1452                                " <massaged suffix>\"\n",
1453                         fname, lineno );
1454                 return 1;
1455         }
1456
1457         if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1458                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1459                         fname, lineno, bvnc.bv_val );
1460                 return 1;
1461         }
1462
1463         ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1464         if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1465                 fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
1466                                 fname, lineno, brnc.bv_val );
1467                 free( nvnc.bv_val );
1468                 free( pvnc.bv_val );
1469                 return 1;
1470         }
1471
1472 #ifdef ENABLE_REWRITE
1473         /*
1474          * The suffix massaging is emulated 
1475          * by means of the rewrite capabilities
1476          */
1477         rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1478                         &pvnc, &nvnc, &prnc, &nrnc );
1479         free( nvnc.bv_val );
1480         free( pvnc.bv_val );
1481         free( nrnc.bv_val );
1482         free( prnc.bv_val );
1483
1484         return( rc );
1485
1486 #else /* !ENABLE_REWRITE */
1487         ber_bvarray_add( &rwmap->rwm_suffix_massage, &pvnc );
1488         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nvnc );
1489                 
1490         ber_bvarray_add( &rwmap->rwm_suffix_massage, &prnc );
1491         ber_bvarray_add( &rwmap->rwm_suffix_massage, &nrnc );
1492 #endif /* !ENABLE_REWRITE */
1493
1494         return 0;
1495 }
1496
1497 static int
1498 rwm_m_config(
1499         BackendDB       *be,
1500         const char      *fname,
1501         int             lineno,
1502         int             argc,
1503         char            **argv )
1504 {
1505         slap_overinst           *on = (slap_overinst *) be->bd_info;
1506         struct ldaprwmap        *rwmap = 
1507                         (struct ldaprwmap *)on->on_bi.bi_private;
1508
1509         /* objectclass/attribute mapping */
1510         return rwm_map_config( &rwmap->rwm_oc,
1511                         &rwmap->rwm_at,
1512                         fname, lineno, argc, argv );
1513 }
1514
1515 static int
1516 rwm_response( Operation *op, SlapReply *rs )
1517 {
1518         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
1519         struct ldaprwmap        *rwmap = 
1520                         (struct ldaprwmap *)on->on_bi.bi_private;
1521
1522         int             rc;
1523
1524         if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1525                 return rwm_send_entry( op, rs );
1526         }
1527
1528         switch( op->o_tag ) {
1529         case LDAP_REQ_SEARCH:
1530         case LDAP_REQ_BIND:
1531         case LDAP_REQ_ADD:
1532         case LDAP_REQ_DELETE:
1533         case LDAP_REQ_MODRDN:
1534         case LDAP_REQ_MODIFY:
1535         case LDAP_REQ_COMPARE:
1536         case LDAP_REQ_EXTENDED:
1537                 if ( rs->sr_ref ) {
1538                         dncookie                dc;
1539
1540                         /*
1541                          * Rewrite the dn of the referrals, if needed
1542                          */
1543                         dc.rwmap = rwmap;
1544 #ifdef ENABLE_REWRITE
1545                         dc.conn = op->o_conn;
1546                         dc.rs = NULL; 
1547                         dc.ctx = "referralDN";
1548 #else /* ! ENABLE_REWRITE */
1549                         dc.tofrom = 0;
1550                         dc.normalized = 0;
1551 #endif /* ! ENABLE_REWRITE */
1552                         rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1553                         if ( rc != LDAP_SUCCESS ) {
1554                                 rc = 1;
1555                                 break;
1556                         }
1557                 }
1558                 rc = rwm_matched( op, rs );
1559                 break;
1560
1561         default:
1562                 rc = SLAP_CB_CONTINUE;
1563                 break;
1564         }
1565
1566         return rc;
1567 }
1568
1569 static int
1570 rwm_db_config(
1571         BackendDB       *be,
1572         const char      *fname,
1573         int             lineno,
1574         int             argc,
1575         char            **argv )
1576 {
1577         slap_overinst           *on = (slap_overinst *) be->bd_info;
1578         struct ldaprwmap        *rwmap = 
1579                         (struct ldaprwmap *)on->on_bi.bi_private;
1580
1581         int             rc = 0;
1582         char            *argv0 = NULL;
1583
1584         if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1585                 argv0 = argv[ 0 ];
1586                 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1587         }
1588
1589         if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1590                 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1591
1592         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1593                 rc = rwm_m_config( be, fname, lineno, argc, argv );
1594
1595         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1596                 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1597
1598         } else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
1599                 if ( argc != 2 ) {
1600                         fprintf( stderr,
1601                 "%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
1602                                         fname, lineno );
1603                         return( 1 );
1604                 }
1605
1606                 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1607                         rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F|RWM_F_SUPPORT_T_F_DISCOVER);
1608
1609                 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1610                         rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
1611
1612                 /* TODO: not implemented yet */
1613                 } else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1614                         fprintf( stderr,
1615                 "%s: line %d: \"discover\" not supported yet "
1616                 "in \"t-f-support {no|yes|discover}\".\n",
1617                                         fname, lineno );
1618                         return( 1 );
1619 #if 0
1620                         rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
1621 #endif
1622
1623                 } else {
1624                         fprintf( stderr,
1625         "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1626                                 fname, lineno, argv[ 1 ] );
1627                         return 1;
1628                 }
1629
1630         } else {
1631                 rc = SLAP_CONF_UNKNOWN;
1632         }
1633
1634         if ( argv0 ) {
1635                 argv[ 0 ] = argv0;
1636         }
1637
1638         return rc;
1639 }
1640
1641 static int
1642 rwm_db_init(
1643         BackendDB       *be )
1644 {
1645         slap_overinst           *on = (slap_overinst *) be->bd_info;
1646         struct ldapmapping      *mapping = NULL;
1647         struct ldaprwmap        *rwmap;
1648 #ifdef ENABLE_REWRITE
1649         char                    *rargv[ 3 ];
1650 #endif /* ENABLE_REWRITE */
1651         int                     rc = 0;
1652
1653         rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
1654
1655 #ifdef ENABLE_REWRITE
1656         rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
1657         if ( rwmap->rwm_rw == NULL ) {
1658                 rc = -1;
1659                 goto error_return;
1660         }
1661
1662         /* this rewriteContext by default must be null;
1663          * rules can be added if required */
1664         rargv[ 0 ] = "rewriteContext";
1665         rargv[ 1 ] = "searchFilter";
1666         rargv[ 2 ] = NULL;
1667         rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
1668
1669         rargv[ 0 ] = "rewriteContext";
1670         rargv[ 1 ] = "default";
1671         rargv[ 2 ] = NULL;
1672         rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
1673 #endif /* ENABLE_REWRITE */
1674
1675         if ( rwm_map_init( &rwmap->rwm_oc, &mapping ) != LDAP_SUCCESS ||
1676                         rwm_map_init( &rwmap->rwm_at, &mapping ) != LDAP_SUCCESS )
1677         {
1678                 rc = 1;
1679                 goto error_return;
1680         }
1681
1682 error_return:;
1683         on->on_bi.bi_private = (void *)rwmap;
1684
1685         if ( rc ) {
1686                 (void)rwm_db_destroy( be );
1687         }
1688
1689         return rc;
1690 }
1691
1692 static int
1693 rwm_db_destroy(
1694         BackendDB       *be )
1695 {
1696         slap_overinst   *on = (slap_overinst *) be->bd_info;
1697         int             rc = 0;
1698
1699         if ( on->on_bi.bi_private ) {
1700                 struct ldaprwmap        *rwmap = 
1701                         (struct ldaprwmap *)on->on_bi.bi_private;
1702
1703 #ifdef ENABLE_REWRITE
1704                 if ( rwmap->rwm_rw ) {
1705                         rewrite_info_delete( &rwmap->rwm_rw );
1706                 }
1707 #else /* !ENABLE_REWRITE */
1708                 if ( rwmap->rwm_suffix_massage ) {
1709                         ber_bvarray_free( rwmap->rwm_suffix_massage );
1710                 }
1711 #endif /* !ENABLE_REWRITE */
1712
1713                 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
1714                 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
1715                 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
1716                 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
1717
1718                 ch_free( rwmap );
1719         }
1720
1721         return rc;
1722 }
1723
1724 static slap_overinst rwm = { { NULL } };
1725
1726 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1727 static
1728 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1729 int
1730 rwm_initialize( void )
1731 {
1732         memset( &rwm, 0, sizeof( slap_overinst ) );
1733
1734         rwm.on_bi.bi_type = "rwm";
1735         rwm.on_bi.bi_flags =
1736                 SLAPO_BFLAG_SINGLE |
1737                 0;
1738
1739         rwm.on_bi.bi_db_init = rwm_db_init;
1740         rwm.on_bi.bi_db_config = rwm_db_config;
1741         rwm.on_bi.bi_db_destroy = rwm_db_destroy;
1742
1743         rwm.on_bi.bi_op_bind = rwm_op_bind;
1744         rwm.on_bi.bi_op_search = rwm_op_search;
1745         rwm.on_bi.bi_op_compare = rwm_op_compare;
1746         rwm.on_bi.bi_op_modify = rwm_op_modify;
1747         rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
1748         rwm.on_bi.bi_op_add = rwm_op_add;
1749         rwm.on_bi.bi_op_delete = rwm_op_delete;
1750         rwm.on_bi.bi_op_unbind = rwm_op_unbind;
1751         rwm.on_bi.bi_extended = rwm_extended;
1752
1753         rwm.on_bi.bi_operational = rwm_operational;
1754         rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
1755
1756 #ifdef ENABLE_REWRITE
1757         rwm.on_bi.bi_connection_init = rwm_conn_init;
1758         rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
1759 #endif /* ENABLE_REWRITE */
1760
1761         rwm.on_response = rwm_response;
1762
1763         return overlay_register( &rwm );
1764 }
1765
1766 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
1767 int
1768 init_module( int argc, char *argv[] )
1769 {
1770         return rwm_initialize();
1771 }
1772 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
1773
1774 #endif /* SLAPD_OVER_RWM */