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