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