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