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