]> git.sur5r.net Git - openldap/blob - servers/slapd/backover.c
unifdef -DSLAP_ACL_HONOR_DISCLOSE
[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-2006 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 enum db_which {
33         db_open = 0,
34         db_close,
35         db_destroy,
36         db_last
37 };
38
39 static int
40 over_db_func(
41         BackendDB *be,
42         enum db_which which
43 )
44 {
45         slap_overinfo *oi = be->bd_info->bi_private;
46         slap_overinst *on = oi->oi_list;
47         BackendInfo *bi_orig = be->bd_info;
48         BI_db_open **func;
49         int rc = 0;
50
51         func = &oi->oi_orig->bi_db_open;
52         if ( func[which] ) {
53                 be->bd_info = oi->oi_orig;
54                 rc = func[which]( be );
55         }
56
57         for (; on && rc == 0; on=on->on_next) {
58                 be->bd_info = &on->on_bi;
59                 func = &on->on_bi.bi_db_open;
60                 if (func[which]) {
61                         rc = func[which]( be );
62                 }
63         }
64         be->bd_info = bi_orig;
65         return rc;
66 }
67
68 static int
69 over_db_config(
70         BackendDB *be,
71         const char *fname,
72         int lineno,
73         int argc,
74         char **argv
75 )
76 {
77         slap_overinfo *oi = be->bd_info->bi_private;
78         slap_overinst *on = oi->oi_list;
79         BackendInfo *bi_orig = be->bd_info;
80         struct ConfigOCs *be_cf_ocs = be->be_cf_ocs;
81         ConfigArgs ca = {0};
82         int rc = 0;
83
84         if ( oi->oi_orig->bi_db_config ) {
85                 be->bd_info = oi->oi_orig;
86                 be->be_cf_ocs = oi->oi_orig->bi_cf_ocs;
87                 rc = oi->oi_orig->bi_db_config( be, fname, lineno,
88                         argc, argv );
89
90                 if ( be->bd_info != oi->oi_orig ) {
91                         slap_overinfo   *oi2;
92                         slap_overinst   *on2, **onp;
93                         BackendDB       be2 = *be;
94                         int             i;
95
96                         /* a database added an overlay;
97                          * work it around... */
98                         assert( overlay_is_over( be ) );
99                         
100                         oi2 = ( slap_overinfo * )be->bd_info->bi_private;
101                         on2 = oi2->oi_list;
102
103                         /* need to put a uniqueness check here as well;
104                          * note that in principle there could be more than
105                          * one overlay as a result of multiple calls to
106                          * overlay_config() */
107                         be2.bd_info = (BackendInfo *)oi;
108
109                         for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
110                                 if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
111                                         Debug( LDAP_DEBUG_ANY, "over_db_config(): "
112                                                         "warning, freshly added "
113                                                         "overlay #%d \"%s\" is already in list\n",
114                                                         i, (*onp)->on_bi.bi_type, 0 );
115
116                                         /* NOTE: if the overlay already exists,
117                                          * there is no way to merge the results
118                                          * of the configuration that may have 
119                                          * occurred during bi_db_config(); we
120                                          * just issue a warning, and the 
121                                          * administrator should deal with this */
122                                 }
123                         }
124                         *onp = oi->oi_list;
125
126                         oi->oi_list = on2;
127
128                         ch_free( be->bd_info );
129                 }
130
131                 be->bd_info = (BackendInfo *)oi;
132                 if ( rc != SLAP_CONF_UNKNOWN ) return rc;
133         }
134
135         ca.argv = argv;
136         ca.argc = argc;
137         ca.fname = fname;
138         ca.lineno = lineno;
139         ca.be = be;
140         snprintf( ca.log, sizeof( ca.log ), "%s: line %d",
141                         ca.fname, ca.lineno );
142
143         for (; on; on=on->on_next) {
144                 rc = SLAP_CONF_UNKNOWN;
145                 if (on->on_bi.bi_cf_ocs) {
146                         ConfigTable *ct;
147                         ca.bi = &on->on_bi;
148                         ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca );
149                         if ( ct ) {
150                                 rc = config_add_vals( ct, &ca );
151                                 if ( rc != SLAP_CONF_UNKNOWN )
152                                         break;
153                         }
154                 }
155                 if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) {
156                         be->bd_info = &on->on_bi;
157                         rc = on->on_bi.bi_db_config( be, fname, lineno,
158                                 argc, argv );
159                         if ( rc != SLAP_CONF_UNKNOWN ) break;
160                 }
161         }
162         be->bd_info = bi_orig;
163         be->be_cf_ocs = be_cf_ocs;
164         
165         return rc;
166 }
167
168 static int
169 over_db_open(
170         BackendDB *be
171 )
172 {
173         return over_db_func( be, db_open );
174 }
175
176 static int
177 over_db_close(
178         BackendDB *be
179 )
180 {
181         slap_overinfo *oi = be->bd_info->bi_private;
182         slap_overinst *on = oi->oi_list;
183         BackendInfo *bi_orig = be->bd_info;
184         int rc = 0;
185
186         for (; on && rc == 0; on=on->on_next) {
187                 be->bd_info = &on->on_bi;
188                 if ( be->bd_info->bi_db_close ) {
189                         rc = be->bd_info->bi_db_close( be );
190                 }
191         }
192
193         if ( oi->oi_orig->bi_db_close ) {
194                 be->bd_info = oi->oi_orig;
195                 rc = be->bd_info->bi_db_close( be );
196         }
197
198         be->bd_info = bi_orig;
199         return rc;
200 }
201
202 static int
203 over_db_destroy(
204         BackendDB *be
205 )
206 {
207         slap_overinfo *oi = be->bd_info->bi_private;
208         slap_overinst *on = oi->oi_list, *next;
209         int rc;
210
211         rc = over_db_func( be, db_destroy );
212
213         for (next = on->on_next; on; on=next) {
214                 next = on->on_next;
215                 free( on );
216         }
217         free( oi );
218         return rc;
219 }
220
221 static int
222 over_back_response ( Operation *op, SlapReply *rs )
223 {
224         slap_overinfo *oi = op->o_callback->sc_private;
225         slap_overinst *on = oi->oi_list;
226         int rc = SLAP_CB_CONTINUE;
227         BackendDB *be = op->o_bd, db = *op->o_bd;
228
229         db.be_flags |= SLAP_DBFLAG_OVERLAY;
230         op->o_bd = &db;
231         for (; on; on=on->on_next ) {
232                 if ( on->on_response ) {
233                         db.bd_info = (BackendInfo *)on;
234                         rc = on->on_response( op, rs );
235                         if ( rc != SLAP_CB_CONTINUE ) break;
236                 }
237         }
238         op->o_bd = be;
239         return rc;
240 }
241
242 static int
243 over_access_allowed(
244         Operation               *op,
245         Entry                   *e,
246         AttributeDescription    *desc,
247         struct berval           *val,
248         slap_access_t           access,
249         AccessControlState      *state,
250         slap_mask_t             *maskp )
251 {
252         slap_overinfo *oi;
253         slap_overinst *on;
254         BackendInfo *bi;
255         BackendDB *be = op->o_bd, db;
256         int rc = SLAP_CB_CONTINUE;
257
258         /* FIXME: used to happen for instance during abandon
259          * when global overlays are used... */
260         assert( op->o_bd != NULL );
261
262         bi = op->o_bd->bd_info;
263         /* Were we invoked on the frontend? */
264         if ( !bi->bi_access_allowed ) {
265                 oi = frontendDB->bd_info->bi_private;
266         } else {
267                 oi = op->o_bd->bd_info->bi_private;
268         }
269         on = oi->oi_list;
270
271         for ( ; on; on = on->on_next ) {
272                 if ( on->on_bi.bi_access_allowed ) {
273                         /* NOTE: do not copy the structure until required */
274                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
275                                 db = *op->o_bd;
276                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
277                                 op->o_bd = &db;
278                         }
279
280                         op->o_bd->bd_info = (BackendInfo *)on;
281                         rc = on->on_bi.bi_access_allowed( op, e,
282                                 desc, val, access, state, maskp );
283                         if ( rc != SLAP_CB_CONTINUE ) break;
284                 }
285         }
286
287         if ( rc == SLAP_CB_CONTINUE ) {
288                 BI_access_allowed       *bi_access_allowed;
289
290                 /* if the database structure was changed, o_bd points to a
291                  * copy of the structure; put the original bd_info in place */
292                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
293                         op->o_bd->bd_info = oi->oi_orig;
294                 }
295
296                 if ( oi->oi_orig->bi_access_allowed ) {
297                         bi_access_allowed = oi->oi_orig->bi_access_allowed;
298                 } else {
299                         bi_access_allowed = slap_access_allowed;
300                 }
301
302                 rc = bi_access_allowed( op, e,
303                         desc, val, access, state, maskp );
304         }
305         /* should not fall thru this far without anything happening... */
306         if ( rc == SLAP_CB_CONTINUE ) {
307                 /* access not allowed */
308                 rc = 0;
309         }
310
311         op->o_bd = be;
312         op->o_bd->bd_info = bi;
313
314         return rc;
315 }
316
317 static int
318 over_acl_group(
319         Operation               *op,
320         Entry                   *e,
321         struct berval           *gr_ndn,
322         struct berval           *op_ndn,
323         ObjectClass             *group_oc,
324         AttributeDescription    *group_at )
325 {
326         slap_overinfo *oi;
327         slap_overinst *on;
328         BackendInfo *bi = op->o_bd->bd_info;
329         BackendDB *be = op->o_bd, db;
330         int rc = SLAP_CB_CONTINUE;
331
332         /* FIXME: used to happen for instance during abandon
333          * when global overlays are used... */
334         assert( op->o_bd != NULL );
335
336         oi = op->o_bd->bd_info->bi_private;
337         on = oi->oi_list;
338
339         for ( ; on; on = on->on_next ) {
340                 if ( on->on_bi.bi_acl_group ) {
341                         /* NOTE: do not copy the structure until required */
342                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
343                                 db = *op->o_bd;
344                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
345                                 op->o_bd = &db;
346                         }
347
348                         op->o_bd->bd_info = (BackendInfo *)on;
349                         rc = on->on_bi.bi_acl_group( op, e,
350                                 gr_ndn, op_ndn, group_oc, group_at );
351                         if ( rc != SLAP_CB_CONTINUE ) break;
352                 }
353         }
354
355         if ( rc == SLAP_CB_CONTINUE ) {
356                 BI_acl_group            *bi_acl_group;
357
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_acl_group ) {
365                         bi_acl_group = oi->oi_orig->bi_acl_group;
366                 } else {
367                         bi_acl_group = backend_group;
368                 }
369
370                 rc = bi_acl_group( op, e,
371                         gr_ndn, op_ndn, group_oc, group_at );
372         }
373         /* should not fall thru this far without anything happening... */
374         if ( rc == SLAP_CB_CONTINUE ) {
375                 /* access not allowed */
376                 rc = 0;
377         }
378
379         op->o_bd = be;
380         op->o_bd->bd_info = bi;
381
382         return rc;
383 }
384
385 static int
386 over_acl_attribute(
387         Operation               *op,
388         Entry                   *target,
389         struct berval           *entry_ndn,
390         AttributeDescription    *entry_at,
391         BerVarray               *vals,
392         slap_access_t           access )
393 {
394         slap_overinfo *oi;
395         slap_overinst *on;
396         BackendInfo *bi = op->o_bd->bd_info;
397         BackendDB *be = op->o_bd, db;
398         int rc = SLAP_CB_CONTINUE;
399
400         /* FIXME: used to happen for instance during abandon
401          * when global overlays are used... */
402         assert( op->o_bd != NULL );
403
404         oi = op->o_bd->bd_info->bi_private;
405         on = oi->oi_list;
406
407         for ( ; on; on = on->on_next ) {
408                 if ( on->on_bi.bi_acl_attribute ) {
409                         /* NOTE: do not copy the structure until required */
410                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
411                                 db = *op->o_bd;
412                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
413                                 op->o_bd = &db;
414                         }
415
416                         op->o_bd->bd_info = (BackendInfo *)on;
417                         rc = on->on_bi.bi_acl_attribute( op, target,
418                                 entry_ndn, entry_at, vals, access );
419                         if ( rc != SLAP_CB_CONTINUE ) break;
420                 }
421         }
422
423         if ( rc == SLAP_CB_CONTINUE ) {
424                 BI_acl_attribute                *bi_acl_attribute;
425
426                 /* if the database structure was changed, o_bd points to a
427                  * copy of the structure; put the original bd_info in place */
428                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
429                         op->o_bd->bd_info = oi->oi_orig;
430                 }
431
432                 if ( oi->oi_orig->bi_acl_attribute ) {
433                         bi_acl_attribute = oi->oi_orig->bi_acl_attribute;
434                 } else {
435                         bi_acl_attribute = backend_attribute;
436                 }
437
438                 rc = bi_acl_attribute( op, target,
439                         entry_ndn, entry_at, vals, access );
440         }
441         /* should not fall thru this far without anything happening... */
442         if ( rc == SLAP_CB_CONTINUE ) {
443                 /* access not allowed */
444                 rc = 0;
445         }
446
447         op->o_bd = be;
448         op->o_bd->bd_info = bi;
449
450         return rc;
451 }
452
453 /*
454  * default return code in case of missing backend function
455  * and overlay stack returning SLAP_CB_CONTINUE
456  */
457 static int op_rc[ op_last ] = {
458         LDAP_UNWILLING_TO_PERFORM,      /* bind */
459         LDAP_UNWILLING_TO_PERFORM,      /* unbind */
460         LDAP_UNWILLING_TO_PERFORM,      /* search */
461         SLAP_CB_CONTINUE,               /* compare; pass to frontend */
462         LDAP_UNWILLING_TO_PERFORM,      /* modify */
463         LDAP_UNWILLING_TO_PERFORM,      /* modrdn */
464         LDAP_UNWILLING_TO_PERFORM,      /* add */
465         LDAP_UNWILLING_TO_PERFORM,      /* delete */
466         LDAP_UNWILLING_TO_PERFORM,      /* abandon */
467         LDAP_UNWILLING_TO_PERFORM,      /* cancel */
468         LDAP_UNWILLING_TO_PERFORM,      /* extended */
469         LDAP_SUCCESS,                   /* aux_operational */
470         LDAP_SUCCESS,                   /* aux_chk_referrals */
471         SLAP_CB_CONTINUE                /* aux_chk_controls; pass to frontend */
472 };
473
474 int overlay_op_walk(
475         Operation *op,
476         SlapReply *rs,
477         slap_operation_t which,
478         slap_overinfo *oi,
479         slap_overinst *on
480 )
481 {
482         BI_op_bind **func;
483         int rc = SLAP_CB_CONTINUE;
484
485         for (; on; on=on->on_next ) {
486                 func = &on->on_bi.bi_op_bind;
487                 if ( func[which] ) {
488                         op->o_bd->bd_info = (BackendInfo *)on;
489                         rc = func[which]( op, rs );
490                         if ( rc != SLAP_CB_CONTINUE ) break;
491                 }
492         }
493
494         func = &oi->oi_orig->bi_op_bind;
495         if ( func[which] && rc == SLAP_CB_CONTINUE ) {
496                 op->o_bd->bd_info = oi->oi_orig;
497                 rc = func[which]( op, rs );
498         }
499         /* should not fall thru this far without anything happening... */
500         if ( rc == SLAP_CB_CONTINUE ) {
501                 rc = op_rc[ which ];
502         }
503
504         /* The underlying backend didn't handle the request, make sure
505          * overlay cleanup is processed.
506          */
507         if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
508                 slap_callback *sc_next;
509                 for ( ; op->o_callback && op->o_callback->sc_response !=
510                         over_back_response; op->o_callback = sc_next ) {
511                         sc_next = op->o_callback->sc_next;
512                         if ( op->o_callback->sc_cleanup ) {
513                                 op->o_callback->sc_cleanup( op, rs );
514                         }
515                 }
516         }
517         return rc;
518 }
519
520 static int
521 over_op_func(
522         Operation *op,
523         SlapReply *rs,
524         slap_operation_t which
525 )
526 {
527         slap_overinfo *oi;
528         slap_overinst *on;
529         BackendDB *be = op->o_bd, db;
530         slap_callback cb = {NULL, over_back_response, NULL, NULL};
531         int rc = SLAP_CB_CONTINUE;
532
533         /* FIXME: used to happen for instance during abandon
534          * when global overlays are used... */
535         assert( op->o_bd != NULL );
536
537         oi = op->o_bd->bd_info->bi_private;
538         on = oi->oi_list;
539
540         if ( !SLAP_ISOVERLAY( op->o_bd )) {
541                 db = *op->o_bd;
542                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
543                 op->o_bd = &db;
544         }
545         cb.sc_next = op->o_callback;
546         cb.sc_private = oi;
547         op->o_callback = &cb;
548
549         rc = overlay_op_walk( op, rs, which, oi, on );
550
551         op->o_bd = be;
552         op->o_callback = cb.sc_next;
553         return rc;
554 }
555
556 static int
557 over_op_bind( Operation *op, SlapReply *rs )
558 {
559         return over_op_func( op, rs, op_bind );
560 }
561
562 static int
563 over_op_unbind( Operation *op, SlapReply *rs )
564 {
565         return over_op_func( op, rs, op_unbind );
566 }
567
568 static int
569 over_op_search( Operation *op, SlapReply *rs )
570 {
571         return over_op_func( op, rs, op_search );
572 }
573
574 static int
575 over_op_compare( Operation *op, SlapReply *rs )
576 {
577         return over_op_func( op, rs, op_compare );
578 }
579
580 static int
581 over_op_modify( Operation *op, SlapReply *rs )
582 {
583         return over_op_func( op, rs, op_modify );
584 }
585
586 static int
587 over_op_modrdn( Operation *op, SlapReply *rs )
588 {
589         return over_op_func( op, rs, op_modrdn );
590 }
591
592 static int
593 over_op_add( Operation *op, SlapReply *rs )
594 {
595         return over_op_func( op, rs, op_add );
596 }
597
598 static int
599 over_op_delete( Operation *op, SlapReply *rs )
600 {
601         return over_op_func( op, rs, op_delete );
602 }
603
604 static int
605 over_op_abandon( Operation *op, SlapReply *rs )
606 {
607         return over_op_func( op, rs, op_abandon );
608 }
609
610 static int
611 over_op_cancel( Operation *op, SlapReply *rs )
612 {
613         return over_op_func( op, rs, op_cancel );
614 }
615
616 static int
617 over_op_extended( Operation *op, SlapReply *rs )
618 {
619         return over_op_func( op, rs, op_extended );
620 }
621
622 static int
623 over_aux_operational( Operation *op, SlapReply *rs )
624 {
625         return over_op_func( op, rs, op_aux_operational );
626 }
627
628 static int
629 over_aux_chk_referrals( Operation *op, SlapReply *rs )
630 {
631         return over_op_func( op, rs, op_aux_chk_referrals );
632 }
633
634 static int
635 over_aux_chk_controls( Operation *op, SlapReply *rs )
636 {
637         return over_op_func( op, rs, op_aux_chk_controls );
638 }
639
640 enum conn_which {
641         conn_init = 0,
642         conn_destroy,
643         conn_last
644 };
645
646 static int
647 over_connection_func(
648         BackendDB       *bd,
649         Connection      *conn,
650         enum conn_which which
651 )
652 {
653         slap_overinfo           *oi;
654         slap_overinst           *on;
655         BackendDB               db;
656         int                     rc = SLAP_CB_CONTINUE;
657         BI_connection_init      **func;
658
659         /* FIXME: used to happen for instance during abandon
660          * when global overlays are used... */
661         assert( bd != NULL );
662
663         oi = bd->bd_info->bi_private;
664         on = oi->oi_list;
665
666         if ( !SLAP_ISOVERLAY( bd ) ) {
667                 db = *bd;
668                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
669                 bd = &db;
670         }
671
672         for ( ; on; on = on->on_next ) {
673                 func = &on->on_bi.bi_connection_init;
674                 if ( func[ which ] ) {
675                         bd->bd_info = (BackendInfo *)on;
676                         rc = func[ which ]( bd, conn );
677                         if ( rc != SLAP_CB_CONTINUE ) break;
678                 }
679         }
680
681         func = &oi->oi_orig->bi_connection_init;
682         if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
683                 bd->bd_info = oi->oi_orig;
684                 rc = func[ which ]( bd, conn );
685         }
686         /* should not fall thru this far without anything happening... */
687         if ( rc == SLAP_CB_CONTINUE ) {
688                 rc = LDAP_UNWILLING_TO_PERFORM;
689         }
690
691         return rc;
692 }
693
694 static int
695 over_connection_init(
696         BackendDB       *bd,
697         Connection      *conn
698 )
699 {
700         return over_connection_func( bd, conn, conn_init );
701 }
702
703 static int
704 over_connection_destroy(
705         BackendDB       *bd,
706         Connection      *conn
707 )
708 {
709         return over_connection_func( bd, conn, conn_destroy );
710 }
711
712 int
713 overlay_register(
714         slap_overinst *on
715 )
716 {
717         slap_overinst   *tmp;
718
719         /* FIXME: check for duplicates? */
720         for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) {
721                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) {
722                         Debug( LDAP_DEBUG_ANY,
723                                 "overlay_register(\"%s\"): "
724                                 "name already in use.\n",
725                                 on->on_bi.bi_type, 0, 0 );
726                         return -1;
727                 }
728
729                 if ( on->on_bi.bi_obsolete_names != NULL ) {
730                         int     i;
731
732                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
733                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) {
734                                         Debug( LDAP_DEBUG_ANY,
735                                                 "overlay_register(\"%s\"): "
736                                                 "obsolete name \"%s\" already in use "
737                                                 "by overlay \"%s\".\n",
738                                                 on->on_bi.bi_type,
739                                                 on->on_bi.bi_obsolete_names[ i ],
740                                                 tmp->on_bi.bi_type );
741                                         return -1;
742                                 }
743                         }
744                 }
745
746                 if ( tmp->on_bi.bi_obsolete_names != NULL ) {
747                         int     i;
748
749                         for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
750                                 int     j;
751
752                                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
753                                         Debug( LDAP_DEBUG_ANY,
754                                                 "overlay_register(\"%s\"): "
755                                                 "name already in use "
756                                                 "as obsolete by overlay \"%s\".\n",
757                                                 on->on_bi.bi_type,
758                                                 tmp->on_bi.bi_obsolete_names[ i ], 0 );
759                                         return -1;
760                                 }
761
762                                 if ( on->on_bi.bi_obsolete_names != NULL ) {
763                                         for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) {
764                                                 if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
765                                                         Debug( LDAP_DEBUG_ANY,
766                                                                 "overlay_register(\"%s\"): "
767                                                                 "obsolete name \"%s\" already in use "
768                                                                 "as obsolete by overlay \"%s\".\n",
769                                                                 on->on_bi.bi_type,
770                                                                 on->on_bi.bi_obsolete_names[ j ],
771                                                                 tmp->on_bi.bi_type );
772                                                         return -1;
773                                                 }
774                                         }
775                                 }
776                         }
777                 }
778         }
779
780         on->on_next = overlays;
781         overlays = on;
782         return 0;
783 }
784
785 /*
786  * iterator on registered overlays; overlay_next( NULL ) returns the first
787  * overlay; subsequent calls with the previously returned value allow to 
788  * iterate over the entire list; returns NULL when no more overlays are 
789  * registered.
790  */
791
792 slap_overinst *
793 overlay_next(
794         slap_overinst *on
795 )
796 {
797         if ( on == NULL ) {
798                 return overlays;
799         }
800
801         return on->on_next;
802 }
803
804 /*
805  * returns a specific registered overlay based on the type; NULL if not
806  * registered.
807  */
808
809 slap_overinst *
810 overlay_find( const char *over_type )
811 {
812         slap_overinst *on = overlays;
813
814         assert( over_type != NULL );
815
816         for ( ; on; on = on->on_next ) {
817                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
818                         goto foundit;
819                 }
820
821                 if ( on->on_bi.bi_obsolete_names != NULL ) {
822                         int     i;
823
824                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
825                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) {
826                                         Debug( LDAP_DEBUG_ANY,
827                                                 "overlay_find(\"%s\"): "
828                                                 "obsolete name for \"%s\".\n",
829                                                 on->on_bi.bi_obsolete_names[ i ],
830                                                 on->on_bi.bi_type, 0 );
831                                         goto foundit;
832                                 }
833                         }
834                 }
835         }
836
837 foundit:;
838         return on;
839 }
840
841 static const char overtype[] = "over";
842
843 /*
844  * returns TRUE (1) if the database is actually an overlay instance;
845  * FALSE (0) otherwise.
846  */
847
848 int
849 overlay_is_over( BackendDB *be )
850 {
851         return be->bd_info->bi_type == overtype;
852 }
853
854 /*
855  * returns TRUE (1) if the given database is actually an overlay
856  * instance and, somewhere in the list, contains the requested overlay;
857  * FALSE (0) otherwise.
858  */
859
860 int
861 overlay_is_inst( BackendDB *be, const char *over_type )
862 {
863         slap_overinst   *on;
864
865         assert( be != NULL );
866
867         if ( !overlay_is_over( be ) ) {
868                 return 0;
869         }
870         
871         on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
872         for ( ; on; on = on->on_next ) {
873                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
874                         return 1;
875                 }
876         }
877
878         return 0;
879 }
880
881 int
882 overlay_register_control( BackendDB *be, const char *oid )
883 {
884         int             gotit = 0;
885         int             cid;
886
887         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
888                 return -1;
889         }
890
891         if ( SLAP_ISGLOBALOVERLAY( be ) ) {
892                 BackendDB *bd;
893                 
894                 /* add to all backends... */
895                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
896                         if ( be == bd ) {
897                                 gotit = 1;
898                         }
899
900                         bd->be_ctrls[ cid ] = 1;
901                         bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
902                 }
903
904         }
905         
906         if ( !gotit ) {
907                 be->be_ctrls[ cid ] = 1;
908                 be->be_ctrls[ SLAP_MAX_CIDS ] = 1;
909         }
910
911         return 0;
912 }
913
914 void
915 overlay_destroy_one( BackendDB *be, slap_overinst *on )
916 {
917         slap_overinfo *oi = on->on_info;
918         slap_overinst **oidx;
919
920         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
921                 if ( *oidx == on ) {
922                         *oidx = on->on_next;
923                         if ( on->on_bi.bi_db_destroy ) {
924                                 BackendInfo *bi_orig = be->bd_info;
925                                 be->bd_info = (BackendInfo *)on;
926                                 on->on_bi.bi_db_destroy( be );
927                                 be->bd_info = bi_orig;
928                         }
929                         free( on );
930                         break;
931                 }
932         }
933 }
934
935 /* add an overlay to a particular backend. */
936 int
937 overlay_config( BackendDB *be, const char *ov )
938 {
939         slap_overinst *on = NULL, *on2 = NULL;
940         slap_overinfo *oi = NULL;
941         BackendInfo *bi = NULL;
942
943         on = overlay_find( ov );
944         if ( !on ) {
945                 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
946                 return 1;
947         }
948
949         /* If this is the first overlay on this backend, set up the
950          * overlay info structure
951          */
952         if ( !overlay_is_over( be ) ) {
953                 int     isglobal = 0;
954
955                 /* NOTE: the first time a global overlay is configured,
956                  * frontendDB gets this flag; it is used later by overlays
957                  * to determine if they're stacked on top of the frontendDB */
958                 if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) {
959                         isglobal = 1;
960                         if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) {
961                                 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
962                                         "overlay \"%s\" cannot be global.\n",
963                                         ov, 0, 0 );
964                                 return 1;
965                         }
966
967                 } else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) {
968                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
969                                 "overlay \"%s\" can only be global.\n",
970                                 ov, 0, 0 );
971                         return 1;
972                 }
973
974                 oi = ch_malloc( sizeof( slap_overinfo ) );
975                 oi->oi_orig = be->bd_info;
976                 oi->oi_bi = *be->bd_info;
977                 oi->oi_origdb = be;
978
979                 if ( isglobal ) {
980                         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
981                 }
982
983                 /* Save a pointer to ourself in bi_private.
984                  */
985                 oi->oi_bi.bi_private = oi;
986                 oi->oi_list = NULL;
987                 bi = (BackendInfo *)oi;
988
989                 bi->bi_type = (char *)overtype;
990
991                 bi->bi_db_config = over_db_config;
992                 bi->bi_db_open = over_db_open;
993                 bi->bi_db_close = over_db_close;
994                 bi->bi_db_destroy = over_db_destroy;
995
996                 bi->bi_op_bind = over_op_bind;
997                 bi->bi_op_unbind = over_op_unbind;
998                 bi->bi_op_search = over_op_search;
999                 bi->bi_op_compare = over_op_compare;
1000                 bi->bi_op_modify = over_op_modify;
1001                 bi->bi_op_modrdn = over_op_modrdn;
1002                 bi->bi_op_add = over_op_add;
1003                 bi->bi_op_delete = over_op_delete;
1004                 bi->bi_op_abandon = over_op_abandon;
1005                 bi->bi_op_cancel = over_op_cancel;
1006
1007                 bi->bi_extended = over_op_extended;
1008
1009                 /*
1010                  * this is fine because it has the same
1011                  * args of the operations; we need to rework
1012                  * all the hooks to share the same args
1013                  * of the operations...
1014                  */
1015                 bi->bi_operational = over_aux_operational;
1016                 bi->bi_chk_referrals = over_aux_chk_referrals;
1017                 bi->bi_chk_controls = over_aux_chk_controls;
1018
1019                 /* these have specific arglists */
1020                 bi->bi_access_allowed = over_access_allowed;
1021                 bi->bi_acl_group = over_acl_group;
1022                 bi->bi_acl_attribute = over_acl_attribute;
1023                 
1024                 bi->bi_connection_init = over_connection_init;
1025                 bi->bi_connection_destroy = over_connection_destroy;
1026
1027                 be->bd_info = bi;
1028
1029         } else {
1030                 if ( overlay_is_inst( be, ov ) ) {
1031                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1032                                 "overlay \"%s\" already in list\n",
1033                                 ov, 0, 0 );
1034                         if ( SLAPO_SINGLE( be ) ) {
1035                                 return 1;
1036                         }
1037                 }
1038
1039                 oi = be->bd_info->bi_private;
1040         }
1041
1042         /* Insert new overlay on head of list. Overlays are executed
1043          * in reverse of config order...
1044          */
1045         on2 = ch_calloc( 1, sizeof(slap_overinst) );
1046         *on2 = *on;
1047         on2->on_info = oi;
1048         on2->on_next = oi->oi_list;
1049         oi->oi_list = on2;
1050
1051         /* Any initialization needed? */
1052         if ( on->on_bi.bi_db_init ) {
1053                 int rc;
1054                 be->bd_info = (BackendInfo *)on2;
1055                 rc = on2->on_bi.bi_db_init( be );
1056                 be->bd_info = (BackendInfo *)oi;
1057                 if ( rc ) return rc;
1058         }
1059
1060         return 0;
1061 }
1062