]> git.sur5r.net Git - openldap/blob - servers/slapd/backover.c
Sync with HEAD
[openldap] / servers / slapd / backover.c
1 /* backover.c - backend overlay routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2005 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 /* Functions to overlay other modules over a backend. */
18
19 #include "portable.h"
20
21 #include <stdio.h>
22
23 #include <ac/string.h>
24 #include <ac/socket.h>
25
26 #define SLAPD_TOOLS
27 #include "slap.h"
28 #include "config.h"
29
30 static slap_overinst *overlays;
31
32 enum db_which { db_open = 0, db_close, db_destroy };
33
34 static int
35 over_db_func(
36         BackendDB *be,
37         enum db_which which
38 )
39 {
40         slap_overinfo *oi = be->bd_info->bi_private;
41         slap_overinst *on = oi->oi_list;
42         BackendInfo *bi_orig = be->bd_info;
43         BI_db_open **func;
44         int rc = 0;
45
46         func = &oi->oi_orig->bi_db_open;
47         if ( func[which] ) {
48                 be->bd_info = oi->oi_orig;
49                 rc = func[which]( be );
50         }
51
52         for (; on && rc == 0; on=on->on_next) {
53                 be->bd_info = &on->on_bi;
54                 func = &on->on_bi.bi_db_open;
55                 if (func[which]) {
56                         rc = func[which]( be );
57                 }
58         }
59         be->bd_info = bi_orig;
60         return rc;
61 }
62
63 static int
64 over_db_config(
65         BackendDB *be,
66         const char *fname,
67         int lineno,
68         int argc,
69         char **argv
70 )
71 {
72         slap_overinfo *oi = be->bd_info->bi_private;
73         slap_overinst *on = oi->oi_list;
74         BackendInfo *bi_orig = be->bd_info;
75         struct ConfigOCs *be_cf_ocs = be->be_cf_ocs;
76         ConfigArgs ca = {0};
77         ConfigTable *ct;
78         int rc = 0;
79
80         if ( oi->oi_orig->bi_db_config ) {
81                 be->bd_info = oi->oi_orig;
82                 be->be_cf_ocs = oi->oi_orig->bi_cf_ocs;
83                 rc = oi->oi_orig->bi_db_config( be, fname, lineno,
84                         argc, argv );
85
86                 if ( be->bd_info != oi->oi_orig ) {
87                         slap_overinfo   *oi2;
88                         slap_overinst   *on2, **onp;
89                         BackendDB       be2 = *be;
90                         int             i;
91
92                         /* a database added an overlay;
93                          * work it around... */
94                         assert( overlay_is_over( be ) );
95                         
96                         oi2 = ( slap_overinfo * )be->bd_info->bi_private;
97                         on2 = oi2->oi_list;
98
99                         /* need to put a uniqueness check here as well;
100                          * note that in principle there could be more than
101                          * one overlay as a result of multiple calls to
102                          * overlay_config() */
103                         be2.bd_info = (BackendInfo *)oi;
104
105                         for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
106                                 if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
107                                         Debug( LDAP_DEBUG_ANY, "over_db_config(): "
108                                                         "warning, freshly added "
109                                                         "overlay #%d \"%s\" is already in list\n",
110                                                         i, (*onp)->on_bi.bi_type, 0 );
111
112                                         /* NOTE: if the overlay already exists,
113                                          * there is no way to merge the results
114                                          * of the configuration that may have 
115                                          * occurred during bi_db_config(); we
116                                          * just issue a warning, and the 
117                                          * administrator should deal with this */
118                                 }
119                         }
120                         *onp = oi->oi_list;
121
122                         oi->oi_list = on2;
123
124                         ch_free( be->bd_info );
125                 }
126
127                 be->bd_info = (BackendInfo *)oi;
128                 if ( rc != SLAP_CONF_UNKNOWN ) return rc;
129         }
130
131         ca.argv = argv;
132         ca.argc = argc;
133         ca.fname = fname;
134         ca.lineno = lineno;
135         ca.be = be;
136         for (; on; on=on->on_next) {
137                 rc = SLAP_CONF_UNKNOWN;
138                 if (on->on_bi.bi_cf_ocs) {
139                         ConfigTable *ct;
140                         ca.bi = &on->on_bi;
141                         ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca );
142                         if ( ct ) {
143                                 rc = config_add_vals( ct, &ca );
144                         }
145                 }
146                 if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) {
147                         be->bd_info = &on->on_bi;
148                         rc = on->on_bi.bi_db_config( be, fname, lineno,
149                                 argc, argv );
150                         if ( rc != SLAP_CONF_UNKNOWN ) break;
151                 }
152         }
153         be->bd_info = bi_orig;
154         be->be_cf_ocs = be_cf_ocs;
155         
156         return rc;
157 }
158
159 static int
160 over_db_open(
161         BackendDB *be
162 )
163 {
164         return over_db_func( be, db_open );
165 }
166
167 static int
168 over_db_close(
169         BackendDB *be
170 )
171 {
172         slap_overinfo *oi = be->bd_info->bi_private;
173         slap_overinst *on = oi->oi_list;
174         BackendInfo *bi_orig = be->bd_info;
175         int rc = 0;
176
177         for (; on && rc == 0; on=on->on_next) {
178                 be->bd_info = &on->on_bi;
179                 if ( be->bd_info->bi_db_close ) {
180                         rc = be->bd_info->bi_db_close( be );
181                 }
182         }
183
184         if ( oi->oi_orig->bi_db_close ) {
185                 be->bd_info = oi->oi_orig;
186                 rc = be->bd_info->bi_db_close( be );
187         }
188
189         be->bd_info = bi_orig;
190         return rc;
191 }
192
193 static int
194 over_db_destroy(
195         BackendDB *be
196 )
197 {
198         slap_overinfo *oi = be->bd_info->bi_private;
199         slap_overinst *on = oi->oi_list, *next;
200         int rc;
201
202         rc = over_db_func( be, db_destroy );
203
204         for (next = on->on_next; on; on=next) {
205                 next = on->on_next;
206                 free( on );
207         }
208         free( oi );
209         return rc;
210 }
211
212 static int
213 over_back_response ( Operation *op, SlapReply *rs )
214 {
215         slap_overinfo *oi = op->o_callback->sc_private;
216         slap_overinst *on = oi->oi_list;
217         int rc = SLAP_CB_CONTINUE;
218         BackendDB *be = op->o_bd, db = *op->o_bd;
219
220         db.be_flags |= SLAP_DBFLAG_OVERLAY;
221         op->o_bd = &db;
222         for (; on; on=on->on_next ) {
223                 if ( on->on_response ) {
224                         db.bd_info = (BackendInfo *)on;
225                         rc = on->on_response( op, rs );
226                         if ( rc != SLAP_CB_CONTINUE ) break;
227                 }
228         }
229         op->o_bd = be;
230         return rc;
231 }
232
233 enum op_which {
234         op_bind = 0,
235         op_unbind,
236         op_search,
237         op_compare,
238         op_modify,
239         op_modrdn,
240         op_add,
241         op_delete,
242         op_abandon,
243         op_cancel,
244         op_extended,
245         op_aux_operational,
246         op_aux_chk_referrals,
247         op_aux_chk_controls,
248         op_last
249 };
250
251 /*
252  * default return code in case of missing backend function
253  * and overlay stack returning SLAP_CB_CONTINUE
254  */
255 static int op_rc[] = {
256         LDAP_UNWILLING_TO_PERFORM,      /* bind */
257         LDAP_UNWILLING_TO_PERFORM,      /* unbind */
258         LDAP_UNWILLING_TO_PERFORM,      /* search */
259         SLAP_CB_CONTINUE,               /* compare; pass to frontend */
260         LDAP_UNWILLING_TO_PERFORM,      /* modify */
261         LDAP_UNWILLING_TO_PERFORM,      /* modrdn */
262         LDAP_UNWILLING_TO_PERFORM,      /* add */
263         LDAP_UNWILLING_TO_PERFORM,      /* delete */
264         LDAP_UNWILLING_TO_PERFORM,      /* abandon */
265         LDAP_UNWILLING_TO_PERFORM,      /* cancel */
266         LDAP_UNWILLING_TO_PERFORM,      /* extended */
267         LDAP_SUCCESS,                   /* aux_operational */
268         LDAP_SUCCESS,                   /* aux_chk_referrals */
269         SLAP_CB_CONTINUE                /* aux_chk_controls; pass to frontend */
270 };
271
272 #ifdef SLAP_OVERLAY_ACCESS
273 static int
274 over_access_allowed(
275         Operation               *op,
276         Entry                   *e,
277         AttributeDescription    *desc,
278         struct berval           *val,
279         slap_access_t           access,
280         AccessControlState      *state,
281         slap_mask_t             *maskp )
282 {
283         slap_overinfo *oi;
284         slap_overinst *on;
285         BackendInfo *bi = op->o_bd->bd_info;
286         BackendDB *be = op->o_bd, db;
287         int rc = SLAP_CB_CONTINUE;
288
289         /* FIXME: used to happen for instance during abandon
290          * when global overlays are used... */
291         assert( op->o_bd != NULL );
292
293         oi = op->o_bd->bd_info->bi_private;
294         on = oi->oi_list;
295
296         for ( ; on; on = on->on_next ) {
297                 if ( on->on_bi.bi_access_allowed ) {
298                         /* NOTE: do not copy the structure until required */
299                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
300                                 db = *op->o_bd;
301                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
302                                 op->o_bd = &db;
303                         }
304
305                         op->o_bd->bd_info = (BackendInfo *)on;
306                         rc = on->on_bi.bi_access_allowed( op, e,
307                                 desc, val, access, state, maskp );
308                         if ( rc != SLAP_CB_CONTINUE ) break;
309                 }
310         }
311
312         if ( rc == SLAP_CB_CONTINUE ) {
313                 BI_access_allowed       *bi_access_allowed;
314
315                 /* if the database structure was changed, o_bd points to a
316                  * copy of the structure; put the original bd_info in place */
317                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
318                         op->o_bd->bd_info = oi->oi_orig;
319                 }
320
321                 if ( oi->oi_orig->bi_access_allowed ) {
322                         bi_access_allowed = oi->oi_orig->bi_access_allowed;
323                 } else {
324                         bi_access_allowed = slap_access_allowed;
325                 }
326
327                 rc = bi_access_allowed( op, e,
328                         desc, val, access, state, maskp );
329         }
330         /* should not fall thru this far without anything happening... */
331         if ( rc == SLAP_CB_CONTINUE ) {
332                 /* access not allowed */
333                 rc = 0;
334         }
335
336         op->o_bd = be;
337         op->o_bd->bd_info = bi;
338
339         return rc;
340 }
341 #endif /* SLAP_OVERLAY_ACCESS */
342
343 static int
344 over_op_func(
345         Operation *op,
346         SlapReply *rs,
347         enum op_which which
348 )
349 {
350         slap_overinfo *oi;
351         slap_overinst *on;
352         BI_op_bind **func;
353         BackendDB *be = op->o_bd, db;
354         slap_callback cb = {NULL, over_back_response, NULL, NULL};
355         int rc = SLAP_CB_CONTINUE;
356
357         /* FIXME: used to happen for instance during abandon
358          * when global overlays are used... */
359         assert( op->o_bd != NULL );
360
361         oi = op->o_bd->bd_info->bi_private;
362         on = oi->oi_list;
363
364         if ( !SLAP_ISOVERLAY( op->o_bd )) {
365                 db = *op->o_bd;
366                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
367                 op->o_bd = &db;
368         }
369         cb.sc_next = op->o_callback;
370         cb.sc_private = oi;
371         op->o_callback = &cb;
372
373         for (; on; on=on->on_next ) {
374                 func = &on->on_bi.bi_op_bind;
375                 if ( func[which] ) {
376                         op->o_bd->bd_info = (BackendInfo *)on;
377                         rc = func[which]( op, rs );
378                         if ( rc != SLAP_CB_CONTINUE ) break;
379                 }
380         }
381
382         func = &oi->oi_orig->bi_op_bind;
383         if ( func[which] && rc == SLAP_CB_CONTINUE ) {
384                 op->o_bd->bd_info = oi->oi_orig;
385                 rc = func[which]( op, rs );
386         }
387         /* should not fall thru this far without anything happening... */
388         if ( rc == SLAP_CB_CONTINUE ) {
389                 rc = op_rc[ which ];
390         }
391
392         /* The underlying backend didn't handle the request, make sure
393          * overlay cleanup is processed.
394          */
395         if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
396                 slap_callback *sc_next;
397                 for ( ; op->o_callback && op->o_callback != cb.sc_next; 
398                         op->o_callback = sc_next ) {
399                         sc_next = op->o_callback->sc_next;
400                         if ( op->o_callback->sc_cleanup ) {
401                                 op->o_callback->sc_cleanup( op, rs );
402                         }
403                 }
404         }
405         op->o_bd = be;
406         op->o_callback = cb.sc_next;
407         return rc;
408 }
409
410 static int
411 over_op_bind( Operation *op, SlapReply *rs )
412 {
413         return over_op_func( op, rs, op_bind );
414 }
415
416 static int
417 over_op_unbind( Operation *op, SlapReply *rs )
418 {
419         return over_op_func( op, rs, op_unbind );
420 }
421
422 static int
423 over_op_search( Operation *op, SlapReply *rs )
424 {
425         return over_op_func( op, rs, op_search );
426 }
427
428 static int
429 over_op_compare( Operation *op, SlapReply *rs )
430 {
431         return over_op_func( op, rs, op_compare );
432 }
433
434 static int
435 over_op_modify( Operation *op, SlapReply *rs )
436 {
437         return over_op_func( op, rs, op_modify );
438 }
439
440 static int
441 over_op_modrdn( Operation *op, SlapReply *rs )
442 {
443         return over_op_func( op, rs, op_modrdn );
444 }
445
446 static int
447 over_op_add( Operation *op, SlapReply *rs )
448 {
449         return over_op_func( op, rs, op_add );
450 }
451
452 static int
453 over_op_delete( Operation *op, SlapReply *rs )
454 {
455         return over_op_func( op, rs, op_delete );
456 }
457
458 static int
459 over_op_abandon( Operation *op, SlapReply *rs )
460 {
461         return over_op_func( op, rs, op_abandon );
462 }
463
464 static int
465 over_op_cancel( Operation *op, SlapReply *rs )
466 {
467         return over_op_func( op, rs, op_cancel );
468 }
469
470 static int
471 over_op_extended( Operation *op, SlapReply *rs )
472 {
473         return over_op_func( op, rs, op_extended );
474 }
475
476 static int
477 over_aux_operational( Operation *op, SlapReply *rs )
478 {
479         return over_op_func( op, rs, op_aux_operational );
480 }
481
482 static int
483 over_aux_chk_referrals( Operation *op, SlapReply *rs )
484 {
485         return over_op_func( op, rs, op_aux_chk_referrals );
486 }
487
488 static int
489 over_aux_chk_controls( Operation *op, SlapReply *rs )
490 {
491         return over_op_func( op, rs, op_aux_chk_controls );
492 }
493
494 static int
495 over_connection_destroy(
496         BackendDB       *bd,
497         Connection      *conn
498 )
499 {
500         slap_overinfo *oi;
501         slap_overinst *on;
502         BackendDB db;
503         int rc = SLAP_CB_CONTINUE;
504
505         /* FIXME: used to happen for instance during abandon
506          * when global overlays are used... */
507         assert( bd != NULL );
508
509         oi = bd->bd_info->bi_private;
510         on = oi->oi_list;
511
512         if ( !SLAP_ISOVERLAY( bd )) {
513                 db = *bd;
514                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
515                 bd = &db;
516         }
517
518         for (; on; on=on->on_next ) {
519                 if ( on->on_bi.bi_connection_destroy ) {
520                         bd->bd_info = (BackendInfo *)on;
521                         rc = on->on_bi.bi_connection_destroy( bd, conn );
522                         if ( rc != SLAP_CB_CONTINUE ) break;
523                 }
524         }
525
526         if ( oi->oi_orig->bi_connection_destroy && rc == SLAP_CB_CONTINUE ) {
527                 bd->bd_info = oi->oi_orig;
528                 rc = oi->oi_orig->bi_connection_destroy( bd, conn );
529         }
530         /* should not fall thru this far without anything happening... */
531         if ( rc == SLAP_CB_CONTINUE ) {
532                 rc = LDAP_UNWILLING_TO_PERFORM;
533         }
534
535         return rc;
536 }
537
538 int
539 overlay_register(
540         slap_overinst *on
541 )
542 {
543         on->on_next = overlays;
544         overlays = on;
545         return 0;
546 }
547
548 /*
549  * iterator on registered overlays; overlay_next( NULL ) returns the first
550  * overlay; * subsequent calls with the previously returned value allow to 
551  * iterate * over the entire list; returns NULL when no more overlays are 
552  * registered.
553  */
554
555 slap_overinst *
556 overlay_next(
557         slap_overinst *on
558 )
559 {
560         if ( on == NULL ) {
561                 return overlays;
562         }
563
564         return on->on_next;
565 }
566
567 /*
568  * returns a specific registered overlay based on the type; NULL if not
569  * registered.
570  */
571
572 slap_overinst *
573 overlay_find( const char *over_type )
574 {
575         slap_overinst *on = overlays;
576
577         assert( over_type );
578
579         for ( ; on; on = on->on_next ) {
580                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
581                         break;
582                 }
583         }
584
585         return on;
586 }
587
588 static const char overtype[] = "over";
589
590 /*
591  * returns TRUE (1) if the database is actually an overlay instance;
592  * FALSE (0) otherwise.
593  */
594
595 int
596 overlay_is_over( BackendDB *be )
597 {
598         return be->bd_info->bi_type == overtype;
599 }
600
601 /*
602  * returns TRUE (1) if the given database is actually an overlay
603  * instance and, somewhere in the list, contains the requested overlay;
604  * FALSE (0) otherwise.
605  */
606
607 int
608 overlay_is_inst( BackendDB *be, const char *over_type )
609 {
610         slap_overinst   *on;
611
612         assert( be );
613
614         if ( !overlay_is_over( be ) ) {
615                 return 0;
616         }
617         
618         on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
619         for ( ; on; on = on->on_next ) {
620                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
621                         return 1;
622                 }
623         }
624
625         return 0;
626 }
627
628 int
629 overlay_register_control( BackendDB *be, const char *oid )
630 {
631         int             rc = 0;
632         int             gotit = 0;
633         int             cid;
634
635         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
636                 return -1;
637         }
638
639         if ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_GLOBAL_OVERLAY ) {
640                 BackendDB *bd;
641                 
642                 /* add to all backends... */
643                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
644                         if ( be == bd ) {
645                                 gotit = 1;
646                         }
647
648                         bd->be_ctrls[ cid ] = 1;
649                         bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
650                 }
651
652         }
653         
654         if ( rc == 0 && !gotit ) {
655                 be->be_ctrls[ cid ] = 1;
656                 be->be_ctrls[ SLAP_MAX_CIDS ] = 1;
657         }
658
659         return rc;
660 }
661
662 void
663 overlay_destroy_one( BackendDB *be, slap_overinst *on )
664 {
665         slap_overinfo *oi = on->on_info;
666         slap_overinst **oidx;
667
668         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
669                 if ( *oidx == on ) {
670                         *oidx = on->on_next;
671                         if ( on->on_bi.bi_db_destroy ) {
672                                 BackendInfo *bi_orig = be->bd_info;
673                                 be->bd_info = (BackendInfo *)on;
674                                 on->on_bi.bi_db_destroy( be );
675                                 be->bd_info = bi_orig;
676                         }
677                         free( on );
678                         break;
679                 }
680         }
681 }
682
683 /* add an overlay to a particular backend. */
684 int
685 overlay_config( BackendDB *be, const char *ov )
686 {
687         slap_overinst *on = NULL, *on2 = NULL;
688         slap_overinfo *oi = NULL;
689         BackendInfo *bi = NULL;
690
691         on = overlay_find( ov );
692         if ( !on ) {
693                 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
694                 return 1;
695         }
696
697         /* If this is the first overlay on this backend, set up the
698          * overlay info structure
699          */
700         if ( !overlay_is_over( be ) ) {
701                 oi = ch_malloc( sizeof( slap_overinfo ) );
702                 oi->oi_orig = be->bd_info;
703                 oi->oi_bi = *be->bd_info;
704
705                 /* NOTE: the first time a global overlay is configured,
706                  * frontendDB gets this flag; it is used later by overlays
707                  * to determine if they're stacked on top of the frontendDB */
708                 if ( oi->oi_orig == frontendDB->bd_info ) {
709                         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
710                 }
711
712                 /* Save a pointer to ourself in bi_private.
713                  */
714                 oi->oi_bi.bi_private = oi;
715                 oi->oi_list = NULL;
716                 bi = (BackendInfo *)oi;
717
718                 bi->bi_type = (char *)overtype;
719
720                 bi->bi_db_config = over_db_config;
721                 bi->bi_db_open = over_db_open;
722                 bi->bi_db_close = over_db_close;
723                 bi->bi_db_destroy = over_db_destroy;
724
725                 bi->bi_op_bind = over_op_bind;
726                 bi->bi_op_unbind = over_op_unbind;
727                 bi->bi_op_search = over_op_search;
728                 bi->bi_op_compare = over_op_compare;
729                 bi->bi_op_modify = over_op_modify;
730                 bi->bi_op_modrdn = over_op_modrdn;
731                 bi->bi_op_add = over_op_add;
732                 bi->bi_op_delete = over_op_delete;
733                 bi->bi_op_abandon = over_op_abandon;
734                 bi->bi_op_cancel = over_op_cancel;
735
736                 bi->bi_extended = over_op_extended;
737
738                 /*
739                  * this is fine because it has the same
740                  * args of the operations; we need to rework
741                  * all the hooks to share the same args
742                  * of the operations...
743                  */
744                 bi->bi_operational = over_aux_operational;
745                 bi->bi_chk_referrals = over_aux_chk_referrals;
746                 bi->bi_chk_controls = over_aux_chk_controls;
747
748 #ifdef SLAP_OVERLAY_ACCESS
749                 /* this has a specific arglist */
750                 bi->bi_access_allowed = over_access_allowed;
751 #endif /* SLAP_OVERLAY_ACCESS */
752                 
753                 bi->bi_connection_destroy = over_connection_destroy;
754
755                 be->bd_info = bi;
756
757         } else {
758                 if ( overlay_is_inst( be, ov ) ) {
759                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
760                                         "warning, overlay \"%s\" "
761                                         "already in list\n", ov, 0, 0 );
762                 }
763
764                 oi = be->bd_info->bi_private;
765         }
766
767         /* Insert new overlay on head of list. Overlays are executed
768          * in reverse of config order...
769          */
770         on2 = ch_calloc( 1, sizeof(slap_overinst) );
771         *on2 = *on;
772         on2->on_info = oi;
773         on2->on_next = oi->oi_list;
774         oi->oi_list = on2;
775
776         /* Any initialization needed? */
777         if ( on->on_bi.bi_db_init ) {
778                 int rc;
779                 be->bd_info = (BackendInfo *)on2;
780                 rc = on2->on_bi.bi_db_init( be );
781                 be->bd_info = (BackendInfo *)oi;
782                 if ( rc ) return rc;
783         }
784
785         return 0;
786 }
787