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