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