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