]> git.sur5r.net Git - openldap/blob - servers/slapd/backover.c
ITS#4337 implement modrdn for back-config
[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-2006 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 static int
326 over_acl_group(
327         Operation               *op,
328         Entry                   *e,
329         struct berval           *gr_ndn,
330         struct berval           *op_ndn,
331         ObjectClass             *group_oc,
332         AttributeDescription    *group_at )
333 {
334         slap_overinfo *oi;
335         slap_overinst *on;
336         BackendInfo *bi = op->o_bd->bd_info;
337         BackendDB *be = op->o_bd, db;
338         int rc = SLAP_CB_CONTINUE;
339
340         /* FIXME: used to happen for instance during abandon
341          * when global overlays are used... */
342         assert( op->o_bd != NULL );
343
344         oi = op->o_bd->bd_info->bi_private;
345         on = oi->oi_list;
346
347         for ( ; on; on = on->on_next ) {
348                 if ( on->on_bi.bi_acl_group ) {
349                         /* NOTE: do not copy the structure until required */
350                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
351                                 db = *op->o_bd;
352                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
353                                 op->o_bd = &db;
354                         }
355
356                         op->o_bd->bd_info = (BackendInfo *)on;
357                         rc = on->on_bi.bi_acl_group( op, e,
358                                 gr_ndn, op_ndn, group_oc, group_at );
359                         if ( rc != SLAP_CB_CONTINUE ) break;
360                 }
361         }
362
363         if ( rc == SLAP_CB_CONTINUE ) {
364                 BI_acl_group            *bi_acl_group;
365
366                 /* if the database structure was changed, o_bd points to a
367                  * copy of the structure; put the original bd_info in place */
368                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
369                         op->o_bd->bd_info = oi->oi_orig;
370                 }
371
372                 if ( oi->oi_orig->bi_acl_group ) {
373                         bi_acl_group = oi->oi_orig->bi_acl_group;
374                 } else {
375                         bi_acl_group = backend_group;
376                 }
377
378                 rc = bi_acl_group( op, e,
379                         gr_ndn, op_ndn, group_oc, group_at );
380         }
381         /* should not fall thru this far without anything happening... */
382         if ( rc == SLAP_CB_CONTINUE ) {
383                 /* access not allowed */
384                 rc = 0;
385         }
386
387         op->o_bd = be;
388         op->o_bd->bd_info = bi;
389
390         return rc;
391 }
392
393 static int
394 over_acl_attribute(
395         Operation               *op,
396         Entry                   *target,
397         struct berval           *entry_ndn,
398         AttributeDescription    *entry_at,
399         BerVarray               *vals,
400         slap_access_t           access )
401 {
402         slap_overinfo *oi;
403         slap_overinst *on;
404         BackendInfo *bi = op->o_bd->bd_info;
405         BackendDB *be = op->o_bd, db;
406         int rc = SLAP_CB_CONTINUE;
407
408         /* FIXME: used to happen for instance during abandon
409          * when global overlays are used... */
410         assert( op->o_bd != NULL );
411
412         oi = op->o_bd->bd_info->bi_private;
413         on = oi->oi_list;
414
415         for ( ; on; on = on->on_next ) {
416                 if ( on->on_bi.bi_acl_attribute ) {
417                         /* NOTE: do not copy the structure until required */
418                         if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
419                                 db = *op->o_bd;
420                                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
421                                 op->o_bd = &db;
422                         }
423
424                         op->o_bd->bd_info = (BackendInfo *)on;
425                         rc = on->on_bi.bi_acl_attribute( op, target,
426                                 entry_ndn, entry_at, vals, access );
427                         if ( rc != SLAP_CB_CONTINUE ) break;
428                 }
429         }
430
431         if ( rc == SLAP_CB_CONTINUE ) {
432                 BI_acl_attribute                *bi_acl_attribute;
433
434                 /* if the database structure was changed, o_bd points to a
435                  * copy of the structure; put the original bd_info in place */
436                 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
437                         op->o_bd->bd_info = oi->oi_orig;
438                 }
439
440                 if ( oi->oi_orig->bi_acl_attribute ) {
441                         bi_acl_attribute = oi->oi_orig->bi_acl_attribute;
442                 } else {
443                         bi_acl_attribute = backend_attribute;
444                 }
445
446                 rc = bi_acl_attribute( op, target,
447                         entry_ndn, entry_at, vals, access );
448         }
449         /* should not fall thru this far without anything happening... */
450         if ( rc == SLAP_CB_CONTINUE ) {
451                 /* access not allowed */
452                 rc = 0;
453         }
454
455         op->o_bd = be;
456         op->o_bd->bd_info = bi;
457
458         return rc;
459 }
460
461 /*
462  * default return code in case of missing backend function
463  * and overlay stack returning SLAP_CB_CONTINUE
464  */
465 static int op_rc[ op_last ] = {
466         LDAP_UNWILLING_TO_PERFORM,      /* bind */
467         LDAP_UNWILLING_TO_PERFORM,      /* unbind */
468         LDAP_UNWILLING_TO_PERFORM,      /* search */
469         SLAP_CB_CONTINUE,               /* compare; pass to frontend */
470         LDAP_UNWILLING_TO_PERFORM,      /* modify */
471         LDAP_UNWILLING_TO_PERFORM,      /* modrdn */
472         LDAP_UNWILLING_TO_PERFORM,      /* add */
473         LDAP_UNWILLING_TO_PERFORM,      /* delete */
474         LDAP_UNWILLING_TO_PERFORM,      /* abandon */
475         LDAP_UNWILLING_TO_PERFORM,      /* cancel */
476         LDAP_UNWILLING_TO_PERFORM,      /* extended */
477         LDAP_SUCCESS,                   /* aux_operational */
478         LDAP_SUCCESS,                   /* aux_chk_referrals */
479         SLAP_CB_CONTINUE                /* aux_chk_controls; pass to frontend */
480 };
481
482 int overlay_op_walk(
483         Operation *op,
484         SlapReply *rs,
485         slap_operation_t which,
486         slap_overinfo *oi,
487         slap_overinst *on
488 )
489 {
490         BI_op_bind **func;
491         int rc = SLAP_CB_CONTINUE;
492
493         for (; on; on=on->on_next ) {
494                 func = &on->on_bi.bi_op_bind;
495                 if ( func[which] ) {
496                         op->o_bd->bd_info = (BackendInfo *)on;
497                         rc = func[which]( op, rs );
498                         if ( rc != SLAP_CB_CONTINUE ) break;
499                 }
500         }
501         if ( rc == SLAP_CB_BYPASS )
502                 rc = SLAP_CB_CONTINUE;
503
504         func = &oi->oi_orig->bi_op_bind;
505         if ( func[which] && rc == SLAP_CB_CONTINUE ) {
506                 op->o_bd->bd_info = oi->oi_orig;
507                 rc = func[which]( op, rs );
508         }
509         /* should not fall thru this far without anything happening... */
510         if ( rc == SLAP_CB_CONTINUE ) {
511                 rc = op_rc[ which ];
512         }
513
514         /* The underlying backend didn't handle the request, make sure
515          * overlay cleanup is processed.
516          */
517         if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
518                 slap_callback *sc_next;
519                 for ( ; op->o_callback && op->o_callback->sc_response !=
520                         over_back_response; op->o_callback = sc_next ) {
521                         sc_next = op->o_callback->sc_next;
522                         if ( op->o_callback->sc_cleanup ) {
523                                 op->o_callback->sc_cleanup( op, rs );
524                         }
525                 }
526         }
527         return rc;
528 }
529
530 static int
531 over_op_func(
532         Operation *op,
533         SlapReply *rs,
534         slap_operation_t which
535 )
536 {
537         slap_overinfo *oi;
538         slap_overinst *on;
539         BackendDB *be = op->o_bd, db;
540         slap_callback cb = {NULL, over_back_response, NULL, NULL};
541         int rc = SLAP_CB_CONTINUE;
542
543         /* FIXME: used to happen for instance during abandon
544          * when global overlays are used... */
545         assert( op->o_bd != NULL );
546
547         oi = op->o_bd->bd_info->bi_private;
548         on = oi->oi_list;
549
550         if ( !SLAP_ISOVERLAY( op->o_bd )) {
551                 db = *op->o_bd;
552                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
553                 op->o_bd = &db;
554         }
555         cb.sc_next = op->o_callback;
556         cb.sc_private = oi;
557         op->o_callback = &cb;
558
559         rc = overlay_op_walk( op, rs, which, oi, on );
560
561         op->o_bd = be;
562         op->o_callback = cb.sc_next;
563         return rc;
564 }
565
566 static int
567 over_op_bind( Operation *op, SlapReply *rs )
568 {
569         return over_op_func( op, rs, op_bind );
570 }
571
572 static int
573 over_op_unbind( Operation *op, SlapReply *rs )
574 {
575         return over_op_func( op, rs, op_unbind );
576 }
577
578 static int
579 over_op_search( Operation *op, SlapReply *rs )
580 {
581         return over_op_func( op, rs, op_search );
582 }
583
584 static int
585 over_op_compare( Operation *op, SlapReply *rs )
586 {
587         return over_op_func( op, rs, op_compare );
588 }
589
590 static int
591 over_op_modify( Operation *op, SlapReply *rs )
592 {
593         return over_op_func( op, rs, op_modify );
594 }
595
596 static int
597 over_op_modrdn( Operation *op, SlapReply *rs )
598 {
599         return over_op_func( op, rs, op_modrdn );
600 }
601
602 static int
603 over_op_add( Operation *op, SlapReply *rs )
604 {
605         return over_op_func( op, rs, op_add );
606 }
607
608 static int
609 over_op_delete( Operation *op, SlapReply *rs )
610 {
611         return over_op_func( op, rs, op_delete );
612 }
613
614 static int
615 over_op_abandon( Operation *op, SlapReply *rs )
616 {
617         return over_op_func( op, rs, op_abandon );
618 }
619
620 static int
621 over_op_cancel( Operation *op, SlapReply *rs )
622 {
623         return over_op_func( op, rs, op_cancel );
624 }
625
626 static int
627 over_op_extended( Operation *op, SlapReply *rs )
628 {
629         return over_op_func( op, rs, op_extended );
630 }
631
632 static int
633 over_aux_operational( Operation *op, SlapReply *rs )
634 {
635         return over_op_func( op, rs, op_aux_operational );
636 }
637
638 static int
639 over_aux_chk_referrals( Operation *op, SlapReply *rs )
640 {
641         return over_op_func( op, rs, op_aux_chk_referrals );
642 }
643
644 static int
645 over_aux_chk_controls( Operation *op, SlapReply *rs )
646 {
647         return over_op_func( op, rs, op_aux_chk_controls );
648 }
649
650 enum conn_which {
651         conn_init = 0,
652         conn_destroy,
653         conn_last
654 };
655
656 static int
657 over_connection_func(
658         BackendDB       *bd,
659         Connection      *conn,
660         enum conn_which which
661 )
662 {
663         slap_overinfo           *oi;
664         slap_overinst           *on;
665         BackendDB               db;
666         int                     rc = SLAP_CB_CONTINUE;
667         BI_connection_init      **func;
668
669         /* FIXME: used to happen for instance during abandon
670          * when global overlays are used... */
671         assert( bd != NULL );
672
673         oi = bd->bd_info->bi_private;
674         on = oi->oi_list;
675
676         if ( !SLAP_ISOVERLAY( bd ) ) {
677                 db = *bd;
678                 db.be_flags |= SLAP_DBFLAG_OVERLAY;
679                 bd = &db;
680         }
681
682         for ( ; on; on = on->on_next ) {
683                 func = &on->on_bi.bi_connection_init;
684                 if ( func[ which ] ) {
685                         bd->bd_info = (BackendInfo *)on;
686                         rc = func[ which ]( bd, conn );
687                         if ( rc != SLAP_CB_CONTINUE ) break;
688                 }
689         }
690
691         func = &oi->oi_orig->bi_connection_init;
692         if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
693                 bd->bd_info = oi->oi_orig;
694                 rc = func[ which ]( bd, conn );
695         }
696         /* should not fall thru this far without anything happening... */
697         if ( rc == SLAP_CB_CONTINUE ) {
698                 rc = LDAP_UNWILLING_TO_PERFORM;
699         }
700
701         return rc;
702 }
703
704 static int
705 over_connection_init(
706         BackendDB       *bd,
707         Connection      *conn
708 )
709 {
710         return over_connection_func( bd, conn, conn_init );
711 }
712
713 static int
714 over_connection_destroy(
715         BackendDB       *bd,
716         Connection      *conn
717 )
718 {
719         return over_connection_func( bd, conn, conn_destroy );
720 }
721
722 int
723 overlay_register(
724         slap_overinst *on
725 )
726 {
727         slap_overinst   *tmp;
728
729         /* FIXME: check for duplicates? */
730         for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) {
731                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) {
732                         Debug( LDAP_DEBUG_ANY,
733                                 "overlay_register(\"%s\"): "
734                                 "name already in use.\n",
735                                 on->on_bi.bi_type, 0, 0 );
736                         return -1;
737                 }
738
739                 if ( on->on_bi.bi_obsolete_names != NULL ) {
740                         int     i;
741
742                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
743                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) {
744                                         Debug( LDAP_DEBUG_ANY,
745                                                 "overlay_register(\"%s\"): "
746                                                 "obsolete name \"%s\" already in use "
747                                                 "by overlay \"%s\".\n",
748                                                 on->on_bi.bi_type,
749                                                 on->on_bi.bi_obsolete_names[ i ],
750                                                 tmp->on_bi.bi_type );
751                                         return -1;
752                                 }
753                         }
754                 }
755
756                 if ( tmp->on_bi.bi_obsolete_names != NULL ) {
757                         int     i;
758
759                         for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
760                                 int     j;
761
762                                 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
763                                         Debug( LDAP_DEBUG_ANY,
764                                                 "overlay_register(\"%s\"): "
765                                                 "name already in use "
766                                                 "as obsolete by overlay \"%s\".\n",
767                                                 on->on_bi.bi_type,
768                                                 tmp->on_bi.bi_obsolete_names[ i ], 0 );
769                                         return -1;
770                                 }
771
772                                 if ( on->on_bi.bi_obsolete_names != NULL ) {
773                                         for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) {
774                                                 if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
775                                                         Debug( LDAP_DEBUG_ANY,
776                                                                 "overlay_register(\"%s\"): "
777                                                                 "obsolete name \"%s\" already in use "
778                                                                 "as obsolete by overlay \"%s\".\n",
779                                                                 on->on_bi.bi_type,
780                                                                 on->on_bi.bi_obsolete_names[ j ],
781                                                                 tmp->on_bi.bi_type );
782                                                         return -1;
783                                                 }
784                                         }
785                                 }
786                         }
787                 }
788         }
789
790         on->on_next = overlays;
791         overlays = on;
792         return 0;
793 }
794
795 /*
796  * iterator on registered overlays; overlay_next( NULL ) returns the first
797  * overlay; subsequent calls with the previously returned value allow to 
798  * iterate over the entire list; returns NULL when no more overlays are 
799  * registered.
800  */
801
802 slap_overinst *
803 overlay_next(
804         slap_overinst *on
805 )
806 {
807         if ( on == NULL ) {
808                 return overlays;
809         }
810
811         return on->on_next;
812 }
813
814 /*
815  * returns a specific registered overlay based on the type; NULL if not
816  * registered.
817  */
818
819 slap_overinst *
820 overlay_find( const char *over_type )
821 {
822         slap_overinst *on = overlays;
823
824         assert( over_type != NULL );
825
826         for ( ; on; on = on->on_next ) {
827                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
828                         goto foundit;
829                 }
830
831                 if ( on->on_bi.bi_obsolete_names != NULL ) {
832                         int     i;
833
834                         for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
835                                 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) {
836                                         Debug( LDAP_DEBUG_ANY,
837                                                 "overlay_find(\"%s\"): "
838                                                 "obsolete name for \"%s\".\n",
839                                                 on->on_bi.bi_obsolete_names[ i ],
840                                                 on->on_bi.bi_type, 0 );
841                                         goto foundit;
842                                 }
843                         }
844                 }
845         }
846
847 foundit:;
848         return on;
849 }
850
851 static const char overtype[] = "over";
852
853 /*
854  * returns TRUE (1) if the database is actually an overlay instance;
855  * FALSE (0) otherwise.
856  */
857
858 int
859 overlay_is_over( BackendDB *be )
860 {
861         return be->bd_info->bi_type == overtype;
862 }
863
864 /*
865  * returns TRUE (1) if the given database is actually an overlay
866  * instance and, somewhere in the list, contains the requested overlay;
867  * FALSE (0) otherwise.
868  */
869
870 int
871 overlay_is_inst( BackendDB *be, const char *over_type )
872 {
873         slap_overinst   *on;
874
875         assert( be != NULL );
876
877         if ( !overlay_is_over( be ) ) {
878                 return 0;
879         }
880         
881         on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
882         for ( ; on; on = on->on_next ) {
883                 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
884                         return 1;
885                 }
886         }
887
888         return 0;
889 }
890
891 int
892 overlay_register_control( BackendDB *be, const char *oid )
893 {
894         int             gotit = 0;
895         int             cid;
896
897         if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
898                 return -1;
899         }
900
901         if ( SLAP_ISGLOBALOVERLAY( be ) ) {
902                 BackendDB *bd;
903                 
904                 /* add to all backends... */
905                 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
906                         if ( be == bd ) {
907                                 gotit = 1;
908                         }
909
910                         bd->be_ctrls[ cid ] = 1;
911                         bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
912                 }
913
914         }
915         
916         if ( !gotit ) {
917                 be->be_ctrls[ cid ] = 1;
918                 be->be_ctrls[ SLAP_MAX_CIDS ] = 1;
919         }
920
921         return 0;
922 }
923
924 void
925 overlay_destroy_one( BackendDB *be, slap_overinst *on )
926 {
927         slap_overinfo *oi = on->on_info;
928         slap_overinst **oidx;
929
930         for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
931                 if ( *oidx == on ) {
932                         *oidx = on->on_next;
933                         if ( on->on_bi.bi_db_destroy ) {
934                                 BackendInfo *bi_orig = be->bd_info;
935                                 be->bd_info = (BackendInfo *)on;
936                                 on->on_bi.bi_db_destroy( be );
937                                 be->bd_info = bi_orig;
938                         }
939                         free( on );
940                         break;
941                 }
942         }
943 }
944
945 void
946 overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev,
947         int idx )
948 {
949         slap_overinfo *oi = (slap_overinfo *)be->bd_info;
950
951         if ( idx == -1 ) {
952                 on2->on_next = oi->oi_list;
953                 oi->oi_list = on2;
954         } else {
955                 int i;
956                 slap_overinst *on, *otmp1 = NULL, *otmp2;
957
958                 /* Since the list is in reverse order and is singly linked,
959                  * we reverse it to find the idx insertion point. Adding
960                  * on overlay at a specific point should be a pretty
961                  * infrequent occurrence.
962                  */
963                 for ( on = oi->oi_list; on; on=otmp2 ) {
964                         otmp2 = on->on_next;
965                         on->on_next = otmp1;
966                         otmp1 = on;
967                 }
968                 oi->oi_list = NULL;
969                 /* advance to insertion point */
970                 for ( i=0, on = otmp1; i<idx; i++ ) {
971                         otmp1 = on->on_next;
972                         on->on_next = oi->oi_list;
973                         oi->oi_list = on;
974                 }
975                 /* insert */
976                 on2->on_next = oi->oi_list;
977                 oi->oi_list = on2;
978                 if ( otmp1 ) {
979                         *prev = &otmp1->on_next;
980                         /* replace remainder of list */
981                         for ( on=otmp1; on; on=otmp1 ) {
982                                 otmp1 = on->on_next;
983                                 on->on_next = oi->oi_list;
984                                 oi->oi_list = on;
985                         }
986                 }
987         }
988 }
989
990 void
991 overlay_move( BackendDB *be, slap_overinst *on, int idx )
992 {
993         slap_overinfo *oi = (slap_overinfo *)be->bd_info;
994         slap_overinst **onp;
995
996         for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) {
997                 if ( *onp == on ) {
998                         *onp = on->on_next;
999                         break;
1000                 }
1001         }
1002         overlay_insert( be, on, &onp, idx );
1003 }
1004
1005 /* add an overlay to a particular backend. */
1006 int
1007 overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res )
1008 {
1009         slap_overinst *on = NULL, *on2 = NULL, **prev;
1010         slap_overinfo *oi = NULL;
1011         BackendInfo *bi = NULL;
1012
1013         if ( res )
1014                 *res = NULL;
1015
1016         on = overlay_find( ov );
1017         if ( !on ) {
1018                 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
1019                 return 1;
1020         }
1021
1022         /* If this is the first overlay on this backend, set up the
1023          * overlay info structure
1024          */
1025         if ( !overlay_is_over( be ) ) {
1026                 int     isglobal = 0;
1027
1028                 /* NOTE: the first time a global overlay is configured,
1029                  * frontendDB gets this flag; it is used later by overlays
1030                  * to determine if they're stacked on top of the frontendDB */
1031                 if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) {
1032                         isglobal = 1;
1033                         if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) {
1034                                 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1035                                         "overlay \"%s\" cannot be global.\n",
1036                                         ov, 0, 0 );
1037                                 return 1;
1038                         }
1039
1040                 } else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) {
1041                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1042                                 "overlay \"%s\" can only be global.\n",
1043                                 ov, 0, 0 );
1044                         return 1;
1045                 }
1046
1047                 oi = ch_malloc( sizeof( slap_overinfo ) );
1048                 oi->oi_orig = be->bd_info;
1049                 oi->oi_bi = *be->bd_info;
1050                 oi->oi_origdb = be;
1051
1052                 if ( isglobal ) {
1053                         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
1054                 }
1055
1056                 /* Save a pointer to ourself in bi_private.
1057                  */
1058                 oi->oi_bi.bi_private = oi;
1059                 oi->oi_list = NULL;
1060                 bi = (BackendInfo *)oi;
1061
1062                 bi->bi_type = (char *)overtype;
1063
1064                 bi->bi_db_config = over_db_config;
1065                 bi->bi_db_open = over_db_open;
1066                 bi->bi_db_close = over_db_close;
1067                 bi->bi_db_destroy = over_db_destroy;
1068
1069                 bi->bi_op_bind = over_op_bind;
1070                 bi->bi_op_unbind = over_op_unbind;
1071                 bi->bi_op_search = over_op_search;
1072                 bi->bi_op_compare = over_op_compare;
1073                 bi->bi_op_modify = over_op_modify;
1074                 bi->bi_op_modrdn = over_op_modrdn;
1075                 bi->bi_op_add = over_op_add;
1076                 bi->bi_op_delete = over_op_delete;
1077                 bi->bi_op_abandon = over_op_abandon;
1078                 bi->bi_op_cancel = over_op_cancel;
1079
1080                 bi->bi_extended = over_op_extended;
1081
1082                 /*
1083                  * this is fine because it has the same
1084                  * args of the operations; we need to rework
1085                  * all the hooks to share the same args
1086                  * of the operations...
1087                  */
1088                 bi->bi_operational = over_aux_operational;
1089                 bi->bi_chk_referrals = over_aux_chk_referrals;
1090                 bi->bi_chk_controls = over_aux_chk_controls;
1091
1092                 /* these have specific arglists */
1093                 bi->bi_access_allowed = over_access_allowed;
1094                 bi->bi_acl_group = over_acl_group;
1095                 bi->bi_acl_attribute = over_acl_attribute;
1096                 
1097                 bi->bi_connection_init = over_connection_init;
1098                 bi->bi_connection_destroy = over_connection_destroy;
1099
1100                 be->bd_info = bi;
1101
1102         } else {
1103                 if ( overlay_is_inst( be, ov ) ) {
1104                         Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1105                                 "overlay \"%s\" already in list\n",
1106                                 ov, 0, 0 );
1107                         if ( SLAPO_SINGLE( be ) ) {
1108                                 return 1;
1109                         }
1110                 }
1111
1112                 oi = be->bd_info->bi_private;
1113         }
1114
1115         /* Insert new overlay into list. By default overlays are
1116          * added to head of list and executed in LIFO order.
1117          */
1118         on2 = ch_calloc( 1, sizeof(slap_overinst) );
1119         *on2 = *on;
1120         on2->on_info = oi;
1121
1122         prev = &oi->oi_list;
1123         /* Do we need to find the insertion point? */
1124         if ( idx >= 0 ) {
1125                 int i;
1126
1127                 /* count current overlays */
1128                 for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ );
1129
1130                 /* are we just appending a new one? */
1131                 if ( idx >= i )
1132                         idx = -1;
1133         }
1134         overlay_insert( be, on2, &prev, idx );
1135
1136         /* Any initialization needed? */
1137         if ( on2->on_bi.bi_db_init ) {
1138                 int rc;
1139                 be->bd_info = (BackendInfo *)on2;
1140                 rc = on2->on_bi.bi_db_init( be );
1141                 be->bd_info = (BackendInfo *)oi;
1142                 if ( rc ) {
1143                         *prev = on2->on_next;
1144                         ch_free( on2 );
1145                         on2 = NULL;
1146                         return rc;
1147                 }
1148         }
1149
1150         if ( res )
1151                 *res = &on2->on_bi;
1152
1153         return 0;
1154 }
1155