]> git.sur5r.net Git - openldap/blob - servers/slapd/backover.c
ITS#8752 make sure all cleanups are called in overlay_op_walk
[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_next ) {
720                         sc_next = op->o_callback->sc_next;
721                         if ( op->o_callback->sc_cleanup ) {
722                                 op->o_callback->sc_cleanup( op, rs );
723                         }
724                 }
725         }
726         return rc;
727 }
728
729 static int
730 over_op_func(
731         Operation *op,
732         SlapReply *rs,
733         slap_operation_t which
734 )
735 {
736         slap_overinfo *oi;
737         slap_overinst *on;
738         BackendDB *be = op->o_bd, db;
739         slap_callback **sc;
740         slap_callback *cb;
741         int rc = SLAP_CB_CONTINUE;
742
743         /* FIXME: used to happen for instance during abandon
744          * when global overlays are used... */
745         assert( op->o_bd != NULL );
746
747         oi = op->o_bd->bd_info->bi_private;
748         on = oi->oi_list;
749
750         if ( !SLAP_ISOVERLAY( op->o_bd )) {
751                 db = *op->o_bd;
752                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
753                 op->o_bd = &db;
754         }
755         if ( op->o_tag != LDAP_REQ_ABANDON && op->o_tag != LDAP_REQ_UNBIND ) {
756                 cb = (slap_callback *)op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
757                 cb->sc_cleanup = NULL;
758                 cb->sc_response = over_back_response;
759                 cb->sc_writewait = NULL;
760                 cb->sc_next = op->o_callback;
761                 cb->sc_private = oi;
762                 op->o_callback = cb;
763         }
764
765         rc = overlay_op_walk( op, rs, which, oi, on );
766         if ( rc != SLAPD_ASYNCOP && op->o_tag != LDAP_REQ_ABANDON && op->o_tag != LDAP_REQ_UNBIND ) {
767                 for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) {
768                         if ( *sc == cb ) {
769                                 *sc = cb->sc_next;
770                                 op->o_tmpfree( cb, op->o_tmpmemctx );
771                                 break;
772                         }
773                 }
774         }
775
776         op->o_bd = be;
777         return rc;
778 }
779
780 static int
781 over_op_bind( Operation *op, SlapReply *rs )
782 {
783         return over_op_func( op, rs, op_bind );
784 }
785
786 static int
787 over_op_unbind( Operation *op, SlapReply *rs )
788 {
789         return over_op_func( op, rs, op_unbind );
790 }
791
792 static int
793 over_op_search( Operation *op, SlapReply *rs )
794 {
795         return over_op_func( op, rs, op_search );
796 }
797
798 static int
799 over_op_compare( Operation *op, SlapReply *rs )
800 {
801         return over_op_func( op, rs, op_compare );
802 }
803
804 static int
805 over_op_modify( Operation *op, SlapReply *rs )
806 {
807         return over_op_func( op, rs, op_modify );
808 }
809
810 static int
811 over_op_modrdn( Operation *op, SlapReply *rs )
812 {
813         return over_op_func( op, rs, op_modrdn );
814 }
815
816 static int
817 over_op_add( Operation *op, SlapReply *rs )
818 {
819         return over_op_func( op, rs, op_add );
820 }
821
822 static int
823 over_op_delete( Operation *op, SlapReply *rs )
824 {
825         return over_op_func( op, rs, op_delete );
826 }
827
828 static int
829 over_op_abandon( Operation *op, SlapReply *rs )
830 {
831         return over_op_func( op, rs, op_abandon );
832 }
833
834 static int
835 over_op_cancel( Operation *op, SlapReply *rs )
836 {
837         return over_op_func( op, rs, op_cancel );
838 }
839
840 static int
841 over_op_extended( Operation *op, SlapReply *rs )
842 {
843         return over_op_func( op, rs, op_extended );
844 }
845
846 static int
847 over_aux_operational( Operation *op, SlapReply *rs )
848 {
849         return over_op_func( op, rs, op_aux_operational );
850 }
851
852 static int
853 over_aux_chk_referrals( Operation *op, SlapReply *rs )
854 {
855         return over_op_func( op, rs, op_aux_chk_referrals );
856 }
857
858 static int
859 over_aux_chk_controls( Operation *op, SlapReply *rs )
860 {
861         return over_op_func( op, rs, op_aux_chk_controls );
862 }
863
864 enum conn_which {
865         conn_init = 0,
866         conn_destroy,
867         conn_last
868 };
869
870 static int
871 over_connection_func(
872         BackendDB       *bd,
873         Connection      *conn,
874         enum conn_which which
875 )
876 {
877         slap_overinfo           *oi;
878         slap_overinst           *on;
879         BackendDB               db;
880         int                     rc = SLAP_CB_CONTINUE;
881         BI_connection_init      **func;
882
883         /* FIXME: used to happen for instance during abandon
884          * when global overlays are used... */
885         assert( bd != NULL );
886
887         oi = bd->bd_info->bi_private;
888         on = oi->oi_list;
889
890         if ( !SLAP_ISOVERLAY( bd ) ) {
891                 db = *bd;
892                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
893                 bd = &db;
894         }
895
896         for ( ; on; on = on->on_next ) {
897                 if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
898                         continue;
899                 func = &on->on_bi.bi_connection_init;
900                 if ( func[ which ] ) {
901                         bd->bd_info = (BackendInfo *)on;
902                         rc = func[ which ]( bd, conn );
903                         if ( rc != SLAP_CB_CONTINUE ) break;
904                 }
905         }
906
907         func = &oi->oi_orig->bi_connection_init;
908         if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
909                 bd->bd_info = oi->oi_orig;
910                 rc = func[ which ]( bd, conn );
911         }
912         /* should not fall thru this far without anything happening... */
913         if ( rc == SLAP_CB_CONTINUE ) {
914                 rc = LDAP_UNWILLING_TO_PERFORM;
915         }
916
917         return rc;
918 }
919
920 static int
921 over_connection_init(
922         BackendDB       *bd,
923         Connection      *conn
924 )
925 {
926         return over_connection_func( bd, conn, conn_init );
927 }
928
929 static int
930 over_connection_destroy(
931         BackendDB       *bd,
932         Connection      *conn
933 )
934 {
935         return over_connection_func( bd, conn, conn_destroy );
936 }
937
938 int
939 overlay_register(
940         slap_overinst *on
941 )
942 {
943         slap_overinst   *tmp;
944
945         /* FIXME: check for duplicates? */
946         for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) {
947                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) {
948                         Debug( LDAP_DEBUG_ANY,
949                                 "overlay_register(\"%s\"): "
950                                 "name already in use.\n",
951                                 on->on_bi.bi_type, 0, 0 );
952                         return -1;
953                 }
954
955                 if ( on->on_bi.bi_obsolete_names != NULL ) {
956                         int     i;
957
958                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
959                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) {
960                                         Debug( LDAP_DEBUG_ANY,
961                                                 "overlay_register(\"%s\"): "
962                                                 "obsolete name \"%s\" already in use "
963                                                 "by overlay \"%s\".\n",
964                                                 on->on_bi.bi_type,
965                                                 on->on_bi.bi_obsolete_names[ i ],
966                                                 tmp->on_bi.bi_type );
967                                         return -1;
968                                 }
969                         }
970                 }
971
972                 if ( tmp->on_bi.bi_obsolete_names != NULL ) {
973                         int     i;
974
975                         for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
976                                 int     j;
977
978                                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
979                                         Debug( LDAP_DEBUG_ANY,
980                                                 "overlay_register(\"%s\"): "
981                                                 "name already in use "
982                                                 "as obsolete by overlay \"%s\".\n",
983                                                 on->on_bi.bi_type,
984                                                 tmp->on_bi.bi_obsolete_names[ i ], 0 );
985                                         return -1;
986                                 }
987
988                                 if ( on->on_bi.bi_obsolete_names != NULL ) {
989                                         for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) {
990                                                 if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
991                                                         Debug( LDAP_DEBUG_ANY,
992                                                                 "overlay_register(\"%s\"): "
993                                                                 "obsolete name \"%s\" already in use "
994                                                                 "as obsolete by overlay \"%s\".\n",
995                                                                 on->on_bi.bi_type,
996                                                                 on->on_bi.bi_obsolete_names[ j ],
997                                                                 tmp->on_bi.bi_type );
998                                                         return -1;
999                                                 }
1000                                         }
1001                                 }
1002                         }
1003                 }
1004         }
1005
1006         on->on_next = overlays;
1007         overlays = on;
1008         return 0;
1009 }
1010
1011 /*
1012  * iterator on registered overlays; overlay_next( NULL ) returns the first
1013  * overlay; subsequent calls with the previously returned value allow to 
1014  * iterate over the entire list; returns NULL when no more overlays are 
1015  * registered.
1016  */
1017
1018 slap_overinst *
1019 overlay_next(
1020         slap_overinst *on
1021 )
1022 {
1023         if ( on == NULL ) {
1024                 return overlays;
1025         }
1026
1027         return on->on_next;
1028 }
1029
1030 /*
1031  * returns a specific registered overlay based on the type; NULL if not
1032  * registered.
1033  */
1034
1035 slap_overinst *
1036 overlay_find( const char *over_type )
1037 {
1038         slap_overinst *on = overlays;
1039
1040         assert( over_type != NULL );
1041
1042         for ( ; on; on = on->on_next ) {
1043                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
1044                         goto foundit;
1045                 }
1046
1047                 if ( on->on_bi.bi_obsolete_names != NULL ) {
1048                         int     i;
1049
1050                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
1051                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) {
1052                                         Debug( LDAP_DEBUG_ANY,
1053                                                 "overlay_find(\"%s\"): "
1054                                                 "obsolete name for \"%s\".\n",
1055                                                 on->on_bi.bi_obsolete_names[ i ],
1056                                                 on->on_bi.bi_type, 0 );
1057                                         goto foundit;
1058                                 }
1059                         }
1060                 }
1061         }
1062
1063 foundit:;
1064         return on;
1065 }
1066
1067 static const char overtype[] = "over";
1068
1069 /*
1070  * returns TRUE (1) if the database is actually an overlay instance;
1071  * FALSE (0) otherwise.
1072  */
1073
1074 int
1075 overlay_is_over( BackendDB *be )
1076 {
1077         return be->bd_info->bi_type == overtype;
1078 }
1079
1080 /*
1081  * returns TRUE (1) if the given database is actually an overlay
1082  * instance and, somewhere in the list, contains the requested overlay;
1083  * FALSE (0) otherwise.
1084  */
1085
1086 int
1087 overlay_is_inst( BackendDB *be, const char *over_type )
1088 {
1089         slap_overinst   *on;
1090
1091         assert( be != NULL );
1092
1093         if ( !overlay_is_over( be ) ) {
1094                 return 0;
1095         }
1096         
1097         on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
1098         for ( ; on; on = on->on_next ) {
1099                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
1100                         return 1;
1101                 }
1102         }
1103
1104         return 0;
1105 }
1106
1107 int
1108 overlay_register_control( BackendDB *be, const char *oid )
1109 {
1110         int             gotit = 0;
1111         int             cid;
1112
1113         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
1114                 return -1;
1115         }
1116
1117         if ( SLAP_ISGLOBALOVERLAY( be ) ) {
1118                 BackendDB *bd;
1119                 
1120                 /* add to all backends... */
1121                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
1122                         if ( bd == be->bd_self ) {
1123                                 gotit = 1;
1124                         }
1125
1126                         /* overlays can be instantiated multiple times, use
1127                          * be_ctrls[ cid ] as an instance counter, so that the
1128                          * overlay's controls are only really disabled after the
1129                          * last instance called overlay_register_control() */
1130                         bd->be_ctrls[ cid ]++;
1131                         bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1132                 }
1133
1134         }
1135         
1136         if ( !gotit ) {
1137                 /* overlays can be instantiated multiple times, use
1138                  * be_ctrls[ cid ] as an instance counter, so that the
1139                  * overlay's controls are only really unregistered after the
1140                  * last instance called overlay_register_control() */
1141                 be->bd_self->be_ctrls[ cid ]++;
1142                 be->bd_self->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1143         }
1144
1145         return 0;
1146 }
1147
1148 #ifdef SLAP_CONFIG_DELETE
1149 void
1150 overlay_unregister_control( BackendDB *be, const char *oid )
1151 {
1152         int             gotit = 0;
1153         int             cid;
1154
1155         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
1156                 return;
1157         }
1158
1159         if ( SLAP_ISGLOBALOVERLAY( be ) ) {
1160                 BackendDB *bd;
1161
1162                 /* remove from all backends... */
1163                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
1164                         if ( bd == be->bd_self ) {
1165                                 gotit = 1;
1166                         }
1167
1168                         bd->be_ctrls[ cid ]--;
1169                 }
1170         }
1171
1172         if ( !gotit ) {
1173                 be->bd_self->be_ctrls[ cid ]--;
1174         }
1175 }
1176 #endif /* SLAP_CONFIG_DELETE */
1177
1178 void
1179 overlay_destroy_one( BackendDB *be, slap_overinst *on )
1180 {
1181         slap_overinfo *oi = on->on_info;
1182         slap_overinst **oidx;
1183
1184         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1185                 if ( *oidx == on ) {
1186                         *oidx = on->on_next;
1187                         if ( on->on_bi.bi_db_destroy ) {
1188                                 BackendInfo *bi_orig = be->bd_info;
1189                                 be->bd_info = (BackendInfo *)on;
1190                                 on->on_bi.bi_db_destroy( be, NULL );
1191                                 be->bd_info = bi_orig;
1192                         }
1193                         free( on );
1194                         break;
1195                 }
1196         }
1197 }
1198
1199 #ifdef SLAP_CONFIG_DELETE
1200 typedef struct ov_remove_ctx {
1201         BackendDB *be;
1202         slap_overinst *on;
1203 } ov_remove_ctx;
1204
1205 int
1206 overlay_remove_cb( Operation *op, SlapReply *rs )
1207 {
1208         ov_remove_ctx *rm_ctx = (ov_remove_ctx*) op->o_callback->sc_private;
1209         BackendInfo *bi_orig = rm_ctx->be->bd_info;
1210
1211         rm_ctx->be->bd_info = (BackendInfo*) rm_ctx->on;
1212
1213         if ( rm_ctx->on->on_bi.bi_db_close ) {
1214                 rm_ctx->on->on_bi.bi_db_close( rm_ctx->be, NULL );
1215         }
1216         if ( rm_ctx->on->on_bi.bi_db_destroy ) {
1217                 rm_ctx->on->on_bi.bi_db_destroy( rm_ctx->be, NULL );
1218         }
1219
1220         /* clean up after removing last overlay */
1221         if ( ! rm_ctx->on->on_info->oi_list ) {
1222                 /* reset db flags and bd_info to orig */
1223                 SLAP_DBFLAGS( rm_ctx->be ) &= ~SLAP_DBFLAG_GLOBAL_OVERLAY;
1224                 rm_ctx->be->bd_info = rm_ctx->on->on_info->oi_orig;
1225                 ch_free(rm_ctx->on->on_info);
1226         } else {
1227                 rm_ctx->be->bd_info = bi_orig;
1228         }
1229         free( rm_ctx->on );
1230         op->o_tmpfree(rm_ctx, op->o_tmpmemctx);
1231         return SLAP_CB_CONTINUE;
1232 }
1233
1234 void
1235 overlay_remove( BackendDB *be, slap_overinst *on, Operation *op )
1236 {
1237         slap_overinfo *oi = on->on_info;
1238         slap_overinst **oidx;
1239         ov_remove_ctx *rm_ctx;
1240         slap_callback *rm_cb, *cb;
1241
1242         /* remove overlay from oi_list */
1243         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1244                 if ( *oidx == on ) {
1245                         *oidx = on->on_next;
1246                         break;
1247                 }
1248         }
1249
1250         /* The db_close and db_destroy handlers to cleanup a release
1251          * the overlay's resources are called from the cleanup callback
1252          */
1253         rm_ctx = op->o_tmpalloc( sizeof( ov_remove_ctx ), op->o_tmpmemctx );
1254         rm_ctx->be = be;
1255         rm_ctx->on = on;
1256
1257         rm_cb = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
1258         rm_cb->sc_next = NULL;
1259         rm_cb->sc_cleanup = overlay_remove_cb;
1260         rm_cb->sc_response = NULL;
1261         rm_cb->sc_private = (void*) rm_ctx;
1262         rm_cb->sc_writewait = NULL;
1263
1264         /* Append callback to the end of the list */
1265         if ( !op->o_callback ) {
1266                 op->o_callback = rm_cb;
1267         } else {
1268                 for ( cb = op->o_callback; cb->sc_next; cb = cb->sc_next );
1269                 cb->sc_next = rm_cb;
1270         }
1271 }
1272 #endif /* SLAP_CONFIG_DELETE */
1273
1274 void
1275 overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev,
1276         int idx )
1277 {
1278         slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1279
1280         if ( idx == -1 ) {
1281                 on2->on_next = oi->oi_list;
1282                 oi->oi_list = on2;
1283         } else {
1284                 int i, novs;
1285                 slap_overinst *on, **prev;
1286
1287                 /* Since the list is in reverse order and is singly linked,
1288                  * we have to count the overlays and then insert backwards.
1289                  * Adding on overlay at a specific point should be a pretty
1290                  * infrequent occurrence.
1291                  */
1292                 novs = 0;
1293                 for ( on = oi->oi_list; on; on=on->on_next )
1294                         novs++;
1295
1296                 if (idx > novs)
1297                         idx = 0;
1298                 else
1299                         idx = novs - idx;
1300
1301                 /* advance to insertion point */
1302                 prev = &oi->oi_list;
1303                 for ( i=0; i<idx; i++ ) {
1304                         on = *prev;
1305                         prev = &on->on_next;
1306                 }
1307                 /* insert */
1308                 on2->on_next = *prev;
1309                 *prev = on2;
1310         }
1311 }
1312
1313 void
1314 overlay_move( BackendDB *be, slap_overinst *on, int idx )
1315 {
1316         slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1317         slap_overinst **onp;
1318
1319         for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) {
1320                 if ( *onp == on ) {
1321                         *onp = on->on_next;
1322                         break;
1323                 }
1324         }
1325         overlay_insert( be, on, &onp, idx );
1326 }
1327
1328 /* add an overlay to a particular backend. */
1329 int
1330 overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res, ConfigReply *cr )
1331 {
1332         slap_overinst *on = NULL, *on2 = NULL, **prev;
1333         slap_overinfo *oi = NULL;
1334         BackendInfo *bi = NULL;
1335
1336         if ( res )
1337                 *res = NULL;
1338
1339         on = overlay_find( ov );
1340         if ( !on ) {
1341                 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
1342                 return 1;
1343         }
1344
1345         /* If this is the first overlay on this backend, set up the
1346          * overlay info structure
1347          */
1348         if ( !overlay_is_over( be ) ) {
1349                 int     isglobal = 0;
1350
1351                 /* NOTE: the first time a global overlay is configured,
1352                  * frontendDB gets this flag; it is used later by overlays
1353                  * to determine if they're stacked on top of the frontendDB */
1354                 if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) {
1355                         isglobal = 1;
1356                         if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) {
1357                                 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1358                                         "overlay \"%s\" cannot be global.\n",
1359                                         ov, 0, 0 );
1360                                 return 1;
1361                         }
1362
1363                 } else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) {
1364                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1365                                 "overlay \"%s\" can only be global.\n",
1366                                 ov, 0, 0 );
1367                         return 1;
1368                 }
1369
1370                 oi = ch_malloc( sizeof( slap_overinfo ) );
1371                 oi->oi_orig = be->bd_info;
1372                 oi->oi_bi = *be->bd_info;
1373                 oi->oi_origdb = be;
1374
1375                 if ( isglobal ) {
1376                         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
1377                 }
1378
1379                 /* Save a pointer to ourself in bi_private.
1380                  */
1381                 oi->oi_bi.bi_private = oi;
1382                 oi->oi_list = NULL;
1383                 bi = (BackendInfo *)oi;
1384
1385                 bi->bi_type = (char *)overtype;
1386
1387                 bi->bi_db_config = over_db_config;
1388                 bi->bi_db_open = over_db_open;
1389                 bi->bi_db_close = over_db_close;
1390                 bi->bi_db_destroy = over_db_destroy;
1391
1392                 bi->bi_op_bind = over_op_bind;
1393                 bi->bi_op_unbind = over_op_unbind;
1394                 bi->bi_op_search = over_op_search;
1395                 bi->bi_op_compare = over_op_compare;
1396                 bi->bi_op_modify = over_op_modify;
1397                 bi->bi_op_modrdn = over_op_modrdn;
1398                 bi->bi_op_add = over_op_add;
1399                 bi->bi_op_delete = over_op_delete;
1400                 bi->bi_op_abandon = over_op_abandon;
1401                 bi->bi_op_cancel = over_op_cancel;
1402
1403                 bi->bi_extended = over_op_extended;
1404
1405                 /*
1406                  * this is fine because it has the same
1407                  * args of the operations; we need to rework
1408                  * all the hooks to share the same args
1409                  * of the operations...
1410                  */
1411                 bi->bi_operational = over_aux_operational;
1412                 bi->bi_chk_referrals = over_aux_chk_referrals;
1413                 bi->bi_chk_controls = over_aux_chk_controls;
1414
1415                 /* these have specific arglists */
1416                 bi->bi_entry_get_rw = over_entry_get_rw;
1417                 bi->bi_entry_release_rw = over_entry_release_rw;
1418                 bi->bi_access_allowed = over_access_allowed;
1419                 bi->bi_acl_group = over_acl_group;
1420                 bi->bi_acl_attribute = over_acl_attribute;
1421                 
1422                 bi->bi_connection_init = over_connection_init;
1423                 bi->bi_connection_destroy = over_connection_destroy;
1424
1425                 be->bd_info = bi;
1426
1427         } else {
1428                 if ( overlay_is_inst( be, ov ) ) {
1429                         if ( SLAPO_SINGLE( be ) ) {
1430                                 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1431                                         "overlay \"%s\" already in list\n",
1432                                         ov, 0, 0 );
1433                                 return 1;
1434                         }
1435                 }
1436
1437                 oi = be->bd_info->bi_private;
1438         }
1439
1440         /* Insert new overlay into list. By default overlays are
1441          * added to head of list and executed in LIFO order.
1442          */
1443         on2 = ch_calloc( 1, sizeof(slap_overinst) );
1444         *on2 = *on;
1445         on2->on_info = oi;
1446
1447         prev = &oi->oi_list;
1448         /* Do we need to find the insertion point? */
1449         if ( idx >= 0 ) {
1450                 int i;
1451
1452                 /* count current overlays */
1453                 for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ );
1454
1455                 /* are we just appending a new one? */
1456                 if ( idx >= i )
1457                         idx = -1;
1458         }
1459         overlay_insert( be, on2, &prev, idx );
1460
1461         /* Any initialization needed? */
1462         if ( on2->on_bi.bi_db_init ) {
1463                 int rc;
1464                 be->bd_info = (BackendInfo *)on2;
1465                 rc = on2->on_bi.bi_db_init( be, cr);
1466                 be->bd_info = (BackendInfo *)oi;
1467                 if ( rc ) {
1468                         *prev = on2->on_next;
1469                         ch_free( on2 );
1470                         on2 = NULL;
1471                         return rc;
1472                 }
1473         }
1474
1475         if ( res )
1476                 *res = &on2->on_bi;
1477
1478         return 0;
1479 }