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