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