]> git.sur5r.net Git - openldap/blob - servers/slapd/backover.c
Experimental code for delete support in back-config. Only overlays
[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;
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 /*
601  * default return code in case of missing backend function
602  * and overlay stack returning SLAP_CB_CONTINUE
603  */
604 static int op_rc[ op_last ] = {
605         LDAP_UNWILLING_TO_PERFORM,      /* bind */
606         LDAP_UNWILLING_TO_PERFORM,      /* unbind */
607         LDAP_UNWILLING_TO_PERFORM,      /* search */
608         SLAP_CB_CONTINUE,               /* compare; pass to frontend */
609         LDAP_UNWILLING_TO_PERFORM,      /* modify */
610         LDAP_UNWILLING_TO_PERFORM,      /* modrdn */
611         LDAP_UNWILLING_TO_PERFORM,      /* add */
612         LDAP_UNWILLING_TO_PERFORM,      /* delete */
613         LDAP_UNWILLING_TO_PERFORM,      /* abandon */
614         LDAP_UNWILLING_TO_PERFORM,      /* cancel */
615         LDAP_UNWILLING_TO_PERFORM,      /* extended */
616         LDAP_SUCCESS,                   /* aux_operational */
617         LDAP_SUCCESS,                   /* aux_chk_referrals */
618         SLAP_CB_CONTINUE                /* aux_chk_controls; pass to frontend */
619 };
620
621 int overlay_op_walk(
622         Operation *op,
623         SlapReply *rs,
624         slap_operation_t which,
625         slap_overinfo *oi,
626         slap_overinst *on
627 )
628 {
629         BI_op_bind **func;
630         int rc = SLAP_CB_CONTINUE;
631
632         for (; on; on=on->on_next ) {
633                 func = &on->on_bi.bi_op_bind;
634                 if ( func[which] ) {
635                         op->o_bd->bd_info = (BackendInfo *)on;
636                         rc = func[which]( op, rs );
637                         if ( rc != SLAP_CB_CONTINUE ) break;
638                 }
639         }
640         if ( rc == SLAP_CB_BYPASS )
641                 rc = SLAP_CB_CONTINUE;
642
643         func = &oi->oi_orig->bi_op_bind;
644         if ( func[which] && rc == SLAP_CB_CONTINUE ) {
645                 op->o_bd->bd_info = oi->oi_orig;
646                 rc = func[which]( op, rs );
647         }
648         /* should not fall thru this far without anything happening... */
649         if ( rc == SLAP_CB_CONTINUE ) {
650                 rc = op_rc[ which ];
651         }
652
653         /* The underlying backend didn't handle the request, make sure
654          * overlay cleanup is processed.
655          */
656         if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
657                 slap_callback *sc_next;
658                 for ( ; op->o_callback && op->o_callback->sc_response !=
659                         over_back_response; op->o_callback = sc_next ) {
660                         sc_next = op->o_callback->sc_next;
661                         if ( op->o_callback->sc_cleanup ) {
662                                 op->o_callback->sc_cleanup( op, rs );
663                         }
664                 }
665         }
666         return rc;
667 }
668
669 static int
670 over_op_func(
671         Operation *op,
672         SlapReply *rs,
673         slap_operation_t which
674 )
675 {
676         slap_overinfo *oi;
677         slap_overinst *on;
678         BackendDB *be = op->o_bd, db;
679         slap_callback cb = {NULL, over_back_response, NULL, NULL};
680         int rc = SLAP_CB_CONTINUE;
681
682         /* FIXME: used to happen for instance during abandon
683          * when global overlays are used... */
684         assert( op->o_bd != NULL );
685
686         oi = op->o_bd->bd_info->bi_private;
687         on = oi->oi_list;
688
689         if ( !SLAP_ISOVERLAY( op->o_bd )) {
690                 db = *op->o_bd;
691                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
692                 op->o_bd = &db;
693         }
694         cb.sc_next = op->o_callback;
695         cb.sc_private = oi;
696         op->o_callback = &cb;
697
698         rc = overlay_op_walk( op, rs, which, oi, on );
699
700         op->o_bd = be;
701         op->o_callback = cb.sc_next;
702         return rc;
703 }
704
705 static int
706 over_op_bind( Operation *op, SlapReply *rs )
707 {
708         return over_op_func( op, rs, op_bind );
709 }
710
711 static int
712 over_op_unbind( Operation *op, SlapReply *rs )
713 {
714         return over_op_func( op, rs, op_unbind );
715 }
716
717 static int
718 over_op_search( Operation *op, SlapReply *rs )
719 {
720         return over_op_func( op, rs, op_search );
721 }
722
723 static int
724 over_op_compare( Operation *op, SlapReply *rs )
725 {
726         return over_op_func( op, rs, op_compare );
727 }
728
729 static int
730 over_op_modify( Operation *op, SlapReply *rs )
731 {
732         return over_op_func( op, rs, op_modify );
733 }
734
735 static int
736 over_op_modrdn( Operation *op, SlapReply *rs )
737 {
738         return over_op_func( op, rs, op_modrdn );
739 }
740
741 static int
742 over_op_add( Operation *op, SlapReply *rs )
743 {
744         return over_op_func( op, rs, op_add );
745 }
746
747 static int
748 over_op_delete( Operation *op, SlapReply *rs )
749 {
750         return over_op_func( op, rs, op_delete );
751 }
752
753 static int
754 over_op_abandon( Operation *op, SlapReply *rs )
755 {
756         return over_op_func( op, rs, op_abandon );
757 }
758
759 static int
760 over_op_cancel( Operation *op, SlapReply *rs )
761 {
762         return over_op_func( op, rs, op_cancel );
763 }
764
765 static int
766 over_op_extended( Operation *op, SlapReply *rs )
767 {
768         return over_op_func( op, rs, op_extended );
769 }
770
771 static int
772 over_aux_operational( Operation *op, SlapReply *rs )
773 {
774         return over_op_func( op, rs, op_aux_operational );
775 }
776
777 static int
778 over_aux_chk_referrals( Operation *op, SlapReply *rs )
779 {
780         return over_op_func( op, rs, op_aux_chk_referrals );
781 }
782
783 static int
784 over_aux_chk_controls( Operation *op, SlapReply *rs )
785 {
786         return over_op_func( op, rs, op_aux_chk_controls );
787 }
788
789 enum conn_which {
790         conn_init = 0,
791         conn_destroy,
792         conn_last
793 };
794
795 static int
796 over_connection_func(
797         BackendDB       *bd,
798         Connection      *conn,
799         enum conn_which which
800 )
801 {
802         slap_overinfo           *oi;
803         slap_overinst           *on;
804         BackendDB               db;
805         int                     rc = SLAP_CB_CONTINUE;
806         BI_connection_init      **func;
807
808         /* FIXME: used to happen for instance during abandon
809          * when global overlays are used... */
810         assert( bd != NULL );
811
812         oi = bd->bd_info->bi_private;
813         on = oi->oi_list;
814
815         if ( !SLAP_ISOVERLAY( bd ) ) {
816                 db = *bd;
817                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
818                 bd = &db;
819         }
820
821         for ( ; on; on = on->on_next ) {
822                 func = &on->on_bi.bi_connection_init;
823                 if ( func[ which ] ) {
824                         bd->bd_info = (BackendInfo *)on;
825                         rc = func[ which ]( bd, conn );
826                         if ( rc != SLAP_CB_CONTINUE ) break;
827                 }
828         }
829
830         func = &oi->oi_orig->bi_connection_init;
831         if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
832                 bd->bd_info = oi->oi_orig;
833                 rc = func[ which ]( bd, conn );
834         }
835         /* should not fall thru this far without anything happening... */
836         if ( rc == SLAP_CB_CONTINUE ) {
837                 rc = LDAP_UNWILLING_TO_PERFORM;
838         }
839
840         return rc;
841 }
842
843 static int
844 over_connection_init(
845         BackendDB       *bd,
846         Connection      *conn
847 )
848 {
849         return over_connection_func( bd, conn, conn_init );
850 }
851
852 static int
853 over_connection_destroy(
854         BackendDB       *bd,
855         Connection      *conn
856 )
857 {
858         return over_connection_func( bd, conn, conn_destroy );
859 }
860
861 int
862 overlay_register(
863         slap_overinst *on
864 )
865 {
866         slap_overinst   *tmp;
867
868         /* FIXME: check for duplicates? */
869         for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) {
870                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) {
871                         Debug( LDAP_DEBUG_ANY,
872                                 "overlay_register(\"%s\"): "
873                                 "name already in use.\n",
874                                 on->on_bi.bi_type, 0, 0 );
875                         return -1;
876                 }
877
878                 if ( on->on_bi.bi_obsolete_names != NULL ) {
879                         int     i;
880
881                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
882                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) {
883                                         Debug( LDAP_DEBUG_ANY,
884                                                 "overlay_register(\"%s\"): "
885                                                 "obsolete name \"%s\" already in use "
886                                                 "by overlay \"%s\".\n",
887                                                 on->on_bi.bi_type,
888                                                 on->on_bi.bi_obsolete_names[ i ],
889                                                 tmp->on_bi.bi_type );
890                                         return -1;
891                                 }
892                         }
893                 }
894
895                 if ( tmp->on_bi.bi_obsolete_names != NULL ) {
896                         int     i;
897
898                         for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
899                                 int     j;
900
901                                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
902                                         Debug( LDAP_DEBUG_ANY,
903                                                 "overlay_register(\"%s\"): "
904                                                 "name already in use "
905                                                 "as obsolete by overlay \"%s\".\n",
906                                                 on->on_bi.bi_type,
907                                                 tmp->on_bi.bi_obsolete_names[ i ], 0 );
908                                         return -1;
909                                 }
910
911                                 if ( on->on_bi.bi_obsolete_names != NULL ) {
912                                         for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) {
913                                                 if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
914                                                         Debug( LDAP_DEBUG_ANY,
915                                                                 "overlay_register(\"%s\"): "
916                                                                 "obsolete name \"%s\" already in use "
917                                                                 "as obsolete by overlay \"%s\".\n",
918                                                                 on->on_bi.bi_type,
919                                                                 on->on_bi.bi_obsolete_names[ j ],
920                                                                 tmp->on_bi.bi_type );
921                                                         return -1;
922                                                 }
923                                         }
924                                 }
925                         }
926                 }
927         }
928
929         on->on_next = overlays;
930         overlays = on;
931         return 0;
932 }
933
934 /*
935  * iterator on registered overlays; overlay_next( NULL ) returns the first
936  * overlay; subsequent calls with the previously returned value allow to 
937  * iterate over the entire list; returns NULL when no more overlays are 
938  * registered.
939  */
940
941 slap_overinst *
942 overlay_next(
943         slap_overinst *on
944 )
945 {
946         if ( on == NULL ) {
947                 return overlays;
948         }
949
950         return on->on_next;
951 }
952
953 /*
954  * returns a specific registered overlay based on the type; NULL if not
955  * registered.
956  */
957
958 slap_overinst *
959 overlay_find( const char *over_type )
960 {
961         slap_overinst *on = overlays;
962
963         assert( over_type != NULL );
964
965         for ( ; on; on = on->on_next ) {
966                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
967                         goto foundit;
968                 }
969
970                 if ( on->on_bi.bi_obsolete_names != NULL ) {
971                         int     i;
972
973                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
974                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) {
975                                         Debug( LDAP_DEBUG_ANY,
976                                                 "overlay_find(\"%s\"): "
977                                                 "obsolete name for \"%s\".\n",
978                                                 on->on_bi.bi_obsolete_names[ i ],
979                                                 on->on_bi.bi_type, 0 );
980                                         goto foundit;
981                                 }
982                         }
983                 }
984         }
985
986 foundit:;
987         return on;
988 }
989
990 static const char overtype[] = "over";
991
992 /*
993  * returns TRUE (1) if the database is actually an overlay instance;
994  * FALSE (0) otherwise.
995  */
996
997 int
998 overlay_is_over( BackendDB *be )
999 {
1000         return be->bd_info->bi_type == overtype;
1001 }
1002
1003 /*
1004  * returns TRUE (1) if the given database is actually an overlay
1005  * instance and, somewhere in the list, contains the requested overlay;
1006  * FALSE (0) otherwise.
1007  */
1008
1009 int
1010 overlay_is_inst( BackendDB *be, const char *over_type )
1011 {
1012         slap_overinst   *on;
1013
1014         assert( be != NULL );
1015
1016         if ( !overlay_is_over( be ) ) {
1017                 return 0;
1018         }
1019         
1020         on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
1021         for ( ; on; on = on->on_next ) {
1022                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
1023                         return 1;
1024                 }
1025         }
1026
1027         return 0;
1028 }
1029
1030 int
1031 overlay_register_control( BackendDB *be, const char *oid )
1032 {
1033         int             gotit = 0;
1034         int             cid;
1035
1036         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
1037                 return -1;
1038         }
1039
1040         if ( SLAP_ISGLOBALOVERLAY( be ) ) {
1041                 BackendDB *bd;
1042                 
1043                 /* add to all backends... */
1044                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
1045                         if ( be == bd ) {
1046                                 gotit = 1;
1047                         }
1048
1049                         bd->be_ctrls[ cid ] = 1;
1050                         bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1051                 }
1052
1053         }
1054         
1055         if ( !gotit ) {
1056                 be->be_ctrls[ cid ] = 1;
1057                 be->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1058         }
1059
1060         return 0;
1061 }
1062
1063 void
1064 overlay_destroy_one( BackendDB *be, slap_overinst *on )
1065 {
1066         slap_overinfo *oi = on->on_info;
1067         slap_overinst **oidx;
1068
1069         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1070                 if ( *oidx == on ) {
1071                         *oidx = on->on_next;
1072                         if ( on->on_bi.bi_db_destroy ) {
1073                                 BackendInfo *bi_orig = be->bd_info;
1074                                 be->bd_info = (BackendInfo *)on;
1075                                 on->on_bi.bi_db_destroy( be, NULL );
1076                                 be->bd_info = bi_orig;
1077                         }
1078                         free( on );
1079                         break;
1080                 }
1081         }
1082 }
1083
1084 #ifdef SLAP_CONFIG_DELETE
1085 void
1086 overlay_remove( BackendDB *be, slap_overinst *on )
1087 {
1088         slap_overinfo *oi = on->on_info;
1089         slap_overinst **oidx, *on2;
1090
1091         /* remove overlay from oi_list an call db_close and db_destroy
1092          * handlers */
1093         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1094                 if ( *oidx == on ) {
1095                         *oidx = on->on_next;
1096                         BackendInfo *bi_orig = be->bd_info;
1097                         be->bd_info = (BackendInfo *)on;
1098                         if ( on->on_bi.bi_db_close ) {
1099                                 on->on_bi.bi_db_close( be, NULL );
1100                         }
1101                         if ( on->on_bi.bi_db_destroy ) {
1102                                 on->on_bi.bi_db_destroy( be, NULL );
1103                         }
1104                         be->bd_info = bi_orig;
1105                         free( on );
1106                         break;
1107                 }
1108         }
1109         
1110         /* clean up after removing last overlay */
1111         if ( ! oi->oi_list ) 
1112         {
1113                 /* reset db flags and bd_info to orig */
1114                 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_GLOBAL_OVERLAY;
1115                 be->bd_info = oi->oi_orig;
1116                 ch_free(oi);
1117         }
1118 }
1119 #endif /* SLAP_CONFIG_DELETE */
1120
1121 void
1122 overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev,
1123         int idx )
1124 {
1125         slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1126
1127         if ( idx == -1 ) {
1128                 on2->on_next = oi->oi_list;
1129                 oi->oi_list = on2;
1130         } else {
1131                 int i;
1132                 slap_overinst *on, *otmp1 = NULL, *otmp2;
1133
1134                 /* Since the list is in reverse order and is singly linked,
1135                  * we reverse it to find the idx insertion point. Adding
1136                  * on overlay at a specific point should be a pretty
1137                  * infrequent occurrence.
1138                  */
1139                 for ( on = oi->oi_list; on; on=otmp2 ) {
1140                         otmp2 = on->on_next;
1141                         on->on_next = otmp1;
1142                         otmp1 = on;
1143                 }
1144                 oi->oi_list = NULL;
1145                 /* advance to insertion point */
1146                 for ( i=0, on = otmp1; i<idx; i++ ) {
1147                         otmp1 = on->on_next;
1148                         on->on_next = oi->oi_list;
1149                         oi->oi_list = on;
1150                 }
1151                 /* insert */
1152                 on2->on_next = oi->oi_list;
1153                 oi->oi_list = on2;
1154                 if ( otmp1 ) {
1155                         *prev = &otmp1->on_next;
1156                         /* replace remainder of list */
1157                         for ( on=otmp1; on; on=otmp1 ) {
1158                                 otmp1 = on->on_next;
1159                                 on->on_next = oi->oi_list;
1160                                 oi->oi_list = on;
1161                         }
1162                 }
1163         }
1164 }
1165
1166 void
1167 overlay_move( BackendDB *be, slap_overinst *on, int idx )
1168 {
1169         slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1170         slap_overinst **onp;
1171
1172         for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) {
1173                 if ( *onp == on ) {
1174                         *onp = on->on_next;
1175                         break;
1176                 }
1177         }
1178         overlay_insert( be, on, &onp, idx );
1179 }
1180
1181 /* add an overlay to a particular backend. */
1182 int
1183 overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res, ConfigReply *cr )
1184 {
1185         slap_overinst *on = NULL, *on2 = NULL, **prev;
1186         slap_overinfo *oi = NULL;
1187         BackendInfo *bi = NULL;
1188
1189         if ( res )
1190                 *res = NULL;
1191
1192         on = overlay_find( ov );
1193         if ( !on ) {
1194                 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
1195                 return 1;
1196         }
1197
1198         /* If this is the first overlay on this backend, set up the
1199          * overlay info structure
1200          */
1201         if ( !overlay_is_over( be ) ) {
1202                 int     isglobal = 0;
1203
1204                 /* NOTE: the first time a global overlay is configured,
1205                  * frontendDB gets this flag; it is used later by overlays
1206                  * to determine if they're stacked on top of the frontendDB */
1207                 if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) {
1208                         isglobal = 1;
1209                         if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) {
1210                                 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1211                                         "overlay \"%s\" cannot be global.\n",
1212                                         ov, 0, 0 );
1213                                 return 1;
1214                         }
1215
1216                 } else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) {
1217                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1218                                 "overlay \"%s\" can only be global.\n",
1219                                 ov, 0, 0 );
1220                         return 1;
1221                 }
1222
1223                 oi = ch_malloc( sizeof( slap_overinfo ) );
1224                 oi->oi_orig = be->bd_info;
1225                 oi->oi_bi = *be->bd_info;
1226                 oi->oi_origdb = be;
1227
1228                 if ( isglobal ) {
1229                         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
1230                 }
1231
1232                 /* Save a pointer to ourself in bi_private.
1233                  */
1234                 oi->oi_bi.bi_private = oi;
1235                 oi->oi_list = NULL;
1236                 bi = (BackendInfo *)oi;
1237
1238                 bi->bi_type = (char *)overtype;
1239
1240                 bi->bi_db_config = over_db_config;
1241                 bi->bi_db_open = over_db_open;
1242                 bi->bi_db_close = over_db_close;
1243                 bi->bi_db_destroy = over_db_destroy;
1244
1245                 bi->bi_op_bind = over_op_bind;
1246                 bi->bi_op_unbind = over_op_unbind;
1247                 bi->bi_op_search = over_op_search;
1248                 bi->bi_op_compare = over_op_compare;
1249                 bi->bi_op_modify = over_op_modify;
1250                 bi->bi_op_modrdn = over_op_modrdn;
1251                 bi->bi_op_add = over_op_add;
1252                 bi->bi_op_delete = over_op_delete;
1253                 bi->bi_op_abandon = over_op_abandon;
1254                 bi->bi_op_cancel = over_op_cancel;
1255
1256                 bi->bi_extended = over_op_extended;
1257
1258                 /*
1259                  * this is fine because it has the same
1260                  * args of the operations; we need to rework
1261                  * all the hooks to share the same args
1262                  * of the operations...
1263                  */
1264                 bi->bi_operational = over_aux_operational;
1265                 bi->bi_chk_referrals = over_aux_chk_referrals;
1266                 bi->bi_chk_controls = over_aux_chk_controls;
1267
1268                 /* these have specific arglists */
1269                 bi->bi_entry_get_rw = over_entry_get_rw;
1270                 bi->bi_entry_release_rw = over_entry_release_rw;
1271                 bi->bi_access_allowed = over_access_allowed;
1272                 bi->bi_acl_group = over_acl_group;
1273                 bi->bi_acl_attribute = over_acl_attribute;
1274                 
1275                 bi->bi_connection_init = over_connection_init;
1276                 bi->bi_connection_destroy = over_connection_destroy;
1277
1278                 be->bd_info = bi;
1279
1280         } else {
1281                 if ( overlay_is_inst( be, ov ) ) {
1282                         if ( SLAPO_SINGLE( be ) ) {
1283                                 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1284                                         "overlay \"%s\" already in list\n",
1285                                         ov, 0, 0 );
1286                                 return 1;
1287                         }
1288                 }
1289
1290                 oi = be->bd_info->bi_private;
1291         }
1292
1293         /* Insert new overlay into list. By default overlays are
1294          * added to head of list and executed in LIFO order.
1295          */
1296         on2 = ch_calloc( 1, sizeof(slap_overinst) );
1297         *on2 = *on;
1298         on2->on_info = oi;
1299
1300         prev = &oi->oi_list;
1301         /* Do we need to find the insertion point? */
1302         if ( idx >= 0 ) {
1303                 int i;
1304
1305                 /* count current overlays */
1306                 for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ );
1307
1308                 /* are we just appending a new one? */
1309                 if ( idx >= i )
1310                         idx = -1;
1311         }
1312         overlay_insert( be, on2, &prev, idx );
1313
1314         /* Any initialization needed? */
1315         if ( on2->on_bi.bi_db_init ) {
1316                 int rc;
1317                 be->bd_info = (BackendInfo *)on2;
1318                 rc = on2->on_bi.bi_db_init( be, cr);
1319                 be->bd_info = (BackendInfo *)oi;
1320                 if ( rc ) {
1321                         *prev = on2->on_next;
1322                         ch_free( on2 );
1323                         on2 = NULL;
1324                         return rc;
1325                 }
1326         }
1327
1328         if ( res )
1329                 *res = &on2->on_bi;
1330
1331         return 0;
1332 }
1333