Home | History | Annotate | Line # | Download | only in slapd
      1 /*	$NetBSD: backglue.c,v 1.4 2025/09/05 21:16:25 christos Exp $	*/
      2 
      3 /* backglue.c - backend glue */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 2001-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 /*
     20  * Functions to glue a bunch of other backends into a single tree.
     21  * All of the glued backends must share a common suffix. E.g., you
     22  * can glue o=foo and ou=bar,o=foo but you can't glue o=foo and o=bar.
     23  *
     24  * The purpose of these functions is to allow you to split a single database
     25  * into pieces (for load balancing purposes, whatever) but still be able
     26  * to treat it as a single database after it's been split. As such, each
     27  * of the glued backends should have identical rootdn.
     28  *  -- Howard Chu
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 __RCSID("$NetBSD: backglue.c,v 1.4 2025/09/05 21:16:25 christos Exp $");
     33 
     34 #include "portable.h"
     35 
     36 #include <stdio.h>
     37 
     38 #include <ac/string.h>
     39 #include <ac/socket.h>
     40 
     41 #define SLAPD_TOOLS
     42 #include "slap.h"
     43 #include "lutil.h"
     44 #include "slap-config.h"
     45 
     46 typedef struct gluenode {
     47 	BackendDB *gn_be;
     48 	struct berval gn_pdn;
     49 } gluenode;
     50 
     51 typedef struct glueinfo {
     52 	int gi_nodes;
     53 	struct berval gi_pdn;
     54 	gluenode gi_n[1];
     55 } glueinfo;
     56 
     57 static slap_overinst	glue;
     58 
     59 static int glueMode;
     60 static BackendDB *glueBack;
     61 static BackendDB glueBackDone;
     62 #define GLUEBACK_DONE (&glueBackDone)
     63 
     64 static slap_overinst * glue_tool_inst( BackendInfo *bi);
     65 
     66 static slap_response glue_op_response;
     67 
     68 /* Just like select_backend, but only for our backends */
     69 static BackendDB *
     70 glue_back_select (
     71 	BackendDB *be,
     72 	struct berval *dn
     73 )
     74 {
     75 	slap_overinst	*on = (slap_overinst *)be->bd_info;
     76 	glueinfo		*gi = (glueinfo *)on->on_bi.bi_private;
     77 	int i;
     78 
     79 	for (i = gi->gi_nodes-1; i >= 0; i--) {
     80 		assert( gi->gi_n[i].gn_be->be_nsuffix != NULL );
     81 
     82 		if (dnIsSuffix(dn, &gi->gi_n[i].gn_be->be_nsuffix[0])) {
     83 			return gi->gi_n[i].gn_be;
     84 		}
     85 	}
     86 	be->bd_info = on->on_info->oi_orig;
     87 	return be;
     88 }
     89 
     90 
     91 typedef struct glue_state {
     92 	char *matched;
     93 	BerVarray refs;
     94 	LDAPControl **ctrls;
     95 	int err;
     96 	int matchlen;
     97 	int nrefs;
     98 	int nctrls;
     99 } glue_state;
    100 
    101 typedef struct glue_entry {
    102 	BackendDB *ge_be;
    103 	BackendInfo *ge_bi;
    104 	void *ge_orig;
    105 } glue_entry;
    106 
    107 static int
    108 glue_op_cleanup( Operation *op, SlapReply *rs )
    109 {
    110 	/* This is not a final result */
    111 	if (rs->sr_type == REP_RESULT )
    112 		rs->sr_type = REP_GLUE_RESULT;
    113 	return SLAP_CB_CONTINUE;
    114 }
    115 
    116 static int
    117 glue_op_response ( Operation *op, SlapReply *rs )
    118 {
    119 	glue_state *gs = op->o_callback->sc_private;
    120 
    121 	switch(rs->sr_type) {
    122 	case REP_SEARCH:
    123 	case REP_SEARCHREF:
    124 	case REP_INTERMEDIATE:
    125 		return SLAP_CB_CONTINUE;
    126 
    127 	default:
    128 		if (rs->sr_err == LDAP_SUCCESS ||
    129 			rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ||
    130 			rs->sr_err == LDAP_TIMELIMIT_EXCEEDED ||
    131 			rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED ||
    132 			rs->sr_err == LDAP_NO_SUCH_OBJECT ||
    133 			gs->err != LDAP_SUCCESS)
    134 			gs->err = rs->sr_err;
    135 		if (gs->err == LDAP_SUCCESS && gs->matched) {
    136 			ch_free (gs->matched);
    137 			gs->matched = NULL;
    138 			gs->matchlen = 0;
    139 		}
    140 		if (gs->err != LDAP_SUCCESS && rs->sr_matched) {
    141 			int len;
    142 			len = strlen (rs->sr_matched);
    143 			if (len > gs->matchlen) {
    144 				if (gs->matched)
    145 					ch_free (gs->matched);
    146 				gs->matched = ch_strdup (rs->sr_matched);
    147 				gs->matchlen = len;
    148 			}
    149 		}
    150 		if (rs->sr_ref) {
    151 			int i, j, k;
    152 			BerVarray new;
    153 
    154 			for (i=0; rs->sr_ref[i].bv_val; i++);
    155 
    156 			j = gs->nrefs;
    157 			if (!j) {
    158 				new = ch_malloc ((i+1)*sizeof(struct berval));
    159 			} else {
    160 				new = ch_realloc(gs->refs,
    161 					(j+i+1)*sizeof(struct berval));
    162 			}
    163 			for (k=0; k<i; j++,k++) {
    164 				ber_dupbv( &new[j], &rs->sr_ref[k] );
    165 			}
    166 			new[j].bv_val = NULL;
    167 			gs->nrefs = j;
    168 			gs->refs = new;
    169 		}
    170 		if (rs->sr_ctrls) {
    171 			int i, j, k;
    172 			LDAPControl **newctrls;
    173 
    174 			for (i=0; rs->sr_ctrls[i]; i++);
    175 
    176 			j = gs->nctrls;
    177 			if (!j) {
    178 				newctrls = op->o_tmpalloc((i+1)*sizeof(LDAPControl *),
    179 					op->o_tmpmemctx);
    180 			} else {
    181 				/* Forget old pagedResults response if we're sending
    182 				 * a new one now
    183 				 */
    184 				if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
    185 					int newpage = 0;
    186 					for ( k=0; k<i; k++ ) {
    187 						if ( !strcmp(rs->sr_ctrls[k]->ldctl_oid,
    188 							LDAP_CONTROL_PAGEDRESULTS )) {
    189 							newpage = 1;
    190 							break;
    191 						}
    192 					}
    193 					if ( newpage ) {
    194 						for ( k=0; k<j; k++ ) {
    195 							if ( !strcmp(gs->ctrls[k]->ldctl_oid,
    196 								LDAP_CONTROL_PAGEDRESULTS ))
    197 							{
    198 								op->o_tmpfree(gs->ctrls[k], op->o_tmpmemctx);
    199 								gs->ctrls[k] = gs->ctrls[--j];
    200 								gs->ctrls[j] = NULL;
    201 								break;
    202 							}
    203 						}
    204 					}
    205 				}
    206 				newctrls = op->o_tmprealloc(gs->ctrls,
    207 					(j+i+1)*sizeof(LDAPControl *), op->o_tmpmemctx);
    208 			}
    209 			for (k=0; k<i; j++,k++) {
    210 				ber_len_t oidlen = strlen( rs->sr_ctrls[k]->ldctl_oid );
    211 				newctrls[j] = op->o_tmpalloc(sizeof(LDAPControl) + oidlen + 1 + rs->sr_ctrls[k]->ldctl_value.bv_len + 1,
    212 					op->o_tmpmemctx);
    213 				newctrls[j]->ldctl_iscritical = rs->sr_ctrls[k]->ldctl_iscritical;
    214 				newctrls[j]->ldctl_oid = (char *)&newctrls[j][1];
    215 				lutil_strcopy( newctrls[j]->ldctl_oid, rs->sr_ctrls[k]->ldctl_oid );
    216 				if ( !BER_BVISNULL( &rs->sr_ctrls[k]->ldctl_value ) ) {
    217 					newctrls[j]->ldctl_value.bv_val = &newctrls[j]->ldctl_oid[oidlen + 1];
    218 					newctrls[j]->ldctl_value.bv_len = rs->sr_ctrls[k]->ldctl_value.bv_len;
    219 					lutil_memcopy( newctrls[j]->ldctl_value.bv_val,
    220 						rs->sr_ctrls[k]->ldctl_value.bv_val,
    221 						rs->sr_ctrls[k]->ldctl_value.bv_len + 1 );
    222 				} else {
    223 					BER_BVZERO( &newctrls[j]->ldctl_value );
    224 				}
    225 			}
    226 			newctrls[j] = NULL;
    227 			gs->nctrls = j;
    228 			gs->ctrls = newctrls;
    229 		}
    230 	}
    231 	return 0;
    232 }
    233 
    234 static int
    235 glue_op_func ( Operation *op, SlapReply *rs )
    236 {
    237 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
    238 	BackendDB *b0 = op->o_bd;
    239 	BackendInfo *bi0 = op->o_bd->bd_info, *bi1;
    240 	slap_operation_t which = op_bind;
    241 	int rc;
    242 
    243 	op->o_bd = glue_back_select (b0, &op->o_req_ndn);
    244 
    245 	/* If we're on the primary backend, let overlay framework handle it */
    246 	if ( op->o_bd == b0 )
    247 		return SLAP_CB_CONTINUE;
    248 
    249 	b0->bd_info = on->on_info->oi_orig;
    250 
    251 	switch(op->o_tag) {
    252 	case LDAP_REQ_ADD: which = op_add; break;
    253 	case LDAP_REQ_DELETE: which = op_delete; break;
    254 	case LDAP_REQ_MODIFY: which = op_modify; break;
    255 	case LDAP_REQ_MODRDN: which = op_modrdn; break;
    256 	case LDAP_REQ_EXTENDED: which = op_extended; break;
    257 	default: assert( 0 ); break;
    258 	}
    259 
    260 	bi1 = op->o_bd->bd_info;
    261 	rc = (&bi1->bi_op_bind)[ which ] ?
    262 		(&bi1->bi_op_bind)[ which ]( op, rs ) : SLAP_CB_BYPASS;
    263 
    264 	op->o_bd = b0;
    265 	op->o_bd->bd_info = bi0;
    266 	return rc;
    267 }
    268 
    269 static int
    270 glue_op_abandon( Operation *op, SlapReply *rs )
    271 {
    272 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
    273 	glueinfo		*gi = (glueinfo *)on->on_bi.bi_private;
    274 	BackendDB *b0 = op->o_bd;
    275 	BackendInfo *bi0 = op->o_bd->bd_info;
    276 	int i;
    277 
    278 	b0->bd_info = on->on_info->oi_orig;
    279 
    280 	for (i = gi->gi_nodes-1; i >= 0; i--) {
    281 		assert( gi->gi_n[i].gn_be->be_nsuffix != NULL );
    282 		op->o_bd = gi->gi_n[i].gn_be;
    283 		if ( op->o_bd == b0 )
    284 			continue;
    285 		if ( op->o_bd->bd_info->bi_op_abandon )
    286 			op->o_bd->bd_info->bi_op_abandon( op, rs );
    287 	}
    288 	op->o_bd = b0;
    289 	op->o_bd->bd_info = bi0;
    290 	return SLAP_CB_CONTINUE;
    291 }
    292 
    293 static int
    294 glue_response ( Operation *op, SlapReply *rs )
    295 {
    296 	BackendDB *be = op->o_bd;
    297 	be = glue_back_select (op->o_bd, &op->o_req_ndn);
    298 
    299 	/* If we're on the primary backend, let overlay framework handle it.
    300 	 * Otherwise, bail out.
    301 	 */
    302 	return ( op->o_bd == be ) ? SLAP_CB_CONTINUE : SLAP_CB_BYPASS;
    303 }
    304 
    305 static int
    306 glue_chk_referrals ( Operation *op, SlapReply *rs )
    307 {
    308 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
    309 	BackendDB *b0 = op->o_bd;
    310 	BackendInfo *bi0 = op->o_bd->bd_info;
    311 	int rc;
    312 
    313 	op->o_bd = glue_back_select (b0, &op->o_req_ndn);
    314 	if ( op->o_bd == b0 )
    315 		return SLAP_CB_CONTINUE;
    316 
    317 	b0->bd_info = on->on_info->oi_orig;
    318 
    319 	if ( op->o_bd->bd_info->bi_chk_referrals )
    320 		rc = ( *op->o_bd->bd_info->bi_chk_referrals )( op, rs );
    321 	else
    322 		rc = SLAP_CB_CONTINUE;
    323 
    324 	op->o_bd = b0;
    325 	op->o_bd->bd_info = bi0;
    326 	return rc;
    327 }
    328 
    329 static int
    330 glue_chk_controls ( Operation *op, SlapReply *rs )
    331 {
    332 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
    333 	BackendDB *b0 = op->o_bd;
    334 	BackendInfo *bi0 = op->o_bd->bd_info;
    335 	int rc = SLAP_CB_CONTINUE;
    336 
    337 	op->o_bd = glue_back_select (b0, &op->o_req_ndn);
    338 	if ( op->o_bd == b0 )
    339 		return SLAP_CB_CONTINUE;
    340 
    341 	b0->bd_info = on->on_info->oi_orig;
    342 
    343 	/* if the subordinate database has overlays, the bi_chk_controls()
    344 	 * hook is actually over_aux_chk_controls(); in case it actually
    345 	 * wraps a missing hok, we need to mimic the behavior
    346 	 * of the frontend applied to that database */
    347 	if ( op->o_bd->bd_info->bi_chk_controls ) {
    348 		rc = ( *op->o_bd->bd_info->bi_chk_controls )( op, rs );
    349 	}
    350 
    351 
    352 	if ( rc == SLAP_CB_CONTINUE ) {
    353 		rc = backend_check_controls( op, rs );
    354 	}
    355 
    356 	op->o_bd = b0;
    357 	op->o_bd->bd_info = bi0;
    358 	return rc;
    359 }
    360 
    361 /* ITS#4615 - overlays configured above the glue overlay should be
    362  * invoked for the entire glued tree. Overlays configured below the
    363  * glue overlay should only be invoked on the primary backend.
    364  * So, if we're searching on any subordinates, we need to force the
    365  * current overlay chain to stop processing, without stopping the
    366  * overall callback flow.
    367  */
    368 static int
    369 glue_sub_search( Operation *op, SlapReply *rs, BackendDB *b0,
    370 	slap_overinst *on )
    371 {
    372 	/* Process any overlays on the primary backend */
    373 	if ( op->o_bd == b0 && on->on_next ) {
    374 		BackendInfo *bi = op->o_bd->bd_info;
    375 		int rc = SLAP_CB_CONTINUE;
    376 		for ( on=on->on_next; on; on=on->on_next ) {
    377 			if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
    378 				continue;
    379 			op->o_bd->bd_info = (BackendInfo *)on;
    380 			if ( on->on_bi.bi_op_search ) {
    381 				rc = on->on_bi.bi_op_search( op, rs );
    382 				if ( rc != SLAP_CB_CONTINUE )
    383 					break;
    384 			}
    385 		}
    386 		op->o_bd->bd_info = bi;
    387 		if ( rc != SLAP_CB_CONTINUE )
    388 			return rc;
    389 	}
    390 	return op->o_bd->be_search( op, rs );
    391 }
    392 
    393 static const ID glueID = NOID;
    394 static const struct berval gluecookie = { sizeof( glueID ), (char *)&glueID };
    395 
    396 static int
    397 glue_op_search ( Operation *op, SlapReply *rs )
    398 {
    399 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
    400 	glueinfo		*gi = (glueinfo *)on->on_bi.bi_private;
    401 	BackendDB *b0 = op->o_bd;
    402 	BackendDB *b1 = NULL, *btmp;
    403 	BackendInfo *bi0 = op->o_bd->bd_info;
    404 	int i;
    405 	long stoptime = 0, starttime;
    406 	glue_state gs = {NULL, NULL, NULL, 0, 0, 0, 0};
    407 	slap_callback cb = { NULL, glue_op_response, glue_op_cleanup, NULL };
    408 	int scope0, tlimit0;
    409 	struct berval dn, ndn, *pdn;
    410 
    411 	cb.sc_private = &gs;
    412 
    413 	cb.sc_next = op->o_callback;
    414 
    415 	starttime = op->o_time;
    416 	stoptime = slap_get_time () + op->ors_tlimit;
    417 
    418 	/* reset dummy cookie used to keep paged results going across databases */
    419 	if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED
    420 		&& bvmatch( &((PagedResultsState *)op->o_pagedresults_state)->ps_cookieval, &gluecookie ) )
    421 	{
    422 		PagedResultsState *ps = op->o_pagedresults_state;
    423 		BerElementBuffer berbuf;
    424 		BerElement *ber = (BerElement *)&berbuf;
    425 		struct berval cookie = BER_BVC(""), value;
    426 		int c;
    427 
    428 		for (c = 0; op->o_ctrls[c] != NULL; c++) {
    429 			if (strcmp(op->o_ctrls[c]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS) == 0)
    430 				break;
    431 		}
    432 
    433 		assert( op->o_ctrls[c] != NULL );
    434 
    435 		ber_init2( ber, NULL, LBER_USE_DER );
    436 		ber_printf( ber, "{iO}", ps->ps_size, &cookie );
    437 		ber_flatten2( ber, &value, 0 );
    438 		assert( op->o_ctrls[c]->ldctl_value.bv_len >= value.bv_len );
    439 		op->o_ctrls[c]->ldctl_value.bv_len = value.bv_len;
    440 		lutil_memcopy( op->o_ctrls[c]->ldctl_value.bv_val,
    441 			value.bv_val, value.bv_len );
    442 		ber_free_buf( ber );
    443 
    444 		ps->ps_cookie = (PagedResultsCookie)0;
    445 		BER_BVZERO( &ps->ps_cookieval );
    446 	}
    447 
    448 	op->o_bd = glue_back_select (b0, &op->o_req_ndn);
    449 	b0->bd_info = on->on_info->oi_orig;
    450 
    451 	switch (op->ors_scope) {
    452 	case LDAP_SCOPE_BASE:
    453 		if ( op->o_bd == b0 )
    454 			return SLAP_CB_CONTINUE;
    455 
    456 		if (op->o_bd && op->o_bd->be_search) {
    457 			rs->sr_err = op->o_bd->be_search( op, rs );
    458 		} else {
    459 			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
    460 		}
    461 		return rs->sr_err;
    462 
    463 	case LDAP_SCOPE_ONELEVEL:
    464 	case LDAP_SCOPE_SUBTREE:
    465 	case LDAP_SCOPE_SUBORDINATE: /* FIXME */
    466 		op->o_callback = &cb;
    467 		rs->sr_err = gs.err = LDAP_UNWILLING_TO_PERFORM;
    468 		scope0 = op->ors_scope;
    469 		tlimit0 = op->ors_tlimit;
    470 		dn = op->o_req_dn;
    471 		ndn = op->o_req_ndn;
    472 		b1 = op->o_bd;
    473 
    474 		/*
    475 		 * Execute in reverse order, most specific first
    476 		 */
    477 		for (i = gi->gi_nodes; i >= 0; i--) {
    478 			if ( i == gi->gi_nodes ) {
    479 				btmp = b0;
    480 				pdn = &gi->gi_pdn;
    481 			} else {
    482 				btmp = gi->gi_n[i].gn_be;
    483 				pdn = &gi->gi_n[i].gn_pdn;
    484 			}
    485 			if (!btmp || !btmp->be_search)
    486 				continue;
    487 			if (!dnIsSuffix(&btmp->be_nsuffix[0], &b1->be_nsuffix[0]))
    488 				continue;
    489 			if (get_no_subordinate_glue(op) && btmp != b1)
    490 				continue;
    491 			/* If we remembered which backend we were on before,
    492 			 * skip down to it now
    493 			 */
    494 			if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED &&
    495 				op->o_conn->c_pagedresults_state.ps_be &&
    496 				op->o_conn->c_pagedresults_state.ps_be != btmp )
    497 				continue;
    498 
    499 			if (tlimit0 != SLAP_NO_LIMIT) {
    500 				op->o_time = slap_get_time();
    501 				op->ors_tlimit = stoptime - op->o_time;
    502 				if (op->ors_tlimit <= 0) {
    503 					rs->sr_err = gs.err = LDAP_TIMELIMIT_EXCEEDED;
    504 					break;
    505 				}
    506 			}
    507 			rs->sr_err = 0;
    508 			/*
    509 			 * check for abandon
    510 			 */
    511 			if (op->o_abandon) {
    512 				goto end_of_loop;
    513 			}
    514 			op->o_bd = btmp;
    515 
    516 			assert( op->o_bd->be_suffix != NULL );
    517 			assert( op->o_bd->be_nsuffix != NULL );
    518 
    519 			if (scope0 == LDAP_SCOPE_ONELEVEL &&
    520 				dn_match(pdn, &ndn))
    521 			{
    522 				struct berval mdn, mndn;
    523 				op->ors_scope = LDAP_SCOPE_BASE;
    524 				mdn = op->o_req_dn = op->o_bd->be_suffix[0];
    525 				mndn = op->o_req_ndn = op->o_bd->be_nsuffix[0];
    526 				rs->sr_err = op->o_bd->be_search(op, rs);
    527 				if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
    528 					gs.err = LDAP_SUCCESS;
    529 				}
    530 				op->ors_scope = LDAP_SCOPE_ONELEVEL;
    531 				if ( op->o_req_dn.bv_val == mdn.bv_val )
    532 					op->o_req_dn = dn;
    533 				if ( op->o_req_ndn.bv_val == mndn.bv_val )
    534 					op->o_req_ndn = ndn;
    535 
    536 			} else if (scope0 == LDAP_SCOPE_SUBTREE &&
    537 				dn_match(&op->o_bd->be_nsuffix[0], &ndn))
    538 			{
    539 				rs->sr_err = glue_sub_search( op, rs, b0, on );
    540 
    541 			} else if (scope0 == LDAP_SCOPE_SUBTREE &&
    542 				dnIsSuffix(&op->o_bd->be_nsuffix[0], &ndn))
    543 			{
    544 				struct berval mdn, mndn;
    545 				mdn = op->o_req_dn = op->o_bd->be_suffix[0];
    546 				mndn = op->o_req_ndn = op->o_bd->be_nsuffix[0];
    547 				rs->sr_err = glue_sub_search( op, rs, b0, on );
    548 				if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
    549 					gs.err = LDAP_SUCCESS;
    550 				}
    551 				if ( op->o_req_dn.bv_val == mdn.bv_val )
    552 					op->o_req_dn = dn;
    553 				if ( op->o_req_ndn.bv_val == mndn.bv_val )
    554 					op->o_req_ndn = ndn;
    555 
    556 			} else if (dnIsSuffix(&ndn, &op->o_bd->be_nsuffix[0])) {
    557 				rs->sr_err = glue_sub_search( op, rs, b0, on );
    558 			}
    559 
    560 			if ( rs->sr_err == SLAPD_NO_REPLY ) {
    561 				gs.err = rs->sr_err;
    562 				break;
    563 			}
    564 
    565 			switch ( gs.err ) {
    566 
    567 			/*
    568 			 * Add errors that should result in dropping
    569 			 * the search
    570 			 */
    571 			case LDAP_SIZELIMIT_EXCEEDED:
    572 			case LDAP_TIMELIMIT_EXCEEDED:
    573 			case LDAP_ADMINLIMIT_EXCEEDED:
    574 			case LDAP_NO_SUCH_OBJECT:
    575 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
    576 			case LDAP_X_CANNOT_CHAIN:
    577 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
    578 				goto end_of_loop;
    579 
    580 			case LDAP_SUCCESS:
    581 				if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
    582 					PagedResultsState *ps = op->o_pagedresults_state;
    583 
    584 					/* Assume this backend can be forgotten now */
    585 					op->o_conn->c_pagedresults_state.ps_be = NULL;
    586 
    587 					/* If we have a full page, exit the loop. We may
    588 					 * need to remember this backend so we can continue
    589 					 * from here on a subsequent request.
    590 					 */
    591 					if ( rs->sr_nentries >= ps->ps_size ) {
    592 						PagedResultsState *cps = &op->o_conn->c_pagedresults_state;
    593 
    594 						/* Don't bother to remember the first backend.
    595 						 * Only remember the last one if there's more state left.
    596 						 */
    597 						if ( op->o_bd != b0 &&
    598 							( cps->ps_cookie != NOID
    599 								|| !BER_BVISNULL( &cps->ps_cookieval )
    600 								|| op->o_bd != gi->gi_n[0].gn_be ) )
    601 						{
    602 							op->o_conn->c_pagedresults_state.ps_be = op->o_bd;
    603 						}
    604 
    605 						/* Check whether the cookie is empty,
    606 						 * and give remaining databases a chance
    607 						 */
    608 						if ( op->o_bd != gi->gi_n[0].gn_be || cps->ps_cookie == NOID ) {
    609 							int		c;
    610 
    611 							for ( c = 0; gs.ctrls[c] != NULL; c++ ) {
    612 								if ( strcmp( gs.ctrls[c]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 ) {
    613 									break;
    614 								}
    615 							}
    616 
    617 							if ( gs.ctrls[c] != NULL ) {
    618 								BerElementBuffer berbuf;
    619 								BerElement	*ber = (BerElement *)&berbuf;
    620 								ber_tag_t	tag;
    621 								ber_int_t	size;
    622 								struct berval	cookie, value;
    623 
    624 								ber_init2( ber, &gs.ctrls[c]->ldctl_value, LBER_USE_DER );
    625 
    626 								tag = ber_scanf( ber, "{im}", &size, &cookie );
    627 								assert( tag != LBER_ERROR );
    628 
    629 								if ( BER_BVISEMPTY( &cookie ) && op->o_bd != gi->gi_n[0].gn_be ) {
    630 									/* delete old, create new cookie with NOID */
    631 									PagedResultsCookie respcookie = (PagedResultsCookie)NOID;
    632 									ber_len_t oidlen = strlen( gs.ctrls[c]->ldctl_oid );
    633 									LDAPControl *newctrl;
    634 
    635 									/* it's next database's turn */
    636 									if ( btmp == b0 ) {
    637 										op->o_conn->c_pagedresults_state.ps_be = gi->gi_n[gi->gi_nodes - 1].gn_be;
    638 
    639 									} else {
    640 										op->o_conn->c_pagedresults_state.ps_be = gi->gi_n[(i > 0 ? i - 1: 0)].gn_be;
    641 									}
    642 
    643 									cookie.bv_val = (char *)&respcookie;
    644 									cookie.bv_len = sizeof( PagedResultsCookie );
    645 
    646 									ber_init2( ber, NULL, LBER_USE_DER );
    647 									ber_printf( ber, "{iO}", 0, &cookie );
    648 									ber_flatten2( ber, &value, 0 );
    649 
    650 									newctrl = op->o_tmprealloc( gs.ctrls[c],
    651 										sizeof(LDAPControl) + oidlen + 1 + value.bv_len + 1,
    652 										op->o_tmpmemctx);
    653 									newctrl->ldctl_iscritical = gs.ctrls[c]->ldctl_iscritical;
    654 									newctrl->ldctl_oid = (char *)&newctrl[1];
    655 									lutil_strcopy( newctrl->ldctl_oid, gs.ctrls[c]->ldctl_oid );
    656 									newctrl->ldctl_value.bv_len = value.bv_len;
    657 									lutil_memcopy( newctrl->ldctl_value.bv_val,
    658 										value.bv_val, value.bv_len );
    659 
    660 									gs.ctrls[c] = newctrl;
    661 
    662 									ber_free_buf( ber );
    663 
    664 								} else if ( !BER_BVISEMPTY( &cookie ) && op->o_bd != b0 ) {
    665 									/* if cookie not empty, it's again this database's turn */
    666 									op->o_conn->c_pagedresults_state.ps_be = op->o_bd;
    667 								}
    668 							}
    669 						}
    670 
    671 						goto end_of_loop;
    672 					}
    673 
    674 					/* This backend has run out of entries, but more responses
    675 					 * can fit in the page. Fake a reset of the state so the
    676 					 * next backend will start up properly. Only back-[bh]db
    677 					 * and back-sql look at this state info.
    678 					 */
    679 					ps->ps_cookie = (PagedResultsCookie)0;
    680 					BER_BVZERO( &ps->ps_cookieval );
    681 
    682 					{
    683 						/* change the size of the page in the request
    684 						 * that will be propagated, and reset the cookie */
    685 						BerElementBuffer berbuf;
    686 						BerElement *ber = (BerElement *)&berbuf;
    687 						int size = ps->ps_size - rs->sr_nentries;
    688 						struct berval cookie = BER_BVC(""), value;
    689 						int c;
    690 
    691 						for (c = 0; op->o_ctrls[c] != NULL; c++) {
    692 							if (strcmp(op->o_ctrls[c]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS) == 0)
    693 								break;
    694 						}
    695 
    696 						assert( op->o_ctrls[c] != NULL );
    697 
    698 						ber_init2( ber, NULL, LBER_USE_DER );
    699 						ber_printf( ber, "{iO}", size, &cookie );
    700 						ber_flatten2( ber, &value, 0 );
    701 						assert( op->o_ctrls[c]->ldctl_value.bv_len >= value.bv_len );
    702 						op->o_ctrls[c]->ldctl_value.bv_len = value.bv_len;
    703 						lutil_memcopy( op->o_ctrls[c]->ldctl_value.bv_val,
    704 							value.bv_val, value.bv_len );
    705 						ber_free_buf( ber );
    706 					}
    707 				}
    708 
    709 			default:
    710 				break;
    711 			}
    712 		}
    713 end_of_loop:;
    714 		op->ors_scope = scope0;
    715 		op->ors_tlimit = tlimit0;
    716 		op->o_time = starttime;
    717 
    718 		break;
    719 	}
    720 
    721 	op->o_callback = cb.sc_next;
    722 	if ( op->o_abandon ) {
    723 		rs->sr_err = SLAPD_ABANDON;
    724 	} else {
    725 		rs->sr_err = gs.err;
    726 		rs->sr_matched = gs.matched;
    727 		rs->sr_ref = gs.refs;
    728 	}
    729 	rs->sr_ctrls = gs.ctrls;
    730 
    731 	if ( rs->sr_err != SLAPD_NO_REPLY )
    732 		send_ldap_result( op, rs );
    733 
    734 	op->o_bd = b0;
    735 	op->o_bd->bd_info = bi0;
    736 	if (gs.matched)
    737 		free (gs.matched);
    738 	if (gs.refs)
    739 		ber_bvarray_free(gs.refs);
    740 	if (gs.ctrls) {
    741 		for (i = gs.nctrls; --i >= 0; ) {
    742 			op->o_tmpfree(gs.ctrls[i], op->o_tmpmemctx);
    743 		}
    744 		op->o_tmpfree(gs.ctrls, op->o_tmpmemctx);
    745 	}
    746 	return rs->sr_err;
    747 }
    748 
    749 static BackendDB toolDB;
    750 
    751 static int
    752 glue_tool_entry_open (
    753 	BackendDB *b0,
    754 	int mode
    755 )
    756 {
    757 	slap_overinfo	*oi = (slap_overinfo *)b0->bd_info;
    758 
    759 	/* We don't know which backend to talk to yet, so just
    760 	 * remember the mode and move on...
    761 	 */
    762 
    763 	glueMode = mode;
    764 	glueBack = NULL;
    765 	toolDB = *b0;
    766 	toolDB.bd_info = oi->oi_orig;
    767 
    768 	/* Sanity checks */
    769 	{
    770 		slap_overinst *on = glue_tool_inst( b0->bd_info );
    771 		glueinfo	*gi = on->on_bi.bi_private;
    772 
    773 		int i;
    774 		for (i = 0; i < gi->gi_nodes; i++) {
    775 			BackendDB *bd;
    776 			struct berval pdn;
    777 
    778 			dnParent( &gi->gi_n[i].gn_be->be_nsuffix[0], &pdn );
    779 			bd = select_backend( &pdn, 0 );
    780 			if ( bd ) {
    781 				ID id;
    782 				BackendDB db;
    783 
    784 				if ( overlay_is_over( bd ) ) {
    785 					slap_overinfo *oi = (slap_overinfo *)bd->bd_info;
    786 					db = *bd;
    787 					db.bd_info = oi->oi_orig;
    788 					bd = &db;
    789 				}
    790 
    791 				if ( !bd->bd_info->bi_tool_dn2id_get
    792 					|| !bd->bd_info->bi_tool_entry_open
    793 					|| !bd->bd_info->bi_tool_entry_close )
    794 				{
    795 					continue;
    796 				}
    797 
    798 				bd->bd_info->bi_tool_entry_open( bd, 0 );
    799 				id = bd->bd_info->bi_tool_dn2id_get( bd, &gi->gi_n[i].gn_be->be_nsuffix[0] );
    800 				bd->bd_info->bi_tool_entry_close( bd );
    801 				if ( id != NOID ) {
    802 					Debug( LDAP_DEBUG_ANY,
    803 						"glue_tool_entry_open: subordinate database suffix entry DN=\"%s\" also present in superior database rooted at DN=\"%s\"\n",
    804 						gi->gi_n[i].gn_be->be_suffix[0].bv_val, bd->be_suffix[0].bv_val );
    805 					return LDAP_OTHER;
    806 				}
    807 			}
    808 		}
    809 	}
    810 
    811 	return 0;
    812 }
    813 
    814 static int
    815 glue_tool_entry_close (
    816 	BackendDB *b0
    817 )
    818 {
    819 	int rc = 0;
    820 
    821 	if (glueBack && glueBack != GLUEBACK_DONE) {
    822 		if (!glueBack->be_entry_close)
    823 			return 0;
    824 		rc = glueBack->be_entry_close (glueBack);
    825 	}
    826 	return rc;
    827 }
    828 
    829 static slap_overinst *
    830 glue_tool_inst(
    831 	BackendInfo *bi
    832 )
    833 {
    834 	slap_overinfo	*oi = (slap_overinfo *)bi;
    835 	slap_overinst	*on;
    836 
    837 	for ( on = oi->oi_list; on; on=on->on_next ) {
    838 		if ( !strcmp( on->on_bi.bi_type, glue.on_bi.bi_type ))
    839 			return on;
    840 	}
    841 	return NULL;
    842 }
    843 
    844 /* This function will only be called in tool mode */
    845 static int
    846 glue_open (
    847 	BackendInfo *bi
    848 )
    849 {
    850 	slap_overinst *on = glue_tool_inst( bi );
    851 	glueinfo		*gi = on->on_bi.bi_private;
    852 	static int glueOpened = 0;
    853 	int i, j, same, bsame = 0, rc = 0;
    854 	ConfigReply cr = {0};
    855 
    856 	if (glueOpened) return 0;
    857 
    858 	glueOpened = 1;
    859 
    860 	/* If we were invoked in tool mode, open all the underlying backends */
    861 	if (slapMode & SLAP_TOOL_MODE) {
    862 		for (i = 0; i<gi->gi_nodes; i++) {
    863 			same = 0;
    864 			/* Same bi_open as our main backend? */
    865 			if ( gi->gi_n[i].gn_be->bd_info->bi_open ==
    866 				on->on_info->oi_orig->bi_open )
    867 				bsame = 1;
    868 
    869 			/* Loop thru the bd_info's and make sure we only
    870 			 * invoke their bi_open functions once each.
    871 			 */
    872 			for ( j = 0; j<i; j++ ) {
    873 				if ( gi->gi_n[i].gn_be->bd_info->bi_open ==
    874 					gi->gi_n[j].gn_be->bd_info->bi_open ) {
    875 					same = 1;
    876 					break;
    877 				}
    878 			}
    879 			/* OK, it's unique and non-NULL, call it. */
    880 			if ( !same && gi->gi_n[i].gn_be->bd_info->bi_open )
    881 				rc = gi->gi_n[i].gn_be->bd_info->bi_open(
    882 					gi->gi_n[i].gn_be->bd_info );
    883 			/* Let backend.c take care of the rest of startup */
    884 			if ( !rc )
    885 				rc = backend_startup_one( gi->gi_n[i].gn_be, &cr );
    886 			if ( rc ) break;
    887 		}
    888 		if ( !rc && !bsame && on->on_info->oi_orig->bi_open )
    889 			rc = on->on_info->oi_orig->bi_open( on->on_info->oi_orig );
    890 
    891 	} /* other case is impossible */
    892 	return rc;
    893 }
    894 
    895 /* This function will only be called in tool mode */
    896 static int
    897 glue_close (
    898 	BackendInfo *bi
    899 )
    900 {
    901 	static int glueClosed = 0;
    902 	int rc = 0;
    903 
    904 	if (glueClosed) return 0;
    905 
    906 	glueClosed = 1;
    907 
    908 	if (slapMode & SLAP_TOOL_MODE) {
    909 		rc = backend_shutdown( NULL );
    910 	}
    911 	return rc;
    912 }
    913 
    914 static int
    915 glue_entry_get_rw (
    916 	Operation		*op,
    917 	struct berval	*dn,
    918 	ObjectClass		*oc,
    919 	AttributeDescription	*ad,
    920 	int	rw,
    921 	Entry	**e )
    922 {
    923 	int rc;
    924 	BackendDB *b0 = op->o_bd;
    925 	op->o_bd = glue_back_select( b0, dn );
    926 
    927 	if ( op->o_bd->be_fetch ) {
    928 		rc = op->o_bd->be_fetch( op, dn, oc, ad, rw, e );
    929 		if ( rc == LDAP_SUCCESS && *e ) {
    930 			glue_entry *ge = op->o_tmpcalloc( 1, sizeof(glue_entry),
    931 					op->o_tmpmemctx );
    932 
    933 			if ( !ge ) {
    934 				if ( op->o_bd->be_release ) {
    935 					op->o_bd->be_release( op, *e, rw );
    936 				} else {
    937 					entry_free( *e );
    938 				}
    939 				rc = LDAP_OTHER;
    940 				goto out;
    941 			}
    942 
    943 			/* b0 is on overlay_entry_get_ov's stack, we'll be passed a fresh
    944 			 * one at release time */
    945 			if ( op->o_bd != b0 ) {
    946 				ge->ge_be = op->o_bd;
    947 			}
    948 			ge->ge_bi = op->o_bd->bd_info;
    949 			ge->ge_orig = (*e)->e_private;
    950 			(*e)->e_private = ge;
    951 		}
    952 	} else {
    953 		rc = LDAP_UNWILLING_TO_PERFORM;
    954 	}
    955 
    956 out:
    957 	op->o_bd = b0;
    958 	return rc;
    959 }
    960 
    961 static int
    962 glue_entry_release_rw (
    963 	Operation *op,
    964 	Entry *e,
    965 	int rw
    966 )
    967 {
    968 	glue_entry *ge = e->e_private;
    969 	BackendDB *b0 = op->o_bd;
    970 	int rc = -1;
    971 
    972 	if ( glueBack ) {
    973 		op->o_bd = glueBack;
    974 	} else if ( ge ) {
    975 		assert( ge->ge_bi != NULL );
    976 		if ( ge->ge_be )
    977 			op->o_bd = ge->ge_be;
    978 		op->o_bd->bd_info = ge->ge_bi;
    979 		e->e_private = ge->ge_orig;
    980 		op->o_tmpfree( ge, op->o_tmpmemctx );
    981 	} else {
    982 		op->o_bd = glue_back_select( b0, &e->e_nname );
    983 	}
    984 
    985 	if ( op->o_bd->be_release ) {
    986 		rc = op->o_bd->be_release( op, e, rw );
    987 
    988 	} else {
    989 		/* FIXME: mimic be_entry_release_rw
    990 		 * when no be_release() available */
    991 		/* free entry */
    992 		entry_free( e );
    993 		rc = 0;
    994 	}
    995 	op->o_bd = b0;
    996 	return rc;
    997 }
    998 
    999 static struct berval *glue_base;
   1000 static int glue_scope;
   1001 static Filter *glue_filter;
   1002 
   1003 static ID
   1004 glue_tool_entry_first (
   1005 	BackendDB *b0
   1006 )
   1007 {
   1008 	slap_overinst	*on = glue_tool_inst( b0->bd_info );
   1009 	glueinfo		*gi = on->on_bi.bi_private;
   1010 	int i;
   1011 	ID rc;
   1012 
   1013 	/* If we're starting from scratch, start at the most general */
   1014 	if (!glueBack) {
   1015 		if ( toolDB.be_entry_open && toolDB.be_entry_first ) {
   1016 			glueBack = &toolDB;
   1017 		} else {
   1018 			for (i = gi->gi_nodes-1; i >= 0; i--) {
   1019 				if (gi->gi_n[i].gn_be->be_entry_open &&
   1020 					gi->gi_n[i].gn_be->be_entry_first) {
   1021 						glueBack = gi->gi_n[i].gn_be;
   1022 					break;
   1023 				}
   1024 			}
   1025 		}
   1026 	}
   1027 	if (!glueBack || !glueBack->be_entry_open || !glueBack->be_entry_first ||
   1028 		glueBack->be_entry_open (glueBack, glueMode) != 0)
   1029 		return NOID;
   1030 
   1031 	rc = glueBack->be_entry_first (glueBack);
   1032 	while ( rc == NOID ) {
   1033 		if ( glueBack && glueBack->be_entry_close )
   1034 			glueBack->be_entry_close (glueBack);
   1035 		for (i=0; i<gi->gi_nodes; i++) {
   1036 			if (gi->gi_n[i].gn_be == glueBack)
   1037 				break;
   1038 		}
   1039 		if (i == 0) {
   1040 			glueBack = GLUEBACK_DONE;
   1041 			break;
   1042 		} else {
   1043 			glueBack = gi->gi_n[i-1].gn_be;
   1044 			rc = glue_tool_entry_first (b0);
   1045 			if ( glueBack == GLUEBACK_DONE ) {
   1046 				break;
   1047 			}
   1048 		}
   1049 	}
   1050 	return rc;
   1051 }
   1052 
   1053 static ID
   1054 glue_tool_entry_first_x (
   1055 	BackendDB *b0,
   1056 	struct berval *base,
   1057 	int scope,
   1058 	Filter *f
   1059 )
   1060 {
   1061 	slap_overinst	*on = glue_tool_inst( b0->bd_info );
   1062 	glueinfo		*gi = on->on_bi.bi_private;
   1063 	int i;
   1064 	ID rc;
   1065 
   1066 	glue_base = base;
   1067 	glue_scope = scope;
   1068 	glue_filter = f;
   1069 
   1070 	/* If we're starting from scratch, start at the most general */
   1071 	if (!glueBack) {
   1072 		if ( toolDB.be_entry_open && toolDB.be_entry_first_x ) {
   1073 			glueBack = &toolDB;
   1074 		} else {
   1075 			for (i = gi->gi_nodes-1; i >= 0; i--) {
   1076 				if (gi->gi_n[i].gn_be->be_entry_open &&
   1077 					gi->gi_n[i].gn_be->be_entry_first_x)
   1078 				{
   1079 					glueBack = gi->gi_n[i].gn_be;
   1080 					break;
   1081 				}
   1082 			}
   1083 		}
   1084 	}
   1085 	if (!glueBack || !glueBack->be_entry_open || !glueBack->be_entry_first_x ||
   1086 		glueBack->be_entry_open (glueBack, glueMode) != 0)
   1087 		return NOID;
   1088 
   1089 	rc = glueBack->be_entry_first_x (glueBack,
   1090 		glue_base, glue_scope, glue_filter);
   1091 	while ( rc == NOID ) {
   1092 		if ( glueBack && glueBack->be_entry_close )
   1093 			glueBack->be_entry_close (glueBack);
   1094 		for (i=0; i<gi->gi_nodes; i++) {
   1095 			if (gi->gi_n[i].gn_be == glueBack)
   1096 				break;
   1097 		}
   1098 		if (i == 0) {
   1099 			glueBack = GLUEBACK_DONE;
   1100 			break;
   1101 		} else {
   1102 			glueBack = gi->gi_n[i-1].gn_be;
   1103 			rc = glue_tool_entry_first_x (b0,
   1104 				glue_base, glue_scope, glue_filter);
   1105 			if ( glueBack == GLUEBACK_DONE ) {
   1106 				break;
   1107 			}
   1108 		}
   1109 	}
   1110 	return rc;
   1111 }
   1112 
   1113 static ID
   1114 glue_tool_entry_next (
   1115 	BackendDB *b0
   1116 )
   1117 {
   1118 	slap_overinst	*on = glue_tool_inst( b0->bd_info );
   1119 	glueinfo		*gi = on->on_bi.bi_private;
   1120 	int i;
   1121 	ID rc;
   1122 
   1123 	if (!glueBack || !glueBack->be_entry_next)
   1124 		return NOID;
   1125 
   1126 	rc = glueBack->be_entry_next (glueBack);
   1127 
   1128 	/* If we ran out of entries in one database, move on to the next */
   1129 	while (rc == NOID) {
   1130 		if ( glueBack && glueBack->be_entry_close )
   1131 			glueBack->be_entry_close (glueBack);
   1132 		for (i=0; i<gi->gi_nodes; i++) {
   1133 			if (gi->gi_n[i].gn_be == glueBack)
   1134 				break;
   1135 		}
   1136 		if (i == 0) {
   1137 			glueBack = GLUEBACK_DONE;
   1138 			break;
   1139 		} else {
   1140 			glueBack = gi->gi_n[i-1].gn_be;
   1141 			if ( glue_base || glue_filter ) {
   1142 				/* using entry_first_x() */
   1143 				rc = glue_tool_entry_first_x (b0,
   1144 					glue_base, glue_scope, glue_filter);
   1145 
   1146 			} else {
   1147 				/* using entry_first() */
   1148 				rc = glue_tool_entry_first (b0);
   1149 			}
   1150 			if ( glueBack == GLUEBACK_DONE ) {
   1151 				break;
   1152 			}
   1153 		}
   1154 	}
   1155 	return rc;
   1156 }
   1157 
   1158 static ID
   1159 glue_tool_dn2id_get (
   1160 	BackendDB *b0,
   1161 	struct berval *dn
   1162 )
   1163 {
   1164 	BackendDB *be, b2;
   1165 	int rc = -1;
   1166 
   1167 	b2 = *b0;
   1168 	b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info );
   1169 	be = glue_back_select (&b2, dn);
   1170 	if ( be == &b2 ) be = &toolDB;
   1171 
   1172 	if (!be->be_dn2id_get)
   1173 		return NOID;
   1174 
   1175 	if (!glueBack) {
   1176 		if ( be->be_entry_open ) {
   1177 			rc = be->be_entry_open (be, glueMode);
   1178 		}
   1179 		if (rc != 0) {
   1180 			return NOID;
   1181 		}
   1182 	} else if (be != glueBack) {
   1183 		/* If this entry belongs in a different branch than the
   1184 		 * previous one, close the current database and open the
   1185 		 * new one.
   1186 		 */
   1187 		if ( glueBack->be_entry_close ) {
   1188 			glueBack->be_entry_close (glueBack);
   1189 		}
   1190 		if ( be->be_entry_open ) {
   1191 			rc = be->be_entry_open (be, glueMode);
   1192 		}
   1193 		if (rc != 0) {
   1194 			return NOID;
   1195 		}
   1196 	}
   1197 	glueBack = be;
   1198 	return be->be_dn2id_get (be, dn);
   1199 }
   1200 
   1201 static Entry *
   1202 glue_tool_entry_get (
   1203 	BackendDB *b0,
   1204 	ID id
   1205 )
   1206 {
   1207 	if (!glueBack || !glueBack->be_entry_get)
   1208 		return NULL;
   1209 
   1210 	return glueBack->be_entry_get (glueBack, id);
   1211 }
   1212 
   1213 static ID
   1214 glue_tool_entry_put (
   1215 	BackendDB *b0,
   1216 	Entry *e,
   1217 	struct berval *text
   1218 )
   1219 {
   1220 	BackendDB *be, b2;
   1221 	int rc = -1;
   1222 
   1223 	b2 = *b0;
   1224 	b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info );
   1225 	be = glue_back_select (&b2, &e->e_nname);
   1226 	if ( be == &b2 ) be = &toolDB;
   1227 
   1228 	if (!be->be_entry_put)
   1229 		return NOID;
   1230 
   1231 	if (!glueBack) {
   1232 		if ( be->be_entry_open ) {
   1233 			rc = be->be_entry_open (be, glueMode);
   1234 		}
   1235 		if (rc != 0) {
   1236 			return NOID;
   1237 		}
   1238 	} else if (be != glueBack) {
   1239 		/* If this entry belongs in a different branch than the
   1240 		 * previous one, close the current database and open the
   1241 		 * new one.
   1242 		 */
   1243 		if ( glueBack->be_entry_close ) {
   1244 			glueBack->be_entry_close (glueBack);
   1245 		}
   1246 		if ( be->be_entry_open ) {
   1247 			rc = be->be_entry_open (be, glueMode);
   1248 		}
   1249 		if (rc != 0) {
   1250 			return NOID;
   1251 		}
   1252 	}
   1253 	glueBack = be;
   1254 	return be->be_entry_put (be, e, text);
   1255 }
   1256 
   1257 static ID
   1258 glue_tool_entry_modify (
   1259 	BackendDB *b0,
   1260 	Entry *e,
   1261 	struct berval *text
   1262 )
   1263 {
   1264 	if (!glueBack || !glueBack->be_entry_modify)
   1265 		return NOID;
   1266 
   1267 	return glueBack->be_entry_modify (glueBack, e, text);
   1268 }
   1269 
   1270 static int
   1271 glue_tool_entry_reindex (
   1272 	BackendDB *b0,
   1273 	ID id,
   1274 	AttributeDescription **adv
   1275 )
   1276 {
   1277 	if (!glueBack || !glueBack->be_entry_reindex)
   1278 		return -1;
   1279 
   1280 	return glueBack->be_entry_reindex (glueBack, id, adv);
   1281 }
   1282 
   1283 static int
   1284 glue_tool_sync (
   1285 	BackendDB *b0
   1286 )
   1287 {
   1288 	slap_overinst	*on = glue_tool_inst( b0->bd_info );
   1289 	glueinfo		*gi = on->on_bi.bi_private;
   1290 	BackendInfo		*bi = b0->bd_info;
   1291 	int i;
   1292 
   1293 	/* just sync everyone */
   1294 	for (i = 0; i<gi->gi_nodes; i++)
   1295 		if (gi->gi_n[i].gn_be->be_sync)
   1296 			gi->gi_n[i].gn_be->be_sync (gi->gi_n[i].gn_be);
   1297 	b0->bd_info = on->on_info->oi_orig;
   1298 	if ( b0->be_sync )
   1299 		b0->be_sync( b0 );
   1300 	b0->bd_info = bi;
   1301 	return 0;
   1302 }
   1303 
   1304 typedef struct glue_Addrec {
   1305 	struct glue_Addrec *ga_next;
   1306 	BackendDB *ga_be;
   1307 } glue_Addrec;
   1308 
   1309 /* List of added subordinates */
   1310 static glue_Addrec *ga_list;
   1311 static int ga_adding;
   1312 
   1313 static int
   1314 glue_db_init(
   1315 	BackendDB *be,
   1316 	ConfigReply *cr
   1317 )
   1318 {
   1319 	slap_overinst	*on = (slap_overinst *)be->bd_info;
   1320 	slap_overinfo	*oi = on->on_info;
   1321 	BackendInfo	*bi = oi->oi_orig;
   1322 	glueinfo *gi;
   1323 
   1324 	if ( SLAP_GLUE_SUBORDINATE( be )) {
   1325 		Debug( LDAP_DEBUG_ANY, "glue: backend %s is already subordinate, "
   1326 			"cannot have glue overlay!\n",
   1327 			be->be_suffix[0].bv_val );
   1328 		return LDAP_OTHER;
   1329 	}
   1330 
   1331 	gi = ch_calloc( 1, sizeof(glueinfo));
   1332 	on->on_bi.bi_private = gi;
   1333 	dnParent( be->be_nsuffix, &gi->gi_pdn );
   1334 
   1335 	/* Currently the overlay framework doesn't handle these entry points
   1336 	 * but we need them....
   1337 	 */
   1338 	oi->oi_bi.bi_open = glue_open;
   1339 	oi->oi_bi.bi_close = glue_close;
   1340 
   1341 	/* Only advertise these if the root DB supports them */
   1342 	if ( bi->bi_tool_entry_open )
   1343 		oi->oi_bi.bi_tool_entry_open = glue_tool_entry_open;
   1344 	if ( bi->bi_tool_entry_close )
   1345 		oi->oi_bi.bi_tool_entry_close = glue_tool_entry_close;
   1346 	if ( bi->bi_tool_entry_first )
   1347 		oi->oi_bi.bi_tool_entry_first = glue_tool_entry_first;
   1348 	/* FIXME: check whether all support bi_tool_entry_first_x() ? */
   1349 	if ( bi->bi_tool_entry_first_x )
   1350 		oi->oi_bi.bi_tool_entry_first_x = glue_tool_entry_first_x;
   1351 	if ( bi->bi_tool_entry_next )
   1352 		oi->oi_bi.bi_tool_entry_next = glue_tool_entry_next;
   1353 	if ( bi->bi_tool_entry_get )
   1354 		oi->oi_bi.bi_tool_entry_get = glue_tool_entry_get;
   1355 	if ( bi->bi_tool_dn2id_get )
   1356 		oi->oi_bi.bi_tool_dn2id_get = glue_tool_dn2id_get;
   1357 	if ( bi->bi_tool_entry_put )
   1358 		oi->oi_bi.bi_tool_entry_put = glue_tool_entry_put;
   1359 	if ( bi->bi_tool_entry_reindex )
   1360 		oi->oi_bi.bi_tool_entry_reindex = glue_tool_entry_reindex;
   1361 	if ( bi->bi_tool_entry_modify )
   1362 		oi->oi_bi.bi_tool_entry_modify = glue_tool_entry_modify;
   1363 	if ( bi->bi_tool_sync )
   1364 		oi->oi_bi.bi_tool_sync = glue_tool_sync;
   1365 
   1366 	SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_INSTANCE;
   1367 
   1368 	if ( ga_list && ( slapMode & SLAP_SERVER_MODE ) ) {
   1369 		be->bd_info = (BackendInfo *)oi;
   1370 		glue_sub_attach( 1 );
   1371 	}
   1372 
   1373 	return 0;
   1374 }
   1375 
   1376 static int
   1377 glue_db_destroy (
   1378 	BackendDB *be,
   1379 	ConfigReply *cr
   1380 )
   1381 {
   1382 	slap_overinst	*on = (slap_overinst *)be->bd_info;
   1383 	glueinfo		*gi = (glueinfo *)on->on_bi.bi_private;
   1384 
   1385 	free (gi);
   1386 	return 0;
   1387 }
   1388 
   1389 static int
   1390 glue_db_close(
   1391 	BackendDB *be,
   1392 	ConfigReply *cr
   1393 )
   1394 {
   1395 	slap_overinst	*on = (slap_overinst *)be->bd_info;
   1396 
   1397 	on->on_info->oi_bi.bi_db_close = 0;
   1398 	return 0;
   1399 }
   1400 
   1401 int
   1402 glue_sub_del( BackendDB *b0 )
   1403 {
   1404 	BackendDB *be;
   1405 	int rc = 0;
   1406 
   1407 	/* Find the top backend for this subordinate */
   1408 	be = b0;
   1409 	while ( (be=LDAP_STAILQ_NEXT( be, be_next )) != NULL ) {
   1410 		slap_overinfo *oi;
   1411 		slap_overinst *on;
   1412 		glueinfo *gi;
   1413 		int i;
   1414 
   1415 		if ( SLAP_GLUE_SUBORDINATE( be ))
   1416 			continue;
   1417 		if ( !SLAP_GLUE_INSTANCE( be ))
   1418 			continue;
   1419 		if ( !dnIsSuffix( &b0->be_nsuffix[0], &be->be_nsuffix[0] ))
   1420 			continue;
   1421 
   1422 		/* OK, got the right backend, find the overlay */
   1423 		oi = (slap_overinfo *)be->bd_info;
   1424 		for ( on=oi->oi_list; on; on=on->on_next ) {
   1425 			if ( on->on_bi.bi_type == glue.on_bi.bi_type )
   1426 				break;
   1427 		}
   1428 		assert( on != NULL );
   1429 		gi = on->on_bi.bi_private;
   1430 		for ( i=0; i < gi->gi_nodes; i++ ) {
   1431 			if ( gi->gi_n[i].gn_be == b0 ) {
   1432 				int j;
   1433 
   1434 				for (j=i+1; j < gi->gi_nodes; j++)
   1435 					gi->gi_n[j-1] = gi->gi_n[j];
   1436 
   1437 				gi->gi_nodes--;
   1438 			}
   1439 		}
   1440 		/* Mark as no longer linked/sub */
   1441 		b0->be_flags &= ~(SLAP_DBFLAG_GLUE_SUBORDINATE|SLAP_DBFLAG_GLUE_LINKED|
   1442 			SLAP_DBFLAG_GLUE_ADVERTISE);
   1443 		b0->be_pcsn_p = &b0->be_pcsn_st;
   1444 		break;
   1445 	}
   1446 	if ( be == NULL )
   1447 		rc = LDAP_NO_SUCH_OBJECT;
   1448 
   1449 	return rc;
   1450 }
   1451 
   1452 
   1453 /* Attach all the subordinate backends to their superior */
   1454 int
   1455 glue_sub_attach( int online )
   1456 {
   1457 	glue_Addrec *ga, *gnext = NULL;
   1458 	int rc = 0;
   1459 
   1460 	if ( ga_adding )
   1461 		return 0;
   1462 
   1463 	ga_adding = 1;
   1464 
   1465 	/* For all the subordinate backends */
   1466 	for ( ga=ga_list; ga != NULL; ga = gnext ) {
   1467 		BackendDB *be;
   1468 
   1469 		gnext = ga->ga_next;
   1470 
   1471 		/* Find the top backend for this subordinate */
   1472 		be = ga->ga_be;
   1473 		while ( (be=LDAP_STAILQ_NEXT( be, be_next )) != NULL ) {
   1474 			slap_overinfo *oi;
   1475 			slap_overinst *on;
   1476 			glueinfo *gi;
   1477 
   1478 			if ( SLAP_GLUE_SUBORDINATE( be ))
   1479 				continue;
   1480 			if ( !dnIsSuffix( &ga->ga_be->be_nsuffix[0], &be->be_nsuffix[0] ))
   1481 				continue;
   1482 
   1483 			/* If it's not already configured, set up the overlay */
   1484 			if ( !SLAP_GLUE_INSTANCE( be )) {
   1485 				rc = overlay_config( be, glue.on_bi.bi_type, -1, NULL, NULL);
   1486 				if ( rc )
   1487 					break;
   1488 			}
   1489 			/* Find the overlay instance */
   1490 			oi = (slap_overinfo *)be->bd_info;
   1491 			for ( on=oi->oi_list; on; on=on->on_next ) {
   1492 				if ( on->on_bi.bi_type == glue.on_bi.bi_type )
   1493 					break;
   1494 			}
   1495 			assert( on != NULL );
   1496 			gi = on->on_bi.bi_private;
   1497 			gi = (glueinfo *)ch_realloc( gi, sizeof(glueinfo) +
   1498 				gi->gi_nodes * sizeof(gluenode));
   1499 			gi->gi_n[gi->gi_nodes].gn_be = ga->ga_be;
   1500 			dnParent( &ga->ga_be->be_nsuffix[0],
   1501 				&gi->gi_n[gi->gi_nodes].gn_pdn );
   1502 			gi->gi_nodes++;
   1503 			on->on_bi.bi_private = gi;
   1504 			ga->ga_be->be_pcsn_p = be->be_pcsn_p;
   1505 			ga->ga_be->be_flags |= SLAP_DBFLAG_GLUE_LINKED;
   1506 			break;
   1507 		}
   1508 		if ( !be ) {
   1509 			Debug( LDAP_DEBUG_ANY, "glue: no superior found for sub %s!\n",
   1510 				ga->ga_be->be_suffix[0].bv_val );
   1511 			/* allow this for now, assume a superior will
   1512 			 * be added later
   1513 			 */
   1514 			if ( online ) {
   1515 				rc = 0;
   1516 				gnext = ga_list;
   1517 				break;
   1518 			}
   1519 			rc = LDAP_NO_SUCH_OBJECT;
   1520 		}
   1521 		ch_free( ga );
   1522 		if ( rc ) break;
   1523 	}
   1524 
   1525 	ga_list = gnext;
   1526 
   1527 	ga_adding = 0;
   1528 
   1529 	return rc;
   1530 }
   1531 
   1532 int
   1533 glue_sub_add( BackendDB *be, int advert, int online )
   1534 {
   1535 	glue_Addrec *ga;
   1536 	int rc = 0;
   1537 
   1538 	if ( overlay_is_inst( be, "glue" )) {
   1539 		Debug( LDAP_DEBUG_ANY, "glue: backend %s already has glue overlay, "
   1540 			"cannot be a subordinate!\n",
   1541 			be->be_suffix[0].bv_val );
   1542 		return LDAP_OTHER;
   1543 	}
   1544 	SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_SUBORDINATE;
   1545 	if ( advert )
   1546 		SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_ADVERTISE;
   1547 
   1548 	ga = ch_malloc( sizeof( glue_Addrec ));
   1549 	ga->ga_next = ga_list;
   1550 	ga->ga_be = be;
   1551 	ga_list = ga;
   1552 
   1553 	if ( online )
   1554 		rc = glue_sub_attach( online );
   1555 
   1556 	return rc;
   1557 }
   1558 
   1559 static int
   1560 glue_access_allowed(
   1561 	Operation		*op,
   1562 	Entry			*e,
   1563 	AttributeDescription	*desc,
   1564 	struct berval		*val,
   1565 	slap_access_t		access,
   1566 	AccessControlState	*state,
   1567 	slap_mask_t		*maskp )
   1568 {
   1569 	BackendDB *b0, *be = glue_back_select( op->o_bd, &e->e_nname );
   1570 	int rc;
   1571 
   1572 	if ( be == NULL || be == op->o_bd || be->bd_info->bi_access_allowed == NULL )
   1573 		return SLAP_CB_CONTINUE;
   1574 
   1575 	b0 = op->o_bd;
   1576 	op->o_bd = be;
   1577 	rc = be->bd_info->bi_access_allowed ( op, e, desc, val, access, state, maskp );
   1578 	op->o_bd = b0;
   1579 	return rc;
   1580 }
   1581 
   1582 int
   1583 glue_sub_init()
   1584 {
   1585 	glue.on_bi.bi_type = "glue";
   1586 
   1587 	glue.on_bi.bi_db_init = glue_db_init;
   1588 	glue.on_bi.bi_db_close = glue_db_close;
   1589 	glue.on_bi.bi_db_destroy = glue_db_destroy;
   1590 
   1591 	glue.on_bi.bi_op_search = glue_op_search;
   1592 	glue.on_bi.bi_op_modify = glue_op_func;
   1593 	glue.on_bi.bi_op_modrdn = glue_op_func;
   1594 	glue.on_bi.bi_op_add = glue_op_func;
   1595 	glue.on_bi.bi_op_delete = glue_op_func;
   1596 	glue.on_bi.bi_op_abandon = glue_op_abandon;
   1597 	glue.on_bi.bi_extended = glue_op_func;
   1598 
   1599 	glue.on_bi.bi_chk_referrals = glue_chk_referrals;
   1600 	glue.on_bi.bi_chk_controls = glue_chk_controls;
   1601 	glue.on_bi.bi_entry_get_rw = glue_entry_get_rw;
   1602 	glue.on_bi.bi_entry_release_rw = glue_entry_release_rw;
   1603 	glue.on_bi.bi_access_allowed = glue_access_allowed;
   1604 
   1605 	glue.on_response = glue_response;
   1606 
   1607 	return overlay_register( &glue );
   1608 }
   1609