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