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