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