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