]> git.sur5r.net Git - openldap/blob - servers/slapd/backover.c
Happy new year!
[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 #ifdef SLAP_OVERLAY_ACCESS
243 static int
244 over_access_allowed(
245         Operation               *op,
246         Entry                   *e,
247         AttributeDescription    *desc,
248         struct berval           *val,
249         slap_access_t           access,
250         AccessControlState      *state,
251         slap_mask_t             *maskp )
252 {
253         slap_overinfo *oi;
254         slap_overinst *on;
255         BackendInfo *bi;
256         BackendDB *be = op->o_bd, db;
257         int rc = SLAP_CB_CONTINUE;
258
259         /* FIXME: used to happen for instance during abandon
260          * when global overlays are used... */
261         assert( op->o_bd != NULL );
262
263         bi = op->o_bd->bd_info;
264         /* Were we invoked on the frontend? */
265         if ( !bi->bi_access_allowed ) {
266                 oi = frontendDB->bd_info->bi_private;
267         } else {
268                 oi = op->o_bd->bd_info->bi_private;
269         }
270         on = oi->oi_list;
271
272         for ( ; on; on = on->on_next ) {
273                 if ( on->on_bi.bi_access_allowed ) {
274                         /* NOTE: do not copy the structure until required */
275                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
276                                 db = *op->o_bd;
277                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
278                                 op->o_bd = &db;
279                         }
280
281                         op->o_bd->bd_info = (BackendInfo *)on;
282                         rc = on->on_bi.bi_access_allowed( op, e,
283                                 desc, val, access, state, maskp );
284                         if ( rc != SLAP_CB_CONTINUE ) break;
285                 }
286         }
287
288         if ( rc == SLAP_CB_CONTINUE ) {
289                 BI_access_allowed       *bi_access_allowed;
290
291                 /* if the database structure was changed, o_bd points to a
292                  * copy of the structure; put the original bd_info in place */
293                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
294                         op->o_bd->bd_info = oi->oi_orig;
295                 }
296
297                 if ( oi->oi_orig->bi_access_allowed ) {
298                         bi_access_allowed = oi->oi_orig->bi_access_allowed;
299                 } else {
300                         bi_access_allowed = slap_access_allowed;
301                 }
302
303                 rc = bi_access_allowed( op, e,
304                         desc, val, access, state, maskp );
305         }
306         /* should not fall thru this far without anything happening... */
307         if ( rc == SLAP_CB_CONTINUE ) {
308                 /* access not allowed */
309                 rc = 0;
310         }
311
312         op->o_bd = be;
313         op->o_bd->bd_info = bi;
314
315         return rc;
316 }
317
318 static int
319 over_acl_group(
320         Operation               *op,
321         Entry                   *e,
322         struct berval           *gr_ndn,
323         struct berval           *op_ndn,
324         ObjectClass             *group_oc,
325         AttributeDescription    *group_at )
326 {
327         slap_overinfo *oi;
328         slap_overinst *on;
329         BackendInfo *bi = op->o_bd->bd_info;
330         BackendDB *be = op->o_bd, db;
331         int rc = SLAP_CB_CONTINUE;
332
333         /* FIXME: used to happen for instance during abandon
334          * when global overlays are used... */
335         assert( op->o_bd != NULL );
336
337         oi = op->o_bd->bd_info->bi_private;
338         on = oi->oi_list;
339
340         for ( ; on; on = on->on_next ) {
341                 if ( on->on_bi.bi_acl_group ) {
342                         /* NOTE: do not copy the structure until required */
343                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
344                                 db = *op->o_bd;
345                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
346                                 op->o_bd = &db;
347                         }
348
349                         op->o_bd->bd_info = (BackendInfo *)on;
350                         rc = on->on_bi.bi_acl_group( op, e,
351                                 gr_ndn, op_ndn, group_oc, group_at );
352                         if ( rc != SLAP_CB_CONTINUE ) break;
353                 }
354         }
355
356         if ( rc == SLAP_CB_CONTINUE ) {
357                 BI_acl_group            *bi_acl_group;
358
359                 /* if the database structure was changed, o_bd points to a
360                  * copy of the structure; put the original bd_info in place */
361                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
362                         op->o_bd->bd_info = oi->oi_orig;
363                 }
364
365                 if ( oi->oi_orig->bi_acl_group ) {
366                         bi_acl_group = oi->oi_orig->bi_acl_group;
367                 } else {
368                         bi_acl_group = backend_group;
369                 }
370
371                 rc = bi_acl_group( op, e,
372                         gr_ndn, op_ndn, group_oc, group_at );
373         }
374         /* should not fall thru this far without anything happening... */
375         if ( rc == SLAP_CB_CONTINUE ) {
376                 /* access not allowed */
377                 rc = 0;
378         }
379
380         op->o_bd = be;
381         op->o_bd->bd_info = bi;
382
383         return rc;
384 }
385
386 static int
387 over_acl_attribute(
388         Operation               *op,
389         Entry                   *target,
390         struct berval           *entry_ndn,
391         AttributeDescription    *entry_at,
392         BerVarray               *vals,
393         slap_access_t           access )
394 {
395         slap_overinfo *oi;
396         slap_overinst *on;
397         BackendInfo *bi = op->o_bd->bd_info;
398         BackendDB *be = op->o_bd, db;
399         int rc = SLAP_CB_CONTINUE;
400
401         /* FIXME: used to happen for instance during abandon
402          * when global overlays are used... */
403         assert( op->o_bd != NULL );
404
405         oi = op->o_bd->bd_info->bi_private;
406         on = oi->oi_list;
407
408         for ( ; on; on = on->on_next ) {
409                 if ( on->on_bi.bi_acl_attribute ) {
410                         /* NOTE: do not copy the structure until required */
411                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
412                                 db = *op->o_bd;
413                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
414                                 op->o_bd = &db;
415                         }
416
417                         op->o_bd->bd_info = (BackendInfo *)on;
418                         rc = on->on_bi.bi_acl_attribute( op, target,
419                                 entry_ndn, entry_at, vals, access );
420                         if ( rc != SLAP_CB_CONTINUE ) break;
421                 }
422         }
423
424         if ( rc == SLAP_CB_CONTINUE ) {
425                 BI_acl_attribute                *bi_acl_attribute;
426
427                 /* if the database structure was changed, o_bd points to a
428                  * copy of the structure; put the original bd_info in place */
429                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
430                         op->o_bd->bd_info = oi->oi_orig;
431                 }
432
433                 if ( oi->oi_orig->bi_acl_attribute ) {
434                         bi_acl_attribute = oi->oi_orig->bi_acl_attribute;
435                 } else {
436                         bi_acl_attribute = backend_attribute;
437                 }
438
439                 rc = bi_acl_attribute( op, target,
440                         entry_ndn, entry_at, vals, access );
441         }
442         /* should not fall thru this far without anything happening... */
443         if ( rc == SLAP_CB_CONTINUE ) {
444                 /* access not allowed */
445                 rc = 0;
446         }
447
448         op->o_bd = be;
449         op->o_bd->bd_info = bi;
450
451         return rc;
452 }
453 #endif /* SLAP_OVERLAY_ACCESS */
454
455 /*
456  * default return code in case of missing backend function
457  * and overlay stack returning SLAP_CB_CONTINUE
458  */
459 static int op_rc[ op_last ] = {
460         LDAP_UNWILLING_TO_PERFORM,      /* bind */
461         LDAP_UNWILLING_TO_PERFORM,      /* unbind */
462         LDAP_UNWILLING_TO_PERFORM,      /* search */
463         SLAP_CB_CONTINUE,               /* compare; pass to frontend */
464         LDAP_UNWILLING_TO_PERFORM,      /* modify */
465         LDAP_UNWILLING_TO_PERFORM,      /* modrdn */
466         LDAP_UNWILLING_TO_PERFORM,      /* add */
467         LDAP_UNWILLING_TO_PERFORM,      /* delete */
468         LDAP_UNWILLING_TO_PERFORM,      /* abandon */
469         LDAP_UNWILLING_TO_PERFORM,      /* cancel */
470         LDAP_UNWILLING_TO_PERFORM,      /* extended */
471         LDAP_SUCCESS,                   /* aux_operational */
472         LDAP_SUCCESS,                   /* aux_chk_referrals */
473         SLAP_CB_CONTINUE                /* aux_chk_controls; pass to frontend */
474 };
475
476 int overlay_op_walk(
477         Operation *op,
478         SlapReply *rs,
479         slap_operation_t which,
480         slap_overinfo *oi,
481         slap_overinst *on
482 )
483 {
484         BI_op_bind **func;
485         int rc = SLAP_CB_CONTINUE;
486
487         for (; on; on=on->on_next ) {
488                 func = &on->on_bi.bi_op_bind;
489                 if ( func[which] ) {
490                         op->o_bd->bd_info = (BackendInfo *)on;
491                         rc = func[which]( op, rs );
492                         if ( rc != SLAP_CB_CONTINUE ) break;
493                 }
494         }
495
496         func = &oi->oi_orig->bi_op_bind;
497         if ( func[which] && rc == SLAP_CB_CONTINUE ) {
498                 op->o_bd->bd_info = oi->oi_orig;
499                 rc = func[which]( op, rs );
500         }
501         /* should not fall thru this far without anything happening... */
502         if ( rc == SLAP_CB_CONTINUE ) {
503                 rc = op_rc[ which ];
504         }
505
506         /* The underlying backend didn't handle the request, make sure
507          * overlay cleanup is processed.
508          */
509         if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
510                 slap_callback *sc_next;
511                 for ( ; op->o_callback && op->o_callback->sc_response !=
512                         over_back_response; op->o_callback = sc_next ) {
513                         sc_next = op->o_callback->sc_next;
514                         if ( op->o_callback->sc_cleanup ) {
515                                 op->o_callback->sc_cleanup( op, rs );
516                         }
517                 }
518         }
519         return rc;
520 }
521
522 static int
523 over_op_func(
524         Operation *op,
525         SlapReply *rs,
526         slap_operation_t which
527 )
528 {
529         slap_overinfo *oi;
530         slap_overinst *on;
531         BackendDB *be = op->o_bd, db;
532         slap_callback cb = {NULL, over_back_response, NULL, NULL};
533         int rc = SLAP_CB_CONTINUE;
534
535         /* FIXME: used to happen for instance during abandon
536          * when global overlays are used... */
537         assert( op->o_bd != NULL );
538
539         oi = op->o_bd->bd_info->bi_private;
540         on = oi->oi_list;
541
542         if ( !SLAP_ISOVERLAY( op->o_bd )) {
543                 db = *op->o_bd;
544                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
545                 op->o_bd = &db;
546         }
547         cb.sc_next = op->o_callback;
548         cb.sc_private = oi;
549         op->o_callback = &cb;
550
551         rc = overlay_op_walk( op, rs, which, oi, on );
552
553         op->o_bd = be;
554         op->o_callback = cb.sc_next;
555         return rc;
556 }
557
558 static int
559 over_op_bind( Operation *op, SlapReply *rs )
560 {
561         return over_op_func( op, rs, op_bind );
562 }
563
564 static int
565 over_op_unbind( Operation *op, SlapReply *rs )
566 {
567         return over_op_func( op, rs, op_unbind );
568 }
569
570 static int
571 over_op_search( Operation *op, SlapReply *rs )
572 {
573         return over_op_func( op, rs, op_search );
574 }
575
576 static int
577 over_op_compare( Operation *op, SlapReply *rs )
578 {
579         return over_op_func( op, rs, op_compare );
580 }
581
582 static int
583 over_op_modify( Operation *op, SlapReply *rs )
584 {
585         return over_op_func( op, rs, op_modify );
586 }
587
588 static int
589 over_op_modrdn( Operation *op, SlapReply *rs )
590 {
591         return over_op_func( op, rs, op_modrdn );
592 }
593
594 static int
595 over_op_add( Operation *op, SlapReply *rs )
596 {
597         return over_op_func( op, rs, op_add );
598 }
599
600 static int
601 over_op_delete( Operation *op, SlapReply *rs )
602 {
603         return over_op_func( op, rs, op_delete );
604 }
605
606 static int
607 over_op_abandon( Operation *op, SlapReply *rs )
608 {
609         return over_op_func( op, rs, op_abandon );
610 }
611
612 static int
613 over_op_cancel( Operation *op, SlapReply *rs )
614 {
615         return over_op_func( op, rs, op_cancel );
616 }
617
618 static int
619 over_op_extended( Operation *op, SlapReply *rs )
620 {
621         return over_op_func( op, rs, op_extended );
622 }
623
624 static int
625 over_aux_operational( Operation *op, SlapReply *rs )
626 {
627         return over_op_func( op, rs, op_aux_operational );
628 }
629
630 static int
631 over_aux_chk_referrals( Operation *op, SlapReply *rs )
632 {
633         return over_op_func( op, rs, op_aux_chk_referrals );
634 }
635
636 static int
637 over_aux_chk_controls( Operation *op, SlapReply *rs )
638 {
639         return over_op_func( op, rs, op_aux_chk_controls );
640 }
641
642 enum conn_which {
643         conn_init = 0,
644         conn_destroy,
645         conn_last
646 };
647
648 static int
649 over_connection_func(
650         BackendDB       *bd,
651         Connection      *conn,
652         enum conn_which which
653 )
654 {
655         slap_overinfo           *oi;
656         slap_overinst           *on;
657         BackendDB               db;
658         int                     rc = SLAP_CB_CONTINUE;
659         BI_connection_init      **func;
660
661         /* FIXME: used to happen for instance during abandon
662          * when global overlays are used... */
663         assert( bd != NULL );
664
665         oi = bd->bd_info->bi_private;
666         on = oi->oi_list;
667
668         if ( !SLAP_ISOVERLAY( bd ) ) {
669                 db = *bd;
670                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
671                 bd = &db;
672         }
673
674         for ( ; on; on = on->on_next ) {
675                 func = &on->on_bi.bi_connection_init;
676                 if ( func[ which ] ) {
677                         bd->bd_info = (BackendInfo *)on;
678                         rc = func[ which ]( bd, conn );
679                         if ( rc != SLAP_CB_CONTINUE ) break;
680                 }
681         }
682
683         func = &oi->oi_orig->bi_connection_init;
684         if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
685                 bd->bd_info = oi->oi_orig;
686                 rc = func[ which ]( bd, conn );
687         }
688         /* should not fall thru this far without anything happening... */
689         if ( rc == SLAP_CB_CONTINUE ) {
690                 rc = LDAP_UNWILLING_TO_PERFORM;
691         }
692
693         return rc;
694 }
695
696 static int
697 over_connection_init(
698         BackendDB       *bd,
699         Connection      *conn
700 )
701 {
702         return over_connection_func( bd, conn, conn_init );
703 }
704
705 static int
706 over_connection_destroy(
707         BackendDB       *bd,
708         Connection      *conn
709 )
710 {
711         return over_connection_func( bd, conn, conn_destroy );
712 }
713
714 int
715 overlay_register(
716         slap_overinst *on
717 )
718 {
719         slap_overinst   *tmp;
720
721         /* FIXME: check for duplicates? */
722         for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) {
723                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) {
724                         Debug( LDAP_DEBUG_ANY,
725                                 "overlay_register(\"%s\"): "
726                                 "name already in use.\n",
727                                 on->on_bi.bi_type, 0, 0 );
728                         return -1;
729                 }
730
731                 if ( on->on_bi.bi_obsolete_names != NULL ) {
732                         int     i;
733
734                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
735                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) {
736                                         Debug( LDAP_DEBUG_ANY,
737                                                 "overlay_register(\"%s\"): "
738                                                 "obsolete name \"%s\" already in use "
739                                                 "by overlay \"%s\".\n",
740                                                 on->on_bi.bi_type,
741                                                 on->on_bi.bi_obsolete_names[ i ],
742                                                 tmp->on_bi.bi_type );
743                                         return -1;
744                                 }
745                         }
746                 }
747
748                 if ( tmp->on_bi.bi_obsolete_names != NULL ) {
749                         int     i;
750
751                         for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
752                                 int     j;
753
754                                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
755                                         Debug( LDAP_DEBUG_ANY,
756                                                 "overlay_register(\"%s\"): "
757                                                 "name already in use "
758                                                 "as obsolete by overlay \"%s\".\n",
759                                                 on->on_bi.bi_type,
760                                                 tmp->on_bi.bi_obsolete_names[ i ], 0 );
761                                         return -1;
762                                 }
763
764                                 if ( on->on_bi.bi_obsolete_names != NULL ) {
765                                         for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) {
766                                                 if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
767                                                         Debug( LDAP_DEBUG_ANY,
768                                                                 "overlay_register(\"%s\"): "
769                                                                 "obsolete name \"%s\" already in use "
770                                                                 "as obsolete by overlay \"%s\".\n",
771                                                                 on->on_bi.bi_type,
772                                                                 on->on_bi.bi_obsolete_names[ j ],
773                                                                 tmp->on_bi.bi_type );
774                                                         return -1;
775                                                 }
776                                         }
777                                 }
778                         }
779                 }
780         }
781
782         on->on_next = overlays;
783         overlays = on;
784         return 0;
785 }
786
787 /*
788  * iterator on registered overlays; overlay_next( NULL ) returns the first
789  * overlay; subsequent calls with the previously returned value allow to 
790  * iterate over the entire list; returns NULL when no more overlays are 
791  * registered.
792  */
793
794 slap_overinst *
795 overlay_next(
796         slap_overinst *on
797 )
798 {
799         if ( on == NULL ) {
800                 return overlays;
801         }
802
803         return on->on_next;
804 }
805
806 /*
807  * returns a specific registered overlay based on the type; NULL if not
808  * registered.
809  */
810
811 slap_overinst *
812 overlay_find( const char *over_type )
813 {
814         slap_overinst *on = overlays;
815
816         assert( over_type != NULL );
817
818         for ( ; on; on = on->on_next ) {
819                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
820                         goto foundit;
821                 }
822
823                 if ( on->on_bi.bi_obsolete_names != NULL ) {
824                         int     i;
825
826                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
827                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) {
828                                         Debug( LDAP_DEBUG_ANY,
829                                                 "overlay_find(\"%s\"): "
830                                                 "obsolete name for \"%s\".\n",
831                                                 on->on_bi.bi_obsolete_names[ i ],
832                                                 on->on_bi.bi_type, 0 );
833                                         goto foundit;
834                                 }
835                         }
836                 }
837         }
838
839 foundit:;
840         return on;
841 }
842
843 static const char overtype[] = "over";
844
845 /*
846  * returns TRUE (1) if the database is actually an overlay instance;
847  * FALSE (0) otherwise.
848  */
849
850 int
851 overlay_is_over( BackendDB *be )
852 {
853         return be->bd_info->bi_type == overtype;
854 }
855
856 /*
857  * returns TRUE (1) if the given database is actually an overlay
858  * instance and, somewhere in the list, contains the requested overlay;
859  * FALSE (0) otherwise.
860  */
861
862 int
863 overlay_is_inst( BackendDB *be, const char *over_type )
864 {
865         slap_overinst   *on;
866
867         assert( be != NULL );
868
869         if ( !overlay_is_over( be ) ) {
870                 return 0;
871         }
872         
873         on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
874         for ( ; on; on = on->on_next ) {
875                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
876                         return 1;
877                 }
878         }
879
880         return 0;
881 }
882
883 int
884 overlay_register_control( BackendDB *be, const char *oid )
885 {
886         int             gotit = 0;
887         int             cid;
888
889         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
890                 return -1;
891         }
892
893         if ( SLAP_ISGLOBALOVERLAY( be ) ) {
894                 BackendDB *bd;
895                 
896                 /* add to all backends... */
897                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
898                         if ( be == bd ) {
899                                 gotit = 1;
900                         }
901
902                         bd->be_ctrls[ cid ] = 1;
903                         bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
904                 }
905
906         }
907         
908         if ( !gotit ) {
909                 be->be_ctrls[ cid ] = 1;
910                 be->be_ctrls[ SLAP_MAX_CIDS ] = 1;
911         }
912
913         return 0;
914 }
915
916 void
917 overlay_destroy_one( BackendDB *be, slap_overinst *on )
918 {
919         slap_overinfo *oi = on->on_info;
920         slap_overinst **oidx;
921
922         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
923                 if ( *oidx == on ) {
924                         *oidx = on->on_next;
925                         if ( on->on_bi.bi_db_destroy ) {
926                                 BackendInfo *bi_orig = be->bd_info;
927                                 be->bd_info = (BackendInfo *)on;
928                                 on->on_bi.bi_db_destroy( be );
929                                 be->bd_info = bi_orig;
930                         }
931                         free( on );
932                         break;
933                 }
934         }
935 }
936
937 /* add an overlay to a particular backend. */
938 int
939 overlay_config( BackendDB *be, const char *ov )
940 {
941         slap_overinst *on = NULL, *on2 = NULL;
942         slap_overinfo *oi = NULL;
943         BackendInfo *bi = NULL;
944
945         on = overlay_find( ov );
946         if ( !on ) {
947                 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
948                 return 1;
949         }
950
951         /* If this is the first overlay on this backend, set up the
952          * overlay info structure
953          */
954         if ( !overlay_is_over( be ) ) {
955                 oi = ch_malloc( sizeof( slap_overinfo ) );
956                 oi->oi_orig = be->bd_info;
957                 oi->oi_bi = *be->bd_info;
958                 oi->oi_origdb = be;
959
960                 /* NOTE: the first time a global overlay is configured,
961                  * frontendDB gets this flag; it is used later by overlays
962                  * to determine if they're stacked on top of the frontendDB */
963                 if ( oi->oi_orig == frontendDB->bd_info ) {
964                         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
965                 }
966
967                 /* Save a pointer to ourself in bi_private.
968                  */
969                 oi->oi_bi.bi_private = oi;
970                 oi->oi_list = NULL;
971                 bi = (BackendInfo *)oi;
972
973                 bi->bi_type = (char *)overtype;
974
975                 bi->bi_db_config = over_db_config;
976                 bi->bi_db_open = over_db_open;
977                 bi->bi_db_close = over_db_close;
978                 bi->bi_db_destroy = over_db_destroy;
979
980                 bi->bi_op_bind = over_op_bind;
981                 bi->bi_op_unbind = over_op_unbind;
982                 bi->bi_op_search = over_op_search;
983                 bi->bi_op_compare = over_op_compare;
984                 bi->bi_op_modify = over_op_modify;
985                 bi->bi_op_modrdn = over_op_modrdn;
986                 bi->bi_op_add = over_op_add;
987                 bi->bi_op_delete = over_op_delete;
988                 bi->bi_op_abandon = over_op_abandon;
989                 bi->bi_op_cancel = over_op_cancel;
990
991                 bi->bi_extended = over_op_extended;
992
993                 /*
994                  * this is fine because it has the same
995                  * args of the operations; we need to rework
996                  * all the hooks to share the same args
997                  * of the operations...
998                  */
999                 bi->bi_operational = over_aux_operational;
1000                 bi->bi_chk_referrals = over_aux_chk_referrals;
1001                 bi->bi_chk_controls = over_aux_chk_controls;
1002
1003 #ifdef SLAP_OVERLAY_ACCESS
1004                 /* these have specific arglists */
1005                 bi->bi_access_allowed = over_access_allowed;
1006                 bi->bi_acl_group = over_acl_group;
1007                 bi->bi_acl_attribute = over_acl_attribute;
1008 #endif /* SLAP_OVERLAY_ACCESS */
1009                 
1010                 bi->bi_connection_init = over_connection_init;
1011                 bi->bi_connection_destroy = over_connection_destroy;
1012
1013                 be->bd_info = bi;
1014
1015         } else {
1016                 if ( overlay_is_inst( be, ov ) ) {
1017                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1018                                         "warning, overlay \"%s\" "
1019                                         "already in list\n", ov, 0, 0 );
1020                 }
1021
1022                 oi = be->bd_info->bi_private;
1023         }
1024
1025         /* Insert new overlay on head of list. Overlays are executed
1026          * in reverse of config order...
1027          */
1028         on2 = ch_calloc( 1, sizeof(slap_overinst) );
1029         *on2 = *on;
1030         on2->on_info = oi;
1031         on2->on_next = oi->oi_list;
1032         oi->oi_list = on2;
1033
1034         /* Any initialization needed? */
1035         if ( on->on_bi.bi_db_init ) {
1036                 int rc;
1037                 be->bd_info = (BackendInfo *)on2;
1038                 rc = on2->on_bi.bi_db_init( be );
1039                 be->bd_info = (BackendInfo *)oi;
1040                 if ( rc ) return rc;
1041         }
1042
1043         return 0;
1044 }
1045