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