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