]> git.sur5r.net Git - openldap/blob - servers/slapd/backover.c
e14a0192a58a967e42a4c25f18c52ccfd1163140
[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-2008 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 static int
33 over_db_config(
34         BackendDB *be,
35         const char *fname,
36         int lineno,
37         int argc,
38         char **argv
39 )
40 {
41         slap_overinfo *oi = be->bd_info->bi_private;
42         slap_overinst *on = oi->oi_list;
43         BackendInfo *bi_orig = be->bd_info;
44         struct ConfigOCs *be_cf_ocs = be->be_cf_ocs;
45         ConfigArgs ca = {0};
46         int rc = 0;
47
48         if ( oi->oi_orig->bi_db_config ) {
49                 be->bd_info = oi->oi_orig;
50                 be->be_cf_ocs = oi->oi_orig->bi_cf_ocs;
51                 rc = oi->oi_orig->bi_db_config( be, fname, lineno,
52                         argc, argv );
53
54                 if ( be->bd_info != oi->oi_orig ) {
55                         slap_overinfo   *oi2;
56                         slap_overinst   *on2, **onp;
57                         BackendDB       be2 = *be;
58                         int             i;
59
60                         /* a database added an overlay;
61                          * work it around... */
62                         assert( overlay_is_over( be ) );
63                         
64                         oi2 = ( slap_overinfo * )be->bd_info->bi_private;
65                         on2 = oi2->oi_list;
66
67                         /* need to put a uniqueness check here as well;
68                          * note that in principle there could be more than
69                          * one overlay as a result of multiple calls to
70                          * overlay_config() */
71                         be2.bd_info = (BackendInfo *)oi;
72
73                         for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
74                                 if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
75                                         Debug( LDAP_DEBUG_ANY, "over_db_config(): "
76                                                         "warning, freshly added "
77                                                         "overlay #%d \"%s\" is already in list\n",
78                                                         i, (*onp)->on_bi.bi_type, 0 );
79
80                                         /* NOTE: if the overlay already exists,
81                                          * there is no way to merge the results
82                                          * of the configuration that may have 
83                                          * occurred during bi_db_config(); we
84                                          * just issue a warning, and the 
85                                          * administrator should deal with this */
86                                 }
87                         }
88                         *onp = oi->oi_list;
89
90                         oi->oi_list = on2;
91
92                         ch_free( be->bd_info );
93                 }
94
95                 be->bd_info = (BackendInfo *)oi;
96                 if ( rc != SLAP_CONF_UNKNOWN ) return rc;
97         }
98
99         ca.argv = argv;
100         ca.argc = argc;
101         ca.fname = fname;
102         ca.lineno = lineno;
103         ca.be = be;
104         snprintf( ca.log, sizeof( ca.log ), "%s: line %d",
105                         ca.fname, ca.lineno );
106
107         for (; on; on=on->on_next) {
108                 rc = SLAP_CONF_UNKNOWN;
109                 if (on->on_bi.bi_cf_ocs) {
110                         ConfigTable *ct;
111                         ca.bi = &on->on_bi;
112                         ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca );
113                         if ( ct ) {
114                                 ca.table = on->on_bi.bi_cf_ocs->co_type;
115                                 rc = config_add_vals( ct, &ca );
116                                 if ( rc != SLAP_CONF_UNKNOWN )
117                                         break;
118                         }
119                 }
120                 if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) {
121                         be->bd_info = &on->on_bi;
122                         rc = on->on_bi.bi_db_config( be, fname, lineno,
123                                 argc, argv );
124                         if ( rc != SLAP_CONF_UNKNOWN ) break;
125                 }
126         }
127         be->bd_info = bi_orig;
128         be->be_cf_ocs = be_cf_ocs;
129         
130         return rc;
131 }
132
133 static int
134 over_db_open(
135         BackendDB *be,
136         ConfigReply *cr
137 )
138 {
139         slap_overinfo *oi = be->bd_info->bi_private;
140         slap_overinst *on = oi->oi_list;
141         BackendDB db = *be;
142         int rc = 0;
143
144         db.be_flags |= SLAP_DBFLAG_OVERLAY;
145         db.bd_info = oi->oi_orig;
146         if ( db.bd_info->bi_db_open ) {
147                 rc = db.bd_info->bi_db_open( &db, cr );
148         }
149
150         for (; on && rc == 0; on=on->on_next) {
151                 db.bd_info = &on->on_bi;
152                 if ( db.bd_info->bi_db_open ) {
153                         rc = db.bd_info->bi_db_open( &db, cr );
154                 }
155         }
156
157         return rc;
158 }
159
160 static int
161 over_db_close(
162         BackendDB *be,
163         ConfigReply *cr
164 )
165 {
166         slap_overinfo *oi = be->bd_info->bi_private;
167         slap_overinst *on = oi->oi_list;
168         BackendInfo *bi_orig = be->bd_info;
169         int rc = 0;
170
171         for (; on && rc == 0; on=on->on_next) {
172                 be->bd_info = &on->on_bi;
173                 if ( be->bd_info->bi_db_close ) {
174                         rc = be->bd_info->bi_db_close( be, cr );
175                 }
176         }
177
178         if ( oi->oi_orig->bi_db_close ) {
179                 be->bd_info = oi->oi_orig;
180                 rc = be->bd_info->bi_db_close( be, cr );
181         }
182
183         be->bd_info = bi_orig;
184         return rc;
185 }
186
187 static int
188 over_db_destroy(
189         BackendDB *be,
190         ConfigReply *cr
191 )
192 {
193         slap_overinfo *oi = be->bd_info->bi_private;
194         slap_overinst *on = oi->oi_list, *next;
195         BackendInfo *bi_orig = be->bd_info;
196         int rc = 0;
197
198         be->bd_info = oi->oi_orig;
199         if ( be->bd_info->bi_db_destroy ) {
200                 rc = be->bd_info->bi_db_destroy( be, cr );
201         }
202
203         for (; on && rc == 0; on=on->on_next) {
204                 be->bd_info = &on->on_bi;
205                 if ( be->bd_info->bi_db_destroy ) {
206                         rc = be->bd_info->bi_db_destroy( be, cr );
207                 }
208         }
209
210         on = oi->oi_list;
211         if ( on ) {
212                 for (next = on->on_next; on; on=next) {
213                         next = on->on_next;
214                         free( on );
215                 }
216         }
217         be->bd_info = bi_orig;
218         free( oi );
219         return rc;
220 }
221
222 static int
223 over_back_response ( Operation *op, SlapReply *rs )
224 {
225         slap_overinfo *oi = op->o_callback->sc_private;
226         slap_overinst *on = oi->oi_list;
227         int rc = SLAP_CB_CONTINUE;
228         BackendDB *be = op->o_bd, db = *op->o_bd;
229
230         db.be_flags |= SLAP_DBFLAG_OVERLAY;
231         op->o_bd = &db;
232         for (; on; on=on->on_next ) {
233                 if ( on->on_response ) {
234                         db.bd_info = (BackendInfo *)on;
235                         rc = on->on_response( op, rs );
236                         if ( rc != SLAP_CB_CONTINUE ) break;
237                 }
238         }
239         /* Bypass the remaining on_response layers, but allow
240          * normal execution to continue.
241          */
242         if ( rc == SLAP_CB_BYPASS )
243                 rc = SLAP_CB_CONTINUE;
244         op->o_bd = be;
245         return rc;
246 }
247
248 static int
249 over_access_allowed(
250         Operation               *op,
251         Entry                   *e,
252         AttributeDescription    *desc,
253         struct berval           *val,
254         slap_access_t           access,
255         AccessControlState      *state,
256         slap_mask_t             *maskp )
257 {
258         slap_overinfo *oi;
259         slap_overinst *on;
260         BackendInfo *bi;
261         BackendDB *be = op->o_bd, db;
262         int rc = SLAP_CB_CONTINUE;
263
264         /* FIXME: used to happen for instance during abandon
265          * when global overlays are used... */
266         assert( op->o_bd != NULL );
267
268         bi = op->o_bd->bd_info;
269         /* Were we invoked on the frontend? */
270         if ( !bi->bi_access_allowed ) {
271                 oi = frontendDB->bd_info->bi_private;
272         } else {
273                 oi = op->o_bd->bd_info->bi_private;
274         }
275         on = oi->oi_list;
276
277         for ( ; on; on = on->on_next ) {
278                 if ( on->on_bi.bi_access_allowed ) {
279                         /* NOTE: do not copy the structure until required */
280                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
281                                 db = *op->o_bd;
282                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
283                                 op->o_bd = &db;
284                         }
285
286                         op->o_bd->bd_info = (BackendInfo *)on;
287                         rc = on->on_bi.bi_access_allowed( op, e,
288                                 desc, val, access, state, maskp );
289                         if ( rc != SLAP_CB_CONTINUE ) break;
290                 }
291         }
292
293         if ( rc == SLAP_CB_CONTINUE ) {
294                 BI_access_allowed       *bi_access_allowed;
295
296                 /* if the database structure was changed, o_bd points to a
297                  * copy of the structure; put the original bd_info in place */
298                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
299                         op->o_bd->bd_info = oi->oi_orig;
300                 }
301
302                 if ( oi->oi_orig->bi_access_allowed ) {
303                         bi_access_allowed = oi->oi_orig->bi_access_allowed;
304                 } else {
305                         bi_access_allowed = slap_access_allowed;
306                 }
307
308                 rc = bi_access_allowed( op, e,
309                         desc, val, access, state, maskp );
310         }
311         /* should not fall thru this far without anything happening... */
312         if ( rc == SLAP_CB_CONTINUE ) {
313                 /* access not allowed */
314                 rc = 0;
315         }
316
317         op->o_bd = be;
318         op->o_bd->bd_info = bi;
319
320         return rc;
321 }
322
323 int
324 overlay_entry_get_ov(
325         Operation               *op,
326         struct berval   *dn,
327         ObjectClass             *oc,
328         AttributeDescription    *ad,
329         int     rw,
330         Entry   **e,
331         slap_overinst *on )
332 {
333         slap_overinfo *oi = on->on_info;
334         BackendDB *be = op->o_bd, db;
335         BackendInfo *bi = op->o_bd->bd_info;
336         int rc = SLAP_CB_CONTINUE;
337
338         for ( ; on; on = on->on_next ) {
339                 if ( on->on_bi.bi_entry_get_rw ) {
340                         /* NOTE: do not copy the structure until required */
341                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
342                                 db = *op->o_bd;
343                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
344                                 op->o_bd = &db;
345                         }
346
347                         op->o_bd->bd_info = (BackendInfo *)on;
348                         rc = on->on_bi.bi_entry_get_rw( op, dn,
349                                 oc, ad, rw, e );
350                         if ( rc != SLAP_CB_CONTINUE ) break;
351                 }
352         }
353
354         if ( rc == SLAP_CB_CONTINUE ) {
355                 /* if the database structure was changed, o_bd points to a
356                  * copy of the structure; put the original bd_info in place */
357                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
358                         op->o_bd->bd_info = oi->oi_orig;
359                 }
360
361                 if ( oi->oi_orig->bi_entry_get_rw ) {
362                         rc = oi->oi_orig->bi_entry_get_rw( op, dn,
363                                 oc, ad, rw, e );
364                 }
365         }
366         /* should not fall thru this far without anything happening... */
367         if ( rc == SLAP_CB_CONTINUE ) {
368                 rc = LDAP_UNWILLING_TO_PERFORM;
369         }
370
371         op->o_bd = be;
372         op->o_bd->bd_info = bi;
373
374         return rc;
375 }
376
377 static int
378 over_entry_get_rw(
379         Operation               *op,
380         struct berval   *dn,
381         ObjectClass             *oc,
382         AttributeDescription    *ad,
383         int     rw,
384         Entry   **e )
385 {
386         slap_overinfo *oi;
387         slap_overinst *on;
388
389         assert( op->o_bd != NULL );
390
391         oi = op->o_bd->bd_info->bi_private;
392         on = oi->oi_list;
393
394         return overlay_entry_get_ov( op, dn, oc, ad, rw, e, on );
395 }
396
397 int
398 overlay_entry_release_ov(
399         Operation       *op,
400         Entry   *e,
401         int rw,
402         slap_overinst *on )
403 {
404         slap_overinfo *oi = on->on_info;
405         BackendDB *be = op->o_bd, db;
406         BackendInfo *bi = op->o_bd->bd_info;
407         int rc = SLAP_CB_CONTINUE;
408
409         for ( ; on; on = on->on_next ) {
410                 if ( on->on_bi.bi_entry_release_rw ) {
411                         /* NOTE: do not copy the structure until required */
412                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
413                                 db = *op->o_bd;
414                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
415                                 op->o_bd = &db;
416                         }
417
418                         op->o_bd->bd_info = (BackendInfo *)on;
419                         rc = on->on_bi.bi_entry_release_rw( op, e, rw );
420                         if ( rc != SLAP_CB_CONTINUE ) break;
421                 }
422         }
423
424         if ( rc == SLAP_CB_CONTINUE ) {
425                 /* if the database structure was changed, o_bd points to a
426                  * copy of the structure; put the original bd_info in place */
427                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
428                         op->o_bd->bd_info = oi->oi_orig;
429                 }
430
431                 if ( oi->oi_orig->bi_entry_release_rw ) {
432                         rc = oi->oi_orig->bi_entry_release_rw( op, e, rw );
433                 }
434         }
435         /* should not fall thru this far without anything happening... */
436         if ( rc == SLAP_CB_CONTINUE ) {
437                 entry_free( e );
438                 rc = 0;
439         }
440
441         op->o_bd = be;
442         op->o_bd->bd_info = bi;
443
444         return rc;
445 }
446
447 static int
448 over_entry_release_rw(
449         Operation       *op,
450         Entry   *e,
451         int rw )
452 {
453         slap_overinfo *oi;
454         slap_overinst *on;
455
456         assert( op->o_bd != NULL );
457
458         oi = op->o_bd->bd_info->bi_private;
459         on = oi->oi_list;
460
461         return overlay_entry_release_ov( op, e, rw, on );
462 }
463
464 static int
465 over_acl_group(
466         Operation               *op,
467         Entry                   *e,
468         struct berval           *gr_ndn,
469         struct berval           *op_ndn,
470         ObjectClass             *group_oc,
471         AttributeDescription    *group_at )
472 {
473         slap_overinfo *oi;
474         slap_overinst *on;
475         BackendInfo *bi = op->o_bd->bd_info;
476         BackendDB *be = op->o_bd, db;
477         int rc = SLAP_CB_CONTINUE;
478
479         /* FIXME: used to happen for instance during abandon
480          * when global overlays are used... */
481         assert( op->o_bd != NULL );
482
483         oi = op->o_bd->bd_info->bi_private;
484         on = oi->oi_list;
485
486         for ( ; on; on = on->on_next ) {
487                 if ( on->on_bi.bi_acl_group ) {
488                         /* NOTE: do not copy the structure until required */
489                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
490                                 db = *op->o_bd;
491                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
492                                 op->o_bd = &db;
493                         }
494
495                         op->o_bd->bd_info = (BackendInfo *)on;
496                         rc = on->on_bi.bi_acl_group( op, e,
497                                 gr_ndn, op_ndn, group_oc, group_at );
498                         if ( rc != SLAP_CB_CONTINUE ) break;
499                 }
500         }
501
502         if ( rc == SLAP_CB_CONTINUE ) {
503                 BI_acl_group            *bi_acl_group;
504
505                 /* if the database structure was changed, o_bd points to a
506                  * copy of the structure; put the original bd_info in place */
507                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
508                         op->o_bd->bd_info = oi->oi_orig;
509                 }
510
511                 if ( oi->oi_orig->bi_acl_group ) {
512                         bi_acl_group = oi->oi_orig->bi_acl_group;
513                 } else {
514                         bi_acl_group = backend_group;
515                 }
516
517                 rc = bi_acl_group( op, e,
518                         gr_ndn, op_ndn, group_oc, group_at );
519         }
520         /* should not fall thru this far without anything happening... */
521         if ( rc == SLAP_CB_CONTINUE ) {
522                 /* access not allowed */
523                 rc = 0;
524         }
525
526         op->o_bd = be;
527         op->o_bd->bd_info = bi;
528
529         return rc;
530 }
531
532 static int
533 over_acl_attribute(
534         Operation               *op,
535         Entry                   *target,
536         struct berval           *entry_ndn,
537         AttributeDescription    *entry_at,
538         BerVarray               *vals,
539         slap_access_t           access )
540 {
541         slap_overinfo *oi;
542         slap_overinst *on;
543         BackendInfo *bi = op->o_bd->bd_info;
544         BackendDB *be = op->o_bd, db;
545         int rc = SLAP_CB_CONTINUE;
546
547         /* FIXME: used to happen for instance during abandon
548          * when global overlays are used... */
549         assert( op->o_bd != NULL );
550
551         oi = op->o_bd->bd_info->bi_private;
552         on = oi->oi_list;
553
554         for ( ; on; on = on->on_next ) {
555                 if ( on->on_bi.bi_acl_attribute ) {
556                         /* NOTE: do not copy the structure until required */
557                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
558                                 db = *op->o_bd;
559                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
560                                 op->o_bd = &db;
561                         }
562
563                         op->o_bd->bd_info = (BackendInfo *)on;
564                         rc = on->on_bi.bi_acl_attribute( op, target,
565                                 entry_ndn, entry_at, vals, access );
566                         if ( rc != SLAP_CB_CONTINUE ) break;
567                 }
568         }
569
570         if ( rc == SLAP_CB_CONTINUE ) {
571                 BI_acl_attribute                *bi_acl_attribute;
572
573                 /* if the database structure was changed, o_bd points to a
574                  * copy of the structure; put the original bd_info in place */
575                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
576                         op->o_bd->bd_info = oi->oi_orig;
577                 }
578
579                 if ( oi->oi_orig->bi_acl_attribute ) {
580                         bi_acl_attribute = oi->oi_orig->bi_acl_attribute;
581                 } else {
582                         bi_acl_attribute = backend_attribute;
583                 }
584
585                 rc = bi_acl_attribute( op, target,
586                         entry_ndn, entry_at, vals, access );
587         }
588         /* should not fall thru this far without anything happening... */
589         if ( rc == SLAP_CB_CONTINUE ) {
590                 /* access not allowed */
591                 rc = 0;
592         }
593
594         op->o_bd = be;
595         op->o_bd->bd_info = bi;
596
597         return rc;
598 }
599
600 int
601 overlay_callback_after_backover( Operation *op, slap_callback *sc, int append )
602 {
603         slap_callback **scp;
604
605         for ( scp = &op->o_callback; *scp != NULL; scp = &(*scp)->sc_next ) {
606                 if ( (*scp)->sc_response == over_back_response ) {
607                         sc->sc_next = (*scp)->sc_next;
608                         (*scp)->sc_next = sc;
609                         return 0;
610                 }
611         }
612
613         if ( append ) {
614                 *scp = sc;
615                 return 0;
616         }
617
618         return 1;
619 }
620
621 /*
622  * default return code in case of missing backend function
623  * and overlay stack returning SLAP_CB_CONTINUE
624  */
625 static int op_rc[ op_last ] = {
626         LDAP_UNWILLING_TO_PERFORM,      /* bind */
627         LDAP_UNWILLING_TO_PERFORM,      /* unbind */
628         LDAP_UNWILLING_TO_PERFORM,      /* search */
629         SLAP_CB_CONTINUE,               /* compare; pass to frontend */
630         LDAP_UNWILLING_TO_PERFORM,      /* modify */
631         LDAP_UNWILLING_TO_PERFORM,      /* modrdn */
632         LDAP_UNWILLING_TO_PERFORM,      /* add */
633         LDAP_UNWILLING_TO_PERFORM,      /* delete */
634         LDAP_UNWILLING_TO_PERFORM,      /* abandon */
635         LDAP_UNWILLING_TO_PERFORM,      /* cancel */
636         LDAP_UNWILLING_TO_PERFORM,      /* extended */
637         LDAP_SUCCESS,                   /* aux_operational */
638         LDAP_SUCCESS,                   /* aux_chk_referrals */
639         SLAP_CB_CONTINUE                /* aux_chk_controls; pass to frontend */
640 };
641
642 int overlay_op_walk(
643         Operation *op,
644         SlapReply *rs,
645         slap_operation_t which,
646         slap_overinfo *oi,
647         slap_overinst *on
648 )
649 {
650         BI_op_bind **func;
651         int rc = SLAP_CB_CONTINUE;
652
653         for (; on; on=on->on_next ) {
654                 func = &on->on_bi.bi_op_bind;
655                 if ( func[which] ) {
656                         op->o_bd->bd_info = (BackendInfo *)on;
657                         rc = func[which]( op, rs );
658                         if ( rc != SLAP_CB_CONTINUE ) break;
659                 }
660         }
661         if ( rc == SLAP_CB_BYPASS )
662                 rc = SLAP_CB_CONTINUE;
663
664         func = &oi->oi_orig->bi_op_bind;
665         if ( func[which] && rc == SLAP_CB_CONTINUE ) {
666                 op->o_bd->bd_info = oi->oi_orig;
667                 rc = func[which]( op, rs );
668         }
669         /* should not fall thru this far without anything happening... */
670         if ( rc == SLAP_CB_CONTINUE ) {
671                 rc = op_rc[ which ];
672         }
673
674         /* The underlying backend didn't handle the request, make sure
675          * overlay cleanup is processed.
676          */
677         if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
678                 slap_callback *sc_next;
679                 for ( ; op->o_callback && op->o_callback->sc_response !=
680                         over_back_response; op->o_callback = sc_next ) {
681                         sc_next = op->o_callback->sc_next;
682                         if ( op->o_callback->sc_cleanup ) {
683                                 op->o_callback->sc_cleanup( op, rs );
684                         }
685                 }
686         }
687         return rc;
688 }
689
690 static int
691 over_op_func(
692         Operation *op,
693         SlapReply *rs,
694         slap_operation_t which
695 )
696 {
697         slap_overinfo *oi;
698         slap_overinst *on;
699         BackendDB *be = op->o_bd, db;
700         slap_callback cb = {NULL, over_back_response, NULL, NULL};
701         int rc = SLAP_CB_CONTINUE;
702
703         /* FIXME: used to happen for instance during abandon
704          * when global overlays are used... */
705         assert( op->o_bd != NULL );
706
707         oi = op->o_bd->bd_info->bi_private;
708         on = oi->oi_list;
709
710         if ( !SLAP_ISOVERLAY( op->o_bd )) {
711                 db = *op->o_bd;
712                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
713                 op->o_bd = &db;
714         }
715         cb.sc_next = op->o_callback;
716         cb.sc_private = oi;
717         op->o_callback = &cb;
718
719         rc = overlay_op_walk( op, rs, which, oi, on );
720
721         op->o_bd = be;
722         op->o_callback = cb.sc_next;
723         return rc;
724 }
725
726 static int
727 over_op_bind( Operation *op, SlapReply *rs )
728 {
729         return over_op_func( op, rs, op_bind );
730 }
731
732 static int
733 over_op_unbind( Operation *op, SlapReply *rs )
734 {
735         return over_op_func( op, rs, op_unbind );
736 }
737
738 static int
739 over_op_search( Operation *op, SlapReply *rs )
740 {
741         return over_op_func( op, rs, op_search );
742 }
743
744 static int
745 over_op_compare( Operation *op, SlapReply *rs )
746 {
747         return over_op_func( op, rs, op_compare );
748 }
749
750 static int
751 over_op_modify( Operation *op, SlapReply *rs )
752 {
753         return over_op_func( op, rs, op_modify );
754 }
755
756 static int
757 over_op_modrdn( Operation *op, SlapReply *rs )
758 {
759         return over_op_func( op, rs, op_modrdn );
760 }
761
762 static int
763 over_op_add( Operation *op, SlapReply *rs )
764 {
765         return over_op_func( op, rs, op_add );
766 }
767
768 static int
769 over_op_delete( Operation *op, SlapReply *rs )
770 {
771         return over_op_func( op, rs, op_delete );
772 }
773
774 static int
775 over_op_abandon( Operation *op, SlapReply *rs )
776 {
777         return over_op_func( op, rs, op_abandon );
778 }
779
780 static int
781 over_op_cancel( Operation *op, SlapReply *rs )
782 {
783         return over_op_func( op, rs, op_cancel );
784 }
785
786 static int
787 over_op_extended( Operation *op, SlapReply *rs )
788 {
789         return over_op_func( op, rs, op_extended );
790 }
791
792 static int
793 over_aux_operational( Operation *op, SlapReply *rs )
794 {
795         return over_op_func( op, rs, op_aux_operational );
796 }
797
798 static int
799 over_aux_chk_referrals( Operation *op, SlapReply *rs )
800 {
801         return over_op_func( op, rs, op_aux_chk_referrals );
802 }
803
804 static int
805 over_aux_chk_controls( Operation *op, SlapReply *rs )
806 {
807         return over_op_func( op, rs, op_aux_chk_controls );
808 }
809
810 enum conn_which {
811         conn_init = 0,
812         conn_destroy,
813         conn_last
814 };
815
816 static int
817 over_connection_func(
818         BackendDB       *bd,
819         Connection      *conn,
820         enum conn_which which
821 )
822 {
823         slap_overinfo           *oi;
824         slap_overinst           *on;
825         BackendDB               db;
826         int                     rc = SLAP_CB_CONTINUE;
827         BI_connection_init      **func;
828
829         /* FIXME: used to happen for instance during abandon
830          * when global overlays are used... */
831         assert( bd != NULL );
832
833         oi = bd->bd_info->bi_private;
834         on = oi->oi_list;
835
836         if ( !SLAP_ISOVERLAY( bd ) ) {
837                 db = *bd;
838                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
839                 bd = &db;
840         }
841
842         for ( ; on; on = on->on_next ) {
843                 func = &on->on_bi.bi_connection_init;
844                 if ( func[ which ] ) {
845                         bd->bd_info = (BackendInfo *)on;
846                         rc = func[ which ]( bd, conn );
847                         if ( rc != SLAP_CB_CONTINUE ) break;
848                 }
849         }
850
851         func = &oi->oi_orig->bi_connection_init;
852         if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
853                 bd->bd_info = oi->oi_orig;
854                 rc = func[ which ]( bd, conn );
855         }
856         /* should not fall thru this far without anything happening... */
857         if ( rc == SLAP_CB_CONTINUE ) {
858                 rc = LDAP_UNWILLING_TO_PERFORM;
859         }
860
861         return rc;
862 }
863
864 static int
865 over_connection_init(
866         BackendDB       *bd,
867         Connection      *conn
868 )
869 {
870         return over_connection_func( bd, conn, conn_init );
871 }
872
873 static int
874 over_connection_destroy(
875         BackendDB       *bd,
876         Connection      *conn
877 )
878 {
879         return over_connection_func( bd, conn, conn_destroy );
880 }
881
882 int
883 overlay_register(
884         slap_overinst *on
885 )
886 {
887         slap_overinst   *tmp;
888
889         /* FIXME: check for duplicates? */
890         for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) {
891                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) {
892                         Debug( LDAP_DEBUG_ANY,
893                                 "overlay_register(\"%s\"): "
894                                 "name already in use.\n",
895                                 on->on_bi.bi_type, 0, 0 );
896                         return -1;
897                 }
898
899                 if ( on->on_bi.bi_obsolete_names != NULL ) {
900                         int     i;
901
902                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
903                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) {
904                                         Debug( LDAP_DEBUG_ANY,
905                                                 "overlay_register(\"%s\"): "
906                                                 "obsolete name \"%s\" already in use "
907                                                 "by overlay \"%s\".\n",
908                                                 on->on_bi.bi_type,
909                                                 on->on_bi.bi_obsolete_names[ i ],
910                                                 tmp->on_bi.bi_type );
911                                         return -1;
912                                 }
913                         }
914                 }
915
916                 if ( tmp->on_bi.bi_obsolete_names != NULL ) {
917                         int     i;
918
919                         for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
920                                 int     j;
921
922                                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
923                                         Debug( LDAP_DEBUG_ANY,
924                                                 "overlay_register(\"%s\"): "
925                                                 "name already in use "
926                                                 "as obsolete by overlay \"%s\".\n",
927                                                 on->on_bi.bi_type,
928                                                 tmp->on_bi.bi_obsolete_names[ i ], 0 );
929                                         return -1;
930                                 }
931
932                                 if ( on->on_bi.bi_obsolete_names != NULL ) {
933                                         for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) {
934                                                 if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
935                                                         Debug( LDAP_DEBUG_ANY,
936                                                                 "overlay_register(\"%s\"): "
937                                                                 "obsolete name \"%s\" already in use "
938                                                                 "as obsolete by overlay \"%s\".\n",
939                                                                 on->on_bi.bi_type,
940                                                                 on->on_bi.bi_obsolete_names[ j ],
941                                                                 tmp->on_bi.bi_type );
942                                                         return -1;
943                                                 }
944                                         }
945                                 }
946                         }
947                 }
948         }
949
950         on->on_next = overlays;
951         overlays = on;
952         return 0;
953 }
954
955 /*
956  * iterator on registered overlays; overlay_next( NULL ) returns the first
957  * overlay; subsequent calls with the previously returned value allow to 
958  * iterate over the entire list; returns NULL when no more overlays are 
959  * registered.
960  */
961
962 slap_overinst *
963 overlay_next(
964         slap_overinst *on
965 )
966 {
967         if ( on == NULL ) {
968                 return overlays;
969         }
970
971         return on->on_next;
972 }
973
974 /*
975  * returns a specific registered overlay based on the type; NULL if not
976  * registered.
977  */
978
979 slap_overinst *
980 overlay_find( const char *over_type )
981 {
982         slap_overinst *on = overlays;
983
984         assert( over_type != NULL );
985
986         for ( ; on; on = on->on_next ) {
987                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
988                         goto foundit;
989                 }
990
991                 if ( on->on_bi.bi_obsolete_names != NULL ) {
992                         int     i;
993
994                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
995                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) {
996                                         Debug( LDAP_DEBUG_ANY,
997                                                 "overlay_find(\"%s\"): "
998                                                 "obsolete name for \"%s\".\n",
999                                                 on->on_bi.bi_obsolete_names[ i ],
1000                                                 on->on_bi.bi_type, 0 );
1001                                         goto foundit;
1002                                 }
1003                         }
1004                 }
1005         }
1006
1007 foundit:;
1008         return on;
1009 }
1010
1011 static const char overtype[] = "over";
1012
1013 /*
1014  * returns TRUE (1) if the database is actually an overlay instance;
1015  * FALSE (0) otherwise.
1016  */
1017
1018 int
1019 overlay_is_over( BackendDB *be )
1020 {
1021         return be->bd_info->bi_type == overtype;
1022 }
1023
1024 /*
1025  * returns TRUE (1) if the given database is actually an overlay
1026  * instance and, somewhere in the list, contains the requested overlay;
1027  * FALSE (0) otherwise.
1028  */
1029
1030 int
1031 overlay_is_inst( BackendDB *be, const char *over_type )
1032 {
1033         slap_overinst   *on;
1034
1035         assert( be != NULL );
1036
1037         if ( !overlay_is_over( be ) ) {
1038                 return 0;
1039         }
1040         
1041         on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
1042         for ( ; on; on = on->on_next ) {
1043                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
1044                         return 1;
1045                 }
1046         }
1047
1048         return 0;
1049 }
1050
1051 int
1052 overlay_register_control( BackendDB *be, const char *oid )
1053 {
1054         int             gotit = 0;
1055         int             cid;
1056
1057         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
1058                 return -1;
1059         }
1060
1061         if ( SLAP_ISGLOBALOVERLAY( be ) ) {
1062                 BackendDB *bd;
1063                 
1064                 /* add to all backends... */
1065                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
1066                         if ( bd == be->bd_self ) {
1067                                 gotit = 1;
1068                         }
1069
1070                         bd->be_ctrls[ cid ] = 1;
1071                         bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1072                 }
1073
1074         }
1075         
1076         if ( !gotit ) {
1077                 be->bd_self->be_ctrls[ cid ] = 1;
1078                 be->bd_self->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1079         }
1080
1081         return 0;
1082 }
1083
1084 void
1085 overlay_destroy_one( BackendDB *be, slap_overinst *on )
1086 {
1087         slap_overinfo *oi = on->on_info;
1088         slap_overinst **oidx;
1089
1090         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1091                 if ( *oidx == on ) {
1092                         *oidx = on->on_next;
1093                         if ( on->on_bi.bi_db_destroy ) {
1094                                 BackendInfo *bi_orig = be->bd_info;
1095                                 be->bd_info = (BackendInfo *)on;
1096                                 on->on_bi.bi_db_destroy( be, NULL );
1097                                 be->bd_info = bi_orig;
1098                         }
1099                         free( on );
1100                         break;
1101                 }
1102         }
1103 }
1104
1105 #ifdef SLAP_CONFIG_DELETE
1106 void
1107 overlay_remove( BackendDB *be, slap_overinst *on )
1108 {
1109         slap_overinfo *oi = on->on_info;
1110         slap_overinst **oidx, *on2;
1111
1112         /* remove overlay from oi_list an call db_close and db_destroy
1113          * handlers */
1114         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1115                 if ( *oidx == on ) {
1116                         *oidx = on->on_next;
1117                         BackendInfo *bi_orig = be->bd_info;
1118                         be->bd_info = (BackendInfo *)on;
1119                         if ( on->on_bi.bi_db_close ) {
1120                                 on->on_bi.bi_db_close( be, NULL );
1121                         }
1122                         if ( on->on_bi.bi_db_destroy ) {
1123                                 on->on_bi.bi_db_destroy( be, NULL );
1124                         }
1125                         be->bd_info = bi_orig;
1126                         free( on );
1127                         break;
1128                 }
1129         }
1130         
1131         /* clean up after removing last overlay */
1132         if ( ! oi->oi_list ) 
1133         {
1134                 /* reset db flags and bd_info to orig */
1135                 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_GLOBAL_OVERLAY;
1136                 be->bd_info = oi->oi_orig;
1137                 ch_free(oi);
1138         }
1139 }
1140 #endif /* SLAP_CONFIG_DELETE */
1141
1142 void
1143 overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev,
1144         int idx )
1145 {
1146         slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1147
1148         if ( idx == -1 ) {
1149                 on2->on_next = oi->oi_list;
1150                 oi->oi_list = on2;
1151         } else {
1152                 int i;
1153                 slap_overinst *on, *otmp1 = NULL, *otmp2;
1154
1155                 /* Since the list is in reverse order and is singly linked,
1156                  * we reverse it to find the idx insertion point. Adding
1157                  * on overlay at a specific point should be a pretty
1158                  * infrequent occurrence.
1159                  */
1160                 for ( on = oi->oi_list; on; on=otmp2 ) {
1161                         otmp2 = on->on_next;
1162                         on->on_next = otmp1;
1163                         otmp1 = on;
1164                 }
1165                 oi->oi_list = NULL;
1166                 /* advance to insertion point */
1167                 for ( i=0, on = otmp1; i<idx; i++ ) {
1168                         otmp1 = on->on_next;
1169                         on->on_next = oi->oi_list;
1170                         oi->oi_list = on;
1171                 }
1172                 /* insert */
1173                 on2->on_next = oi->oi_list;
1174                 oi->oi_list = on2;
1175                 if ( otmp1 ) {
1176                         *prev = &otmp1->on_next;
1177                         /* replace remainder of list */
1178                         for ( on=otmp1; on; on=otmp1 ) {
1179                                 otmp1 = on->on_next;
1180                                 on->on_next = oi->oi_list;
1181                                 oi->oi_list = on;
1182                         }
1183                 }
1184         }
1185 }
1186
1187 void
1188 overlay_move( BackendDB *be, slap_overinst *on, int idx )
1189 {
1190         slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1191         slap_overinst **onp;
1192
1193         for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) {
1194                 if ( *onp == on ) {
1195                         *onp = on->on_next;
1196                         break;
1197                 }
1198         }
1199         overlay_insert( be, on, &onp, idx );
1200 }
1201
1202 /* add an overlay to a particular backend. */
1203 int
1204 overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res, ConfigReply *cr )
1205 {
1206         slap_overinst *on = NULL, *on2 = NULL, **prev;
1207         slap_overinfo *oi = NULL;
1208         BackendInfo *bi = NULL;
1209
1210         if ( res )
1211                 *res = NULL;
1212
1213         on = overlay_find( ov );
1214         if ( !on ) {
1215                 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
1216                 return 1;
1217         }
1218
1219         /* If this is the first overlay on this backend, set up the
1220          * overlay info structure
1221          */
1222         if ( !overlay_is_over( be ) ) {
1223                 int     isglobal = 0;
1224
1225                 /* NOTE: the first time a global overlay is configured,
1226                  * frontendDB gets this flag; it is used later by overlays
1227                  * to determine if they're stacked on top of the frontendDB */
1228                 if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) {
1229                         isglobal = 1;
1230                         if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) {
1231                                 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1232                                         "overlay \"%s\" cannot be global.\n",
1233                                         ov, 0, 0 );
1234                                 return 1;
1235                         }
1236
1237                 } else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) {
1238                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1239                                 "overlay \"%s\" can only be global.\n",
1240                                 ov, 0, 0 );
1241                         return 1;
1242                 }
1243
1244                 oi = ch_malloc( sizeof( slap_overinfo ) );
1245                 oi->oi_orig = be->bd_info;
1246                 oi->oi_bi = *be->bd_info;
1247                 oi->oi_origdb = be;
1248
1249                 if ( isglobal ) {
1250                         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
1251                 }
1252
1253                 /* Save a pointer to ourself in bi_private.
1254                  */
1255                 oi->oi_bi.bi_private = oi;
1256                 oi->oi_list = NULL;
1257                 bi = (BackendInfo *)oi;
1258
1259                 bi->bi_type = (char *)overtype;
1260
1261                 bi->bi_db_config = over_db_config;
1262                 bi->bi_db_open = over_db_open;
1263                 bi->bi_db_close = over_db_close;
1264                 bi->bi_db_destroy = over_db_destroy;
1265
1266                 bi->bi_op_bind = over_op_bind;
1267                 bi->bi_op_unbind = over_op_unbind;
1268                 bi->bi_op_search = over_op_search;
1269                 bi->bi_op_compare = over_op_compare;
1270                 bi->bi_op_modify = over_op_modify;
1271                 bi->bi_op_modrdn = over_op_modrdn;
1272                 bi->bi_op_add = over_op_add;
1273                 bi->bi_op_delete = over_op_delete;
1274                 bi->bi_op_abandon = over_op_abandon;
1275                 bi->bi_op_cancel = over_op_cancel;
1276
1277                 bi->bi_extended = over_op_extended;
1278
1279                 /*
1280                  * this is fine because it has the same
1281                  * args of the operations; we need to rework
1282                  * all the hooks to share the same args
1283                  * of the operations...
1284                  */
1285                 bi->bi_operational = over_aux_operational;
1286                 bi->bi_chk_referrals = over_aux_chk_referrals;
1287                 bi->bi_chk_controls = over_aux_chk_controls;
1288
1289                 /* these have specific arglists */
1290                 bi->bi_entry_get_rw = over_entry_get_rw;
1291                 bi->bi_entry_release_rw = over_entry_release_rw;
1292                 bi->bi_access_allowed = over_access_allowed;
1293                 bi->bi_acl_group = over_acl_group;
1294                 bi->bi_acl_attribute = over_acl_attribute;
1295                 
1296                 bi->bi_connection_init = over_connection_init;
1297                 bi->bi_connection_destroy = over_connection_destroy;
1298
1299                 be->bd_info = bi;
1300
1301         } else {
1302                 if ( overlay_is_inst( be, ov ) ) {
1303                         if ( SLAPO_SINGLE( be ) ) {
1304                                 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1305                                         "overlay \"%s\" already in list\n",
1306                                         ov, 0, 0 );
1307                                 return 1;
1308                         }
1309                 }
1310
1311                 oi = be->bd_info->bi_private;
1312         }
1313
1314         /* Insert new overlay into list. By default overlays are
1315          * added to head of list and executed in LIFO order.
1316          */
1317         on2 = ch_calloc( 1, sizeof(slap_overinst) );
1318         *on2 = *on;
1319         on2->on_info = oi;
1320
1321         prev = &oi->oi_list;
1322         /* Do we need to find the insertion point? */
1323         if ( idx >= 0 ) {
1324                 int i;
1325
1326                 /* count current overlays */
1327                 for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ );
1328
1329                 /* are we just appending a new one? */
1330                 if ( idx >= i )
1331                         idx = -1;
1332         }
1333         overlay_insert( be, on2, &prev, idx );
1334
1335         /* Any initialization needed? */
1336         if ( on2->on_bi.bi_db_init ) {
1337                 int rc;
1338                 be->bd_info = (BackendInfo *)on2;
1339                 rc = on2->on_bi.bi_db_init( be, cr);
1340                 be->bd_info = (BackendInfo *)oi;
1341                 if ( rc ) {
1342                         *prev = on2->on_next;
1343                         ch_free( on2 );
1344                         on2 = NULL;
1345                         return rc;
1346                 }
1347         }
1348
1349         if ( res )
1350                 *res = &on2->on_bi;
1351
1352         return 0;
1353 }
1354