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