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