]> git.sur5r.net Git - openldap/blob - servers/slapd/backover.c
f04171640ea89a787a5077fd6f3225e1771f03bc
[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-2011 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 static int
33 over_db_config(
34         BackendDB *be,
35         const char *fname,
36         int lineno,
37         int argc,
38         char **argv
39 )
40 {
41         slap_overinfo *oi = be->bd_info->bi_private;
42         slap_overinst *on = oi->oi_list;
43         BackendInfo *bi_orig = be->bd_info;
44         struct ConfigOCs *be_cf_ocs = be->be_cf_ocs;
45         ConfigArgs ca = {0};
46         int rc = 0;
47
48         if ( oi->oi_orig->bi_db_config ) {
49                 be->bd_info = oi->oi_orig;
50                 be->be_cf_ocs = oi->oi_orig->bi_cf_ocs;
51                 rc = oi->oi_orig->bi_db_config( be, fname, lineno,
52                         argc, argv );
53
54                 if ( be->bd_info != oi->oi_orig ) {
55                         slap_overinfo   *oi2;
56                         slap_overinst   *on2, **onp;
57                         BackendDB       be2 = *be;
58                         int             i;
59
60                         /* a database added an overlay;
61                          * work it around... */
62                         assert( overlay_is_over( be ) );
63                         
64                         oi2 = ( slap_overinfo * )be->bd_info->bi_private;
65                         on2 = oi2->oi_list;
66
67                         /* need to put a uniqueness check here as well;
68                          * note that in principle there could be more than
69                          * one overlay as a result of multiple calls to
70                          * overlay_config() */
71                         be2.bd_info = (BackendInfo *)oi;
72
73                         for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
74                                 if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
75                                         Debug( LDAP_DEBUG_ANY, "over_db_config(): "
76                                                         "warning, freshly added "
77                                                         "overlay #%d \"%s\" is already in list\n",
78                                                         i, (*onp)->on_bi.bi_type, 0 );
79
80                                         /* NOTE: if the overlay already exists,
81                                          * there is no way to merge the results
82                                          * of the configuration that may have 
83                                          * occurred during bi_db_config(); we
84                                          * just issue a warning, and the 
85                                          * administrator should deal with this */
86                                 }
87                         }
88                         *onp = oi->oi_list;
89
90                         oi->oi_list = on2;
91
92                         ch_free( be->bd_info );
93                 }
94
95                 be->bd_info = (BackendInfo *)oi;
96                 if ( rc != SLAP_CONF_UNKNOWN ) return rc;
97         }
98
99         ca.argv = argv;
100         ca.argc = argc;
101         ca.fname = fname;
102         ca.lineno = lineno;
103         ca.be = be;
104         snprintf( ca.log, sizeof( ca.log ), "%s: line %d",
105                         ca.fname, ca.lineno );
106         ca.op = SLAP_CONFIG_ADD;
107         ca.valx = -1;
108
109         for (; on; on=on->on_next) {
110                 rc = SLAP_CONF_UNKNOWN;
111                 if (on->on_bi.bi_cf_ocs) {
112                         ConfigTable *ct;
113                         ca.bi = &on->on_bi;
114                         ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca );
115                         if ( ct ) {
116                                 ca.table = on->on_bi.bi_cf_ocs->co_type;
117                                 rc = config_add_vals( ct, &ca );
118                                 if ( rc != SLAP_CONF_UNKNOWN )
119                                         break;
120                         }
121                 }
122                 if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) {
123                         be->bd_info = &on->on_bi;
124                         rc = on->on_bi.bi_db_config( be, fname, lineno,
125                                 argc, argv );
126                         if ( rc != SLAP_CONF_UNKNOWN ) break;
127                 }
128         }
129         be->bd_info = bi_orig;
130         be->be_cf_ocs = be_cf_ocs;
131         
132         return rc;
133 }
134
135 static int
136 over_db_open(
137         BackendDB *be,
138         ConfigReply *cr
139 )
140 {
141         slap_overinfo *oi = be->bd_info->bi_private;
142         slap_overinst *on = oi->oi_list;
143         BackendDB db = *be;
144         int rc = 0;
145
146         db.be_flags |= SLAP_DBFLAG_OVERLAY;
147         db.bd_info = oi->oi_orig;
148         if ( db.bd_info->bi_db_open ) {
149                 rc = db.bd_info->bi_db_open( &db, cr );
150         }
151
152         for (; on && rc == 0; on=on->on_next) {
153                 db.bd_info = &on->on_bi;
154                 if ( db.bd_info->bi_db_open ) {
155                         rc = db.bd_info->bi_db_open( &db, cr );
156                 }
157         }
158
159         return rc;
160 }
161
162 static int
163 over_db_close(
164         BackendDB *be,
165         ConfigReply *cr
166 )
167 {
168         slap_overinfo *oi = be->bd_info->bi_private;
169         slap_overinst *on = oi->oi_list;
170         BackendInfo *bi_orig = be->bd_info;
171         int rc = 0;
172
173         for (; on && rc == 0; on=on->on_next) {
174                 be->bd_info = &on->on_bi;
175                 if ( be->bd_info->bi_db_close ) {
176                         rc = be->bd_info->bi_db_close( be, cr );
177                 }
178         }
179
180         if ( oi->oi_orig->bi_db_close ) {
181                 be->bd_info = oi->oi_orig;
182                 rc = be->bd_info->bi_db_close( be, cr );
183         }
184
185         be->bd_info = bi_orig;
186         return rc;
187 }
188
189 static int
190 over_db_destroy(
191         BackendDB *be,
192         ConfigReply *cr
193 )
194 {
195         slap_overinfo *oi = be->bd_info->bi_private;
196         slap_overinst *on = oi->oi_list, *next;
197         BackendInfo *bi_orig = be->bd_info;
198         int rc = 0;
199
200         be->bd_info = oi->oi_orig;
201         if ( be->bd_info->bi_db_destroy ) {
202                 rc = be->bd_info->bi_db_destroy( be, cr );
203         }
204
205         for (; on && rc == 0; on=on->on_next) {
206                 be->bd_info = &on->on_bi;
207                 if ( be->bd_info->bi_db_destroy ) {
208                         rc = be->bd_info->bi_db_destroy( be, cr );
209                 }
210         }
211
212         on = oi->oi_list;
213         if ( on ) {
214                 for (next = on->on_next; on; on=next) {
215                         next = on->on_next;
216                         free( on );
217                 }
218         }
219         be->bd_info = bi_orig;
220         free( oi );
221         return rc;
222 }
223
224 static int
225 over_back_response ( Operation *op, SlapReply *rs )
226 {
227         slap_overinfo *oi = op->o_callback->sc_private;
228         slap_overinst *on = oi->oi_list;
229         int rc = SLAP_CB_CONTINUE;
230         BackendDB *be = op->o_bd, db = *op->o_bd;
231
232         db.be_flags |= SLAP_DBFLAG_OVERLAY;
233         op->o_bd = &db;
234         for (; on; on=on->on_next ) {
235                 if ( on->on_response ) {
236                         db.bd_info = (BackendInfo *)on;
237                         rc = on->on_response( op, rs );
238                         if ( rc != SLAP_CB_CONTINUE ) break;
239                 }
240         }
241         /* Bypass the remaining on_response layers, but allow
242          * normal execution to continue.
243          */
244         if ( rc == SLAP_CB_BYPASS )
245                 rc = SLAP_CB_CONTINUE;
246         op->o_bd = be;
247         return rc;
248 }
249
250 static int
251 over_access_allowed(
252         Operation               *op,
253         Entry                   *e,
254         AttributeDescription    *desc,
255         struct berval           *val,
256         slap_access_t           access,
257         AccessControlState      *state,
258         slap_mask_t             *maskp )
259 {
260         slap_overinfo *oi;
261         slap_overinst *on;
262         BackendInfo *bi;
263         BackendDB *be = op->o_bd, db;
264         int rc = SLAP_CB_CONTINUE;
265
266         /* FIXME: used to happen for instance during abandon
267          * when global overlays are used... */
268         assert( op->o_bd != NULL );
269
270         bi = op->o_bd->bd_info;
271         /* Were we invoked on the frontend? */
272         if ( !bi->bi_access_allowed ) {
273                 oi = frontendDB->bd_info->bi_private;
274         } else {
275                 oi = op->o_bd->bd_info->bi_private;
276         }
277         on = oi->oi_list;
278
279         for ( ; on; on = on->on_next ) {
280                 if ( on->on_bi.bi_access_allowed ) {
281                         /* NOTE: do not copy the structure until required */
282                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
283                                 db = *op->o_bd;
284                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
285                                 op->o_bd = &db;
286                         }
287
288                         op->o_bd->bd_info = (BackendInfo *)on;
289                         rc = on->on_bi.bi_access_allowed( op, e,
290                                 desc, val, access, state, maskp );
291                         if ( rc != SLAP_CB_CONTINUE ) break;
292                 }
293         }
294
295         if ( rc == SLAP_CB_CONTINUE ) {
296                 BI_access_allowed       *bi_access_allowed;
297
298                 /* if the database structure was changed, o_bd points to a
299                  * copy of the structure; put the original bd_info in place */
300                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
301                         op->o_bd->bd_info = oi->oi_orig;
302                 }
303
304                 if ( oi->oi_orig->bi_access_allowed ) {
305                         bi_access_allowed = oi->oi_orig->bi_access_allowed;
306                 } else {
307                         bi_access_allowed = slap_access_allowed;
308                 }
309
310                 rc = bi_access_allowed( op, e,
311                         desc, val, access, state, maskp );
312         }
313         /* should not fall thru this far without anything happening... */
314         if ( rc == SLAP_CB_CONTINUE ) {
315                 /* access not allowed */
316                 rc = 0;
317         }
318
319         op->o_bd = be;
320         op->o_bd->bd_info = bi;
321
322         return rc;
323 }
324
325 int
326 overlay_entry_get_ov(
327         Operation               *op,
328         struct berval   *dn,
329         ObjectClass             *oc,
330         AttributeDescription    *ad,
331         int     rw,
332         Entry   **e,
333         slap_overinst *on )
334 {
335         slap_overinfo *oi = on->on_info;
336         BackendDB *be = op->o_bd, db;
337         BackendInfo *bi = op->o_bd->bd_info;
338         int rc = SLAP_CB_CONTINUE;
339
340         for ( ; on; on = on->on_next ) {
341                 if ( on->on_bi.bi_entry_get_rw ) {
342                         /* NOTE: do not copy the structure until required */
343                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
344                                 db = *op->o_bd;
345                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
346                                 op->o_bd = &db;
347                         }
348
349                         op->o_bd->bd_info = (BackendInfo *)on;
350                         rc = on->on_bi.bi_entry_get_rw( op, dn,
351                                 oc, ad, rw, e );
352                         if ( rc != SLAP_CB_CONTINUE ) break;
353                 }
354         }
355
356         if ( rc == SLAP_CB_CONTINUE ) {
357                 /* if the database structure was changed, o_bd points to a
358                  * copy of the structure; put the original bd_info in place */
359                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
360                         op->o_bd->bd_info = oi->oi_orig;
361                 }
362
363                 if ( oi->oi_orig->bi_entry_get_rw ) {
364                         rc = oi->oi_orig->bi_entry_get_rw( op, dn,
365                                 oc, ad, rw, e );
366                 }
367         }
368         /* should not fall thru this far without anything happening... */
369         if ( rc == SLAP_CB_CONTINUE ) {
370                 rc = LDAP_UNWILLING_TO_PERFORM;
371         }
372
373         op->o_bd = be;
374         op->o_bd->bd_info = bi;
375
376         return rc;
377 }
378
379 static int
380 over_entry_get_rw(
381         Operation               *op,
382         struct berval   *dn,
383         ObjectClass             *oc,
384         AttributeDescription    *ad,
385         int     rw,
386         Entry   **e )
387 {
388         slap_overinfo *oi;
389         slap_overinst *on;
390
391         assert( op->o_bd != NULL );
392
393         oi = op->o_bd->bd_info->bi_private;
394         on = oi->oi_list;
395
396         return overlay_entry_get_ov( op, dn, oc, ad, rw, e, on );
397 }
398
399 int
400 overlay_entry_release_ov(
401         Operation       *op,
402         Entry   *e,
403         int rw,
404         slap_overinst *on )
405 {
406         slap_overinfo *oi = on->on_info;
407         BackendDB *be = op->o_bd, db;
408         BackendInfo *bi = op->o_bd->bd_info;
409         int rc = SLAP_CB_CONTINUE;
410
411         for ( ; on; on = on->on_next ) {
412                 if ( on->on_bi.bi_entry_release_rw ) {
413                         /* NOTE: do not copy the structure until required */
414                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
415                                 db = *op->o_bd;
416                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
417                                 op->o_bd = &db;
418                         }
419
420                         op->o_bd->bd_info = (BackendInfo *)on;
421                         rc = on->on_bi.bi_entry_release_rw( op, e, rw );
422                         if ( rc != SLAP_CB_CONTINUE ) break;
423                 }
424         }
425
426         if ( rc == SLAP_CB_CONTINUE ) {
427                 /* if the database structure was changed, o_bd points to a
428                  * copy of the structure; put the original bd_info in place */
429                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
430                         op->o_bd->bd_info = oi->oi_orig;
431                 }
432
433                 if ( oi->oi_orig->bi_entry_release_rw ) {
434                         rc = oi->oi_orig->bi_entry_release_rw( op, e, rw );
435                 }
436         }
437         /* should not fall thru this far without anything happening... */
438         if ( rc == SLAP_CB_CONTINUE ) {
439                 entry_free( e );
440                 rc = 0;
441         }
442
443         op->o_bd = be;
444         op->o_bd->bd_info = bi;
445
446         return rc;
447 }
448
449 static int
450 over_entry_release_rw(
451         Operation       *op,
452         Entry   *e,
453         int rw )
454 {
455         slap_overinfo *oi;
456         slap_overinst *on;
457
458         assert( op->o_bd != NULL );
459
460         oi = op->o_bd->bd_info->bi_private;
461         on = oi->oi_list;
462
463         return overlay_entry_release_ov( op, e, rw, on );
464 }
465
466 static int
467 over_acl_group(
468         Operation               *op,
469         Entry                   *e,
470         struct berval           *gr_ndn,
471         struct berval           *op_ndn,
472         ObjectClass             *group_oc,
473         AttributeDescription    *group_at )
474 {
475         slap_overinfo *oi;
476         slap_overinst *on;
477         BackendInfo *bi = op->o_bd->bd_info;
478         BackendDB *be = op->o_bd, db;
479         int rc = SLAP_CB_CONTINUE;
480
481         /* FIXME: used to happen for instance during abandon
482          * when global overlays are used... */
483         assert( op->o_bd != NULL );
484
485         oi = op->o_bd->bd_info->bi_private;
486         on = oi->oi_list;
487
488         for ( ; on; on = on->on_next ) {
489                 if ( on->on_bi.bi_acl_group ) {
490                         /* NOTE: do not copy the structure until required */
491                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
492                                 db = *op->o_bd;
493                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
494                                 op->o_bd = &db;
495                         }
496
497                         op->o_bd->bd_info = (BackendInfo *)on;
498                         rc = on->on_bi.bi_acl_group( op, e,
499                                 gr_ndn, op_ndn, group_oc, group_at );
500                         if ( rc != SLAP_CB_CONTINUE ) break;
501                 }
502         }
503
504         if ( rc == SLAP_CB_CONTINUE ) {
505                 BI_acl_group            *bi_acl_group;
506
507                 /* if the database structure was changed, o_bd points to a
508                  * copy of the structure; put the original bd_info in place */
509                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
510                         op->o_bd->bd_info = oi->oi_orig;
511                 }
512
513                 if ( oi->oi_orig->bi_acl_group ) {
514                         bi_acl_group = oi->oi_orig->bi_acl_group;
515                 } else {
516                         bi_acl_group = backend_group;
517                 }
518
519                 rc = bi_acl_group( op, e,
520                         gr_ndn, op_ndn, group_oc, group_at );
521         }
522         /* should not fall thru this far without anything happening... */
523         if ( rc == SLAP_CB_CONTINUE ) {
524                 /* access not allowed */
525                 rc = 0;
526         }
527
528         op->o_bd = be;
529         op->o_bd->bd_info = bi;
530
531         return rc;
532 }
533
534 static int
535 over_acl_attribute(
536         Operation               *op,
537         Entry                   *target,
538         struct berval           *entry_ndn,
539         AttributeDescription    *entry_at,
540         BerVarray               *vals,
541         slap_access_t           access )
542 {
543         slap_overinfo *oi;
544         slap_overinst *on;
545         BackendInfo *bi = op->o_bd->bd_info;
546         BackendDB *be = op->o_bd, db;
547         int rc = SLAP_CB_CONTINUE;
548
549         /* FIXME: used to happen for instance during abandon
550          * when global overlays are used... */
551         assert( op->o_bd != NULL );
552
553         oi = op->o_bd->bd_info->bi_private;
554         on = oi->oi_list;
555
556         for ( ; on; on = on->on_next ) {
557                 if ( on->on_bi.bi_acl_attribute ) {
558                         /* NOTE: do not copy the structure until required */
559                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
560                                 db = *op->o_bd;
561                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
562                                 op->o_bd = &db;
563                         }
564
565                         op->o_bd->bd_info = (BackendInfo *)on;
566                         rc = on->on_bi.bi_acl_attribute( op, target,
567                                 entry_ndn, entry_at, vals, access );
568                         if ( rc != SLAP_CB_CONTINUE ) break;
569                 }
570         }
571
572         if ( rc == SLAP_CB_CONTINUE ) {
573                 BI_acl_attribute                *bi_acl_attribute;
574
575                 /* if the database structure was changed, o_bd points to a
576                  * copy of the structure; put the original bd_info in place */
577                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
578                         op->o_bd->bd_info = oi->oi_orig;
579                 }
580
581                 if ( oi->oi_orig->bi_acl_attribute ) {
582                         bi_acl_attribute = oi->oi_orig->bi_acl_attribute;
583                 } else {
584                         bi_acl_attribute = backend_attribute;
585                 }
586
587                 rc = bi_acl_attribute( op, target,
588                         entry_ndn, entry_at, vals, access );
589         }
590         /* should not fall thru this far without anything happening... */
591         if ( rc == SLAP_CB_CONTINUE ) {
592                 /* access not allowed */
593                 rc = 0;
594         }
595
596         op->o_bd = be;
597         op->o_bd->bd_info = bi;
598
599         return rc;
600 }
601
602 int
603 overlay_callback_after_backover( Operation *op, slap_callback *sc, int append )
604 {
605         slap_callback **scp;
606
607         for ( scp = &op->o_callback; *scp != NULL; scp = &(*scp)->sc_next ) {
608                 if ( (*scp)->sc_response == over_back_response ) {
609                         sc->sc_next = (*scp)->sc_next;
610                         (*scp)->sc_next = sc;
611                         return 0;
612                 }
613         }
614
615         if ( append ) {
616                 *scp = sc;
617                 return 0;
618         }
619
620         return 1;
621 }
622
623 /*
624  * default return code in case of missing backend function
625  * and overlay stack returning SLAP_CB_CONTINUE
626  */
627 static int op_rc[ op_last ] = {
628         LDAP_UNWILLING_TO_PERFORM,      /* bind */
629         LDAP_UNWILLING_TO_PERFORM,      /* unbind */
630         LDAP_UNWILLING_TO_PERFORM,      /* search */
631         SLAP_CB_CONTINUE,               /* compare; pass to frontend */
632         LDAP_UNWILLING_TO_PERFORM,      /* modify */
633         LDAP_UNWILLING_TO_PERFORM,      /* modrdn */
634         LDAP_UNWILLING_TO_PERFORM,      /* add */
635         LDAP_UNWILLING_TO_PERFORM,      /* delete */
636         LDAP_UNWILLING_TO_PERFORM,      /* abandon */
637         LDAP_UNWILLING_TO_PERFORM,      /* cancel */
638         LDAP_UNWILLING_TO_PERFORM,      /* extended */
639         LDAP_SUCCESS,                   /* aux_operational */
640         LDAP_SUCCESS,                   /* aux_chk_referrals */
641         SLAP_CB_CONTINUE                /* aux_chk_controls; pass to frontend */
642 };
643
644 int overlay_op_walk(
645         Operation *op,
646         SlapReply *rs,
647         slap_operation_t which,
648         slap_overinfo *oi,
649         slap_overinst *on
650 )
651 {
652         BI_op_bind **func;
653         int rc = SLAP_CB_CONTINUE;
654
655         for (; on; on=on->on_next ) {
656                 func = &on->on_bi.bi_op_bind;
657                 if ( func[which] ) {
658                         op->o_bd->bd_info = (BackendInfo *)on;
659                         rc = func[which]( op, rs );
660                         if ( rc != SLAP_CB_CONTINUE ) break;
661                 }
662         }
663         if ( rc == SLAP_CB_BYPASS )
664                 rc = SLAP_CB_CONTINUE;
665
666         func = &oi->oi_orig->bi_op_bind;
667         if ( func[which] && rc == SLAP_CB_CONTINUE ) {
668                 op->o_bd->bd_info = oi->oi_orig;
669                 rc = func[which]( op, rs );
670         }
671         /* should not fall thru this far without anything happening... */
672         if ( rc == SLAP_CB_CONTINUE ) {
673                 rc = op_rc[ which ];
674         }
675
676         /* The underlying backend didn't handle the request, make sure
677          * overlay cleanup is processed.
678          */
679         if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
680                 slap_callback *sc_next;
681                 for ( ; op->o_callback && op->o_callback->sc_response !=
682                         over_back_response; op->o_callback = sc_next ) {
683                         sc_next = op->o_callback->sc_next;
684                         if ( op->o_callback->sc_cleanup ) {
685                                 op->o_callback->sc_cleanup( op, rs );
686                         }
687                 }
688         }
689         return rc;
690 }
691
692 static int
693 over_op_func(
694         Operation *op,
695         SlapReply *rs,
696         slap_operation_t which
697 )
698 {
699         slap_overinfo *oi;
700         slap_overinst *on;
701         BackendDB *be = op->o_bd, db;
702         slap_callback cb = {NULL, over_back_response, NULL, NULL}, **sc;
703         int rc = SLAP_CB_CONTINUE;
704
705         /* FIXME: used to happen for instance during abandon
706          * when global overlays are used... */
707         assert( op->o_bd != NULL );
708
709         oi = op->o_bd->bd_info->bi_private;
710         on = oi->oi_list;
711
712         if ( !SLAP_ISOVERLAY( op->o_bd )) {
713                 db = *op->o_bd;
714                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
715                 op->o_bd = &db;
716         }
717         cb.sc_next = op->o_callback;
718         cb.sc_private = oi;
719         op->o_callback = &cb;
720
721         rc = overlay_op_walk( op, rs, which, oi, on );
722         for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) {
723                 if ( *sc == &cb ) {
724                         *sc = cb.sc_next;
725                         break;
726                 }
727         }
728
729         op->o_bd = be;
730         return rc;
731 }
732
733 static int
734 over_op_bind( Operation *op, SlapReply *rs )
735 {
736         return over_op_func( op, rs, op_bind );
737 }
738
739 static int
740 over_op_unbind( Operation *op, SlapReply *rs )
741 {
742         return over_op_func( op, rs, op_unbind );
743 }
744
745 static int
746 over_op_search( Operation *op, SlapReply *rs )
747 {
748         return over_op_func( op, rs, op_search );
749 }
750
751 static int
752 over_op_compare( Operation *op, SlapReply *rs )
753 {
754         return over_op_func( op, rs, op_compare );
755 }
756
757 static int
758 over_op_modify( Operation *op, SlapReply *rs )
759 {
760         return over_op_func( op, rs, op_modify );
761 }
762
763 static int
764 over_op_modrdn( Operation *op, SlapReply *rs )
765 {
766         return over_op_func( op, rs, op_modrdn );
767 }
768
769 static int
770 over_op_add( Operation *op, SlapReply *rs )
771 {
772         return over_op_func( op, rs, op_add );
773 }
774
775 static int
776 over_op_delete( Operation *op, SlapReply *rs )
777 {
778         return over_op_func( op, rs, op_delete );
779 }
780
781 static int
782 over_op_abandon( Operation *op, SlapReply *rs )
783 {
784         return over_op_func( op, rs, op_abandon );
785 }
786
787 static int
788 over_op_cancel( Operation *op, SlapReply *rs )
789 {
790         return over_op_func( op, rs, op_cancel );
791 }
792
793 static int
794 over_op_extended( Operation *op, SlapReply *rs )
795 {
796         return over_op_func( op, rs, op_extended );
797 }
798
799 static int
800 over_aux_operational( Operation *op, SlapReply *rs )
801 {
802         return over_op_func( op, rs, op_aux_operational );
803 }
804
805 static int
806 over_aux_chk_referrals( Operation *op, SlapReply *rs )
807 {
808         return over_op_func( op, rs, op_aux_chk_referrals );
809 }
810
811 static int
812 over_aux_chk_controls( Operation *op, SlapReply *rs )
813 {
814         return over_op_func( op, rs, op_aux_chk_controls );
815 }
816
817 enum conn_which {
818         conn_init = 0,
819         conn_destroy,
820         conn_last
821 };
822
823 static int
824 over_connection_func(
825         BackendDB       *bd,
826         Connection      *conn,
827         enum conn_which which
828 )
829 {
830         slap_overinfo           *oi;
831         slap_overinst           *on;
832         BackendDB               db;
833         int                     rc = SLAP_CB_CONTINUE;
834         BI_connection_init      **func;
835
836         /* FIXME: used to happen for instance during abandon
837          * when global overlays are used... */
838         assert( bd != NULL );
839
840         oi = bd->bd_info->bi_private;
841         on = oi->oi_list;
842
843         if ( !SLAP_ISOVERLAY( bd ) ) {
844                 db = *bd;
845                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
846                 bd = &db;
847         }
848
849         for ( ; on; on = on->on_next ) {
850                 func = &on->on_bi.bi_connection_init;
851                 if ( func[ which ] ) {
852                         bd->bd_info = (BackendInfo *)on;
853                         rc = func[ which ]( bd, conn );
854                         if ( rc != SLAP_CB_CONTINUE ) break;
855                 }
856         }
857
858         func = &oi->oi_orig->bi_connection_init;
859         if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
860                 bd->bd_info = oi->oi_orig;
861                 rc = func[ which ]( bd, conn );
862         }
863         /* should not fall thru this far without anything happening... */
864         if ( rc == SLAP_CB_CONTINUE ) {
865                 rc = LDAP_UNWILLING_TO_PERFORM;
866         }
867
868         return rc;
869 }
870
871 static int
872 over_connection_init(
873         BackendDB       *bd,
874         Connection      *conn
875 )
876 {
877         return over_connection_func( bd, conn, conn_init );
878 }
879
880 static int
881 over_connection_destroy(
882         BackendDB       *bd,
883         Connection      *conn
884 )
885 {
886         return over_connection_func( bd, conn, conn_destroy );
887 }
888
889 int
890 overlay_register(
891         slap_overinst *on
892 )
893 {
894         slap_overinst   *tmp;
895
896         /* FIXME: check for duplicates? */
897         for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) {
898                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) {
899                         Debug( LDAP_DEBUG_ANY,
900                                 "overlay_register(\"%s\"): "
901                                 "name already in use.\n",
902                                 on->on_bi.bi_type, 0, 0 );
903                         return -1;
904                 }
905
906                 if ( on->on_bi.bi_obsolete_names != NULL ) {
907                         int     i;
908
909                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
910                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) {
911                                         Debug( LDAP_DEBUG_ANY,
912                                                 "overlay_register(\"%s\"): "
913                                                 "obsolete name \"%s\" already in use "
914                                                 "by overlay \"%s\".\n",
915                                                 on->on_bi.bi_type,
916                                                 on->on_bi.bi_obsolete_names[ i ],
917                                                 tmp->on_bi.bi_type );
918                                         return -1;
919                                 }
920                         }
921                 }
922
923                 if ( tmp->on_bi.bi_obsolete_names != NULL ) {
924                         int     i;
925
926                         for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
927                                 int     j;
928
929                                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
930                                         Debug( LDAP_DEBUG_ANY,
931                                                 "overlay_register(\"%s\"): "
932                                                 "name already in use "
933                                                 "as obsolete by overlay \"%s\".\n",
934                                                 on->on_bi.bi_type,
935                                                 tmp->on_bi.bi_obsolete_names[ i ], 0 );
936                                         return -1;
937                                 }
938
939                                 if ( on->on_bi.bi_obsolete_names != NULL ) {
940                                         for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) {
941                                                 if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
942                                                         Debug( LDAP_DEBUG_ANY,
943                                                                 "overlay_register(\"%s\"): "
944                                                                 "obsolete name \"%s\" already in use "
945                                                                 "as obsolete by overlay \"%s\".\n",
946                                                                 on->on_bi.bi_type,
947                                                                 on->on_bi.bi_obsolete_names[ j ],
948                                                                 tmp->on_bi.bi_type );
949                                                         return -1;
950                                                 }
951                                         }
952                                 }
953                         }
954                 }
955         }
956
957         on->on_next = overlays;
958         overlays = on;
959         return 0;
960 }
961
962 /*
963  * iterator on registered overlays; overlay_next( NULL ) returns the first
964  * overlay; subsequent calls with the previously returned value allow to 
965  * iterate over the entire list; returns NULL when no more overlays are 
966  * registered.
967  */
968
969 slap_overinst *
970 overlay_next(
971         slap_overinst *on
972 )
973 {
974         if ( on == NULL ) {
975                 return overlays;
976         }
977
978         return on->on_next;
979 }
980
981 /*
982  * returns a specific registered overlay based on the type; NULL if not
983  * registered.
984  */
985
986 slap_overinst *
987 overlay_find( const char *over_type )
988 {
989         slap_overinst *on = overlays;
990
991         assert( over_type != NULL );
992
993         for ( ; on; on = on->on_next ) {
994                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
995                         goto foundit;
996                 }
997
998                 if ( on->on_bi.bi_obsolete_names != NULL ) {
999                         int     i;
1000
1001                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
1002                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) {
1003                                         Debug( LDAP_DEBUG_ANY,
1004                                                 "overlay_find(\"%s\"): "
1005                                                 "obsolete name for \"%s\".\n",
1006                                                 on->on_bi.bi_obsolete_names[ i ],
1007                                                 on->on_bi.bi_type, 0 );
1008                                         goto foundit;
1009                                 }
1010                         }
1011                 }
1012         }
1013
1014 foundit:;
1015         return on;
1016 }
1017
1018 static const char overtype[] = "over";
1019
1020 /*
1021  * returns TRUE (1) if the database is actually an overlay instance;
1022  * FALSE (0) otherwise.
1023  */
1024
1025 int
1026 overlay_is_over( BackendDB *be )
1027 {
1028         return be->bd_info->bi_type == overtype;
1029 }
1030
1031 /*
1032  * returns TRUE (1) if the given database is actually an overlay
1033  * instance and, somewhere in the list, contains the requested overlay;
1034  * FALSE (0) otherwise.
1035  */
1036
1037 int
1038 overlay_is_inst( BackendDB *be, const char *over_type )
1039 {
1040         slap_overinst   *on;
1041
1042         assert( be != NULL );
1043
1044         if ( !overlay_is_over( be ) ) {
1045                 return 0;
1046         }
1047         
1048         on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
1049         for ( ; on; on = on->on_next ) {
1050                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
1051                         return 1;
1052                 }
1053         }
1054
1055         return 0;
1056 }
1057
1058 int
1059 overlay_register_control( BackendDB *be, const char *oid )
1060 {
1061         int             gotit = 0;
1062         int             cid;
1063
1064         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
1065                 return -1;
1066         }
1067
1068         if ( SLAP_ISGLOBALOVERLAY( be ) ) {
1069                 BackendDB *bd;
1070                 
1071                 /* add to all backends... */
1072                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
1073                         if ( bd == be->bd_self ) {
1074                                 gotit = 1;
1075                         }
1076
1077                         /* overlays can be instanciated multiple times, use
1078                          * be_ctrls[ cid ] as an instance counter, so that the
1079                          * overlay's controls are only really disabled after the
1080                          * last instance called overlay_register_control() */
1081                         bd->be_ctrls[ cid ]++;
1082                         bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1083                 }
1084
1085         }
1086         
1087         if ( !gotit ) {
1088                 /* overlays can be instanciated multiple times, use
1089                  * be_ctrls[ cid ] as an instance counter, so that the
1090                  * overlay's controls are only really unregistered after the
1091                  * last instance called overlay_register_control() */
1092                 be->bd_self->be_ctrls[ cid ]++;
1093                 be->bd_self->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1094         }
1095
1096         return 0;
1097 }
1098
1099 #ifdef SLAP_CONFIG_DELETE
1100 void
1101 overlay_unregister_control( BackendDB *be, const char *oid )
1102 {
1103         int             gotit = 0;
1104         int             cid;
1105
1106         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
1107                 return;
1108         }
1109
1110         if ( SLAP_ISGLOBALOVERLAY( be ) ) {
1111                 BackendDB *bd;
1112
1113                 /* remove from all backends... */
1114                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
1115                         if ( bd == be->bd_self ) {
1116                                 gotit = 1;
1117                         }
1118
1119                         bd->be_ctrls[ cid ]--;
1120                 }
1121         }
1122
1123         if ( !gotit ) {
1124                 be->bd_self->be_ctrls[ cid ]--;
1125         }
1126 }
1127 #endif /* SLAP_CONFIG_DELETE */
1128
1129 void
1130 overlay_destroy_one( BackendDB *be, slap_overinst *on )
1131 {
1132         slap_overinfo *oi = on->on_info;
1133         slap_overinst **oidx;
1134
1135         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1136                 if ( *oidx == on ) {
1137                         *oidx = on->on_next;
1138                         if ( on->on_bi.bi_db_destroy ) {
1139                                 BackendInfo *bi_orig = be->bd_info;
1140                                 be->bd_info = (BackendInfo *)on;
1141                                 on->on_bi.bi_db_destroy( be, NULL );
1142                                 be->bd_info = bi_orig;
1143                         }
1144                         free( on );
1145                         break;
1146                 }
1147         }
1148 }
1149
1150 #ifdef SLAP_CONFIG_DELETE
1151 typedef struct ov_remove_ctx {
1152         BackendDB *be;
1153         slap_overinst *on;
1154 } ov_remove_ctx;
1155
1156 int
1157 overlay_remove_cb( Operation *op, SlapReply *rs )
1158 {
1159         ov_remove_ctx *rm_ctx = (ov_remove_ctx*) op->o_callback->sc_private;
1160         BackendInfo *bi_orig = rm_ctx->be->bd_info;
1161
1162         rm_ctx->be->bd_info = (BackendInfo*) rm_ctx->on;
1163
1164         if ( rm_ctx->on->on_bi.bi_db_close ) {
1165                 rm_ctx->on->on_bi.bi_db_close( rm_ctx->be, NULL );
1166         }
1167         if ( rm_ctx->on->on_bi.bi_db_destroy ) {
1168                 rm_ctx->on->on_bi.bi_db_destroy( rm_ctx->be, NULL );
1169         }
1170
1171         /* clean up after removing last overlay */
1172         if ( ! rm_ctx->on->on_info->oi_list ) {
1173                 /* reset db flags and bd_info to orig */
1174                 SLAP_DBFLAGS( rm_ctx->be ) &= ~SLAP_DBFLAG_GLOBAL_OVERLAY;
1175                 rm_ctx->be->bd_info = rm_ctx->on->on_info->oi_orig;
1176                 ch_free(rm_ctx->on->on_info);
1177         } else {
1178                 rm_ctx->be->bd_info = bi_orig;
1179         }
1180         free( rm_ctx->on );
1181         op->o_tmpfree(rm_ctx, op->o_tmpmemctx);
1182         return SLAP_CB_CONTINUE;
1183 }
1184
1185 void
1186 overlay_remove( BackendDB *be, slap_overinst *on, Operation *op )
1187 {
1188         slap_overinfo *oi = on->on_info;
1189         slap_overinst **oidx;
1190         ov_remove_ctx *rm_ctx;
1191         slap_callback *rm_cb, *cb;
1192
1193         /* remove overlay from oi_list */
1194         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1195                 if ( *oidx == on ) {
1196                         *oidx = on->on_next;
1197                         break;
1198                 }
1199         }
1200
1201         /* The db_close and db_destroy handlers to cleanup a release
1202          * the overlay's resources are called from the cleanup callback
1203          */
1204         rm_ctx = op->o_tmpalloc( sizeof( ov_remove_ctx ), op->o_tmpmemctx );
1205         rm_ctx->be = be;
1206         rm_ctx->on = on;
1207
1208         rm_cb = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
1209         rm_cb->sc_next = NULL;
1210         rm_cb->sc_cleanup = overlay_remove_cb;
1211         rm_cb->sc_response = NULL;
1212         rm_cb->sc_private = (void*) rm_ctx;
1213
1214         /* Append callback to the end of the list */
1215         for ( cb = op->o_callback; cb->sc_next; cb = cb->sc_next );
1216         cb->sc_next = rm_cb;
1217 }
1218 #endif /* SLAP_CONFIG_DELETE */
1219
1220 void
1221 overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev,
1222         int idx )
1223 {
1224         slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1225
1226         if ( idx == -1 ) {
1227                 on2->on_next = oi->oi_list;
1228                 oi->oi_list = on2;
1229         } else {
1230                 int i;
1231                 slap_overinst *on, *otmp1 = NULL, *otmp2;
1232
1233                 /* Since the list is in reverse order and is singly linked,
1234                  * we reverse it to find the idx insertion point. Adding
1235                  * on overlay at a specific point should be a pretty
1236                  * infrequent occurrence.
1237                  */
1238                 for ( on = oi->oi_list; on; on=otmp2 ) {
1239                         otmp2 = on->on_next;
1240                         on->on_next = otmp1;
1241                         otmp1 = on;
1242                 }
1243                 oi->oi_list = NULL;
1244                 /* advance to insertion point */
1245                 for ( i=0, on = otmp1; i<idx; i++ ) {
1246                         otmp1 = on->on_next;
1247                         on->on_next = oi->oi_list;
1248                         oi->oi_list = on;
1249                 }
1250                 /* insert */
1251                 on2->on_next = oi->oi_list;
1252                 oi->oi_list = on2;
1253                 if ( otmp1 ) {
1254                         *prev = &otmp1->on_next;
1255                         /* replace remainder of list */
1256                         for ( on=otmp1; on; on=otmp1 ) {
1257                                 otmp1 = on->on_next;
1258                                 on->on_next = oi->oi_list;
1259                                 oi->oi_list = on;
1260                         }
1261                 }
1262         }
1263 }
1264
1265 void
1266 overlay_move( BackendDB *be, slap_overinst *on, int idx )
1267 {
1268         slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1269         slap_overinst **onp;
1270
1271         for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) {
1272                 if ( *onp == on ) {
1273                         *onp = on->on_next;
1274                         break;
1275                 }
1276         }
1277         overlay_insert( be, on, &onp, idx );
1278 }
1279
1280 /* add an overlay to a particular backend. */
1281 int
1282 overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res, ConfigReply *cr )
1283 {
1284         slap_overinst *on = NULL, *on2 = NULL, **prev;
1285         slap_overinfo *oi = NULL;
1286         BackendInfo *bi = NULL;
1287
1288         if ( res )
1289                 *res = NULL;
1290
1291         on = overlay_find( ov );
1292         if ( !on ) {
1293                 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
1294                 return 1;
1295         }
1296
1297         /* If this is the first overlay on this backend, set up the
1298          * overlay info structure
1299          */
1300         if ( !overlay_is_over( be ) ) {
1301                 int     isglobal = 0;
1302
1303                 /* NOTE: the first time a global overlay is configured,
1304                  * frontendDB gets this flag; it is used later by overlays
1305                  * to determine if they're stacked on top of the frontendDB */
1306                 if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) {
1307                         isglobal = 1;
1308                         if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) {
1309                                 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1310                                         "overlay \"%s\" cannot be global.\n",
1311                                         ov, 0, 0 );
1312                                 return 1;
1313                         }
1314
1315                 } else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) {
1316                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1317                                 "overlay \"%s\" can only be global.\n",
1318                                 ov, 0, 0 );
1319                         return 1;
1320                 }
1321
1322                 oi = ch_malloc( sizeof( slap_overinfo ) );
1323                 oi->oi_orig = be->bd_info;
1324                 oi->oi_bi = *be->bd_info;
1325                 oi->oi_origdb = be;
1326
1327                 if ( isglobal ) {
1328                         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
1329                 }
1330
1331                 /* Save a pointer to ourself in bi_private.
1332                  */
1333                 oi->oi_bi.bi_private = oi;
1334                 oi->oi_list = NULL;
1335                 bi = (BackendInfo *)oi;
1336
1337                 bi->bi_type = (char *)overtype;
1338
1339                 bi->bi_db_config = over_db_config;
1340                 bi->bi_db_open = over_db_open;
1341                 bi->bi_db_close = over_db_close;
1342                 bi->bi_db_destroy = over_db_destroy;
1343
1344                 bi->bi_op_bind = over_op_bind;
1345                 bi->bi_op_unbind = over_op_unbind;
1346                 bi->bi_op_search = over_op_search;
1347                 bi->bi_op_compare = over_op_compare;
1348                 bi->bi_op_modify = over_op_modify;
1349                 bi->bi_op_modrdn = over_op_modrdn;
1350                 bi->bi_op_add = over_op_add;
1351                 bi->bi_op_delete = over_op_delete;
1352                 bi->bi_op_abandon = over_op_abandon;
1353                 bi->bi_op_cancel = over_op_cancel;
1354
1355                 bi->bi_extended = over_op_extended;
1356
1357                 /*
1358                  * this is fine because it has the same
1359                  * args of the operations; we need to rework
1360                  * all the hooks to share the same args
1361                  * of the operations...
1362                  */
1363                 bi->bi_operational = over_aux_operational;
1364                 bi->bi_chk_referrals = over_aux_chk_referrals;
1365                 bi->bi_chk_controls = over_aux_chk_controls;
1366
1367                 /* these have specific arglists */
1368                 bi->bi_entry_get_rw = over_entry_get_rw;
1369                 bi->bi_entry_release_rw = over_entry_release_rw;
1370                 bi->bi_access_allowed = over_access_allowed;
1371                 bi->bi_acl_group = over_acl_group;
1372                 bi->bi_acl_attribute = over_acl_attribute;
1373                 
1374                 bi->bi_connection_init = over_connection_init;
1375                 bi->bi_connection_destroy = over_connection_destroy;
1376
1377                 be->bd_info = bi;
1378
1379         } else {
1380                 if ( overlay_is_inst( be, ov ) ) {
1381                         if ( SLAPO_SINGLE( be ) ) {
1382                                 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1383                                         "overlay \"%s\" already in list\n",
1384                                         ov, 0, 0 );
1385                                 return 1;
1386                         }
1387                 }
1388
1389                 oi = be->bd_info->bi_private;
1390         }
1391
1392         /* Insert new overlay into list. By default overlays are
1393          * added to head of list and executed in LIFO order.
1394          */
1395         on2 = ch_calloc( 1, sizeof(slap_overinst) );
1396         *on2 = *on;
1397         on2->on_info = oi;
1398
1399         prev = &oi->oi_list;
1400         /* Do we need to find the insertion point? */
1401         if ( idx >= 0 ) {
1402                 int i;
1403
1404                 /* count current overlays */
1405                 for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ );
1406
1407                 /* are we just appending a new one? */
1408                 if ( idx >= i )
1409                         idx = -1;
1410         }
1411         overlay_insert( be, on2, &prev, idx );
1412
1413         /* Any initialization needed? */
1414         if ( on2->on_bi.bi_db_init ) {
1415                 int rc;
1416                 be->bd_info = (BackendInfo *)on2;
1417                 rc = on2->on_bi.bi_db_init( be, cr);
1418                 be->bd_info = (BackendInfo *)oi;
1419                 if ( rc ) {
1420                         *prev = on2->on_next;
1421                         ch_free( on2 );
1422                         on2 = NULL;
1423                         return rc;
1424                 }
1425         }
1426
1427         if ( res )
1428                 *res = &on2->on_bi;
1429
1430         return 0;
1431 }
1432