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