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