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