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