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