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