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