Home | History | Annotate | Line # | Download | only in slapd
      1 /*	$NetBSD: backover.c,v 1.4 2025/09/05 21:16:25 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-2024 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.4 2025/09/05 21:16:25 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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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
    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
    787 over_op_bind( Operation *op, SlapReply *rs )
    788 {
    789 	return over_op_func( op, rs, op_bind );
    790 }
    791 
    792 static int
    793 over_op_unbind( Operation *op, SlapReply *rs )
    794 {
    795 	return over_op_func( op, rs, op_unbind );
    796 }
    797 
    798 static int
    799 over_op_search( Operation *op, SlapReply *rs )
    800 {
    801 	return over_op_func( op, rs, op_search );
    802 }
    803 
    804 static int
    805 over_op_compare( Operation *op, SlapReply *rs )
    806 {
    807 	return over_op_func( op, rs, op_compare );
    808 }
    809 
    810 static int
    811 over_op_modify( Operation *op, SlapReply *rs )
    812 {
    813 	return over_op_func( op, rs, op_modify );
    814 }
    815 
    816 static int
    817 over_op_modrdn( Operation *op, SlapReply *rs )
    818 {
    819 	return over_op_func( op, rs, op_modrdn );
    820 }
    821 
    822 static int
    823 over_op_add( Operation *op, SlapReply *rs )
    824 {
    825 	return over_op_func( op, rs, op_add );
    826 }
    827 
    828 static int
    829 over_op_delete( Operation *op, SlapReply *rs )
    830 {
    831 	return over_op_func( op, rs, op_delete );
    832 }
    833 
    834 static int
    835 over_op_abandon( Operation *op, SlapReply *rs )
    836 {
    837 	return over_op_func( op, rs, op_abandon );
    838 }
    839 
    840 static int
    841 over_op_cancel( Operation *op, SlapReply *rs )
    842 {
    843 	return over_op_func( op, rs, op_cancel );
    844 }
    845 
    846 static int
    847 over_op_extended( Operation *op, SlapReply *rs )
    848 {
    849 	return over_op_func( op, rs, op_extended );
    850 }
    851 
    852 static int
    853 over_aux_operational( Operation *op, SlapReply *rs )
    854 {
    855 	return over_op_func( op, rs, op_aux_operational );
    856 }
    857 
    858 static int
    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
    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
    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
    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
    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
    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 *
   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 *
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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