1 /*	$NetBSD: backglue.c,v 1.3 2021/08/14 16:14:58 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-2021 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.3 2021/08/14 16:14:58 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 *
glue_back_select(BackendDB * be,struct berval * dn)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 static int
glue_op_cleanup(Operation * op,SlapReply * rs)102 glue_op_cleanup( Operation *op, SlapReply *rs )
103 {
104 	/* This is not a final result */
105 	if (rs->sr_type == REP_RESULT )
106 		rs->sr_type = REP_GLUE_RESULT;
107 	return SLAP_CB_CONTINUE;
108 }
109 
110 static int
glue_op_response(Operation * op,SlapReply * rs)111 glue_op_response ( Operation *op, SlapReply *rs )
112 {
113 	glue_state *gs = op->o_callback->sc_private;
114 
115 	switch(rs->sr_type) {
116 	case REP_SEARCH:
117 	case REP_SEARCHREF:
118 	case REP_INTERMEDIATE:
119 		return SLAP_CB_CONTINUE;
120 
121 	default:
122 		if (rs->sr_err == LDAP_SUCCESS ||
123 			rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ||
124 			rs->sr_err == LDAP_TIMELIMIT_EXCEEDED ||
125 			rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED ||
126 			rs->sr_err == LDAP_NO_SUCH_OBJECT ||
127 			gs->err != LDAP_SUCCESS)
128 			gs->err = rs->sr_err;
129 		if (gs->err == LDAP_SUCCESS && gs->matched) {
130 			ch_free (gs->matched);
131 			gs->matched = NULL;
132 			gs->matchlen = 0;
133 		}
134 		if (gs->err != LDAP_SUCCESS && rs->sr_matched) {
135 			int len;
136 			len = strlen (rs->sr_matched);
137 			if (len > gs->matchlen) {
138 				if (gs->matched)
139 					ch_free (gs->matched);
140 				gs->matched = ch_strdup (rs->sr_matched);
141 				gs->matchlen = len;
142 			}
143 		}
144 		if (rs->sr_ref) {
145 			int i, j, k;
146 			BerVarray new;
147 
148 			for (i=0; rs->sr_ref[i].bv_val; i++);
149 
150 			j = gs->nrefs;
151 			if (!j) {
152 				new = ch_malloc ((i+1)*sizeof(struct berval));
153 			} else {
154 				new = ch_realloc(gs->refs,
155 					(j+i+1)*sizeof(struct berval));
156 			}
157 			for (k=0; k<i; j++,k++) {
158 				ber_dupbv( &new[j], &rs->sr_ref[k] );
159 			}
160 			new[j].bv_val = NULL;
161 			gs->nrefs = j;
162 			gs->refs = new;
163 		}
164 		if (rs->sr_ctrls) {
165 			int i, j, k;
166 			LDAPControl **newctrls;
167 
168 			for (i=0; rs->sr_ctrls[i]; i++);
169 
170 			j = gs->nctrls;
171 			if (!j) {
172 				newctrls = op->o_tmpalloc((i+1)*sizeof(LDAPControl *),
173 					op->o_tmpmemctx);
174 			} else {
175 				/* Forget old pagedResults response if we're sending
176 				 * a new one now
177 				 */
178 				if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
179 					int newpage = 0;
180 					for ( k=0; k<i; k++ ) {
181 						if ( !strcmp(rs->sr_ctrls[k]->ldctl_oid,
182 							LDAP_CONTROL_PAGEDRESULTS )) {
183 							newpage = 1;
184 							break;
185 						}
186 					}
187 					if ( newpage ) {
188 						for ( k=0; k<j; k++ ) {
189 							if ( !strcmp(gs->ctrls[k]->ldctl_oid,
190 								LDAP_CONTROL_PAGEDRESULTS ))
191 							{
192 								op->o_tmpfree(gs->ctrls[k], op->o_tmpmemctx);
193 								gs->ctrls[k] = gs->ctrls[--j];
194 								gs->ctrls[j] = NULL;
195 								break;
196 							}
197 						}
198 					}
199 				}
200 				newctrls = op->o_tmprealloc(gs->ctrls,
201 					(j+i+1)*sizeof(LDAPControl *), op->o_tmpmemctx);
202 			}
203 			for (k=0; k<i; j++,k++) {
204 				ber_len_t oidlen = strlen( rs->sr_ctrls[k]->ldctl_oid );
205 				newctrls[j] = op->o_tmpalloc(sizeof(LDAPControl) + oidlen + 1 + rs->sr_ctrls[k]->ldctl_value.bv_len + 1,
206 					op->o_tmpmemctx);
207 				newctrls[j]->ldctl_iscritical = rs->sr_ctrls[k]->ldctl_iscritical;
208 				newctrls[j]->ldctl_oid = (char *)&newctrls[j][1];
209 				lutil_strcopy( newctrls[j]->ldctl_oid, rs->sr_ctrls[k]->ldctl_oid );
210 				if ( !BER_BVISNULL( &rs->sr_ctrls[k]->ldctl_value ) ) {
211 					newctrls[j]->ldctl_value.bv_val = &newctrls[j]->ldctl_oid[oidlen + 1];
212 					newctrls[j]->ldctl_value.bv_len = rs->sr_ctrls[k]->ldctl_value.bv_len;
213 					lutil_memcopy( newctrls[j]->ldctl_value.bv_val,
214 						rs->sr_ctrls[k]->ldctl_value.bv_val,
215 						rs->sr_ctrls[k]->ldctl_value.bv_len + 1 );
216 				} else {
217 					BER_BVZERO( &newctrls[j]->ldctl_value );
218 				}
219 			}
220 			newctrls[j] = NULL;
221 			gs->nctrls = j;
222 			gs->ctrls = newctrls;
223 		}
224 	}
225 	return 0;
226 }
227 
228 static int
glue_op_func(Operation * op,SlapReply * rs)229 glue_op_func ( Operation *op, SlapReply *rs )
230 {
231 	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
232 	BackendDB *b0 = op->o_bd;
233 	BackendInfo *bi0 = op->o_bd->bd_info, *bi1;
234 	slap_operation_t which = op_bind;
235 	int rc;
236 
237 	op->o_bd = glue_back_select (b0, &op->o_req_ndn);
238 
239 	/* If we're on the primary backend, let overlay framework handle it */
240 	if ( op->o_bd == b0 )
241 		return SLAP_CB_CONTINUE;
242 
243 	b0->bd_info = on->on_info->oi_orig;
244 
245 	switch(op->o_tag) {
246 	case LDAP_REQ_ADD: which = op_add; break;
247 	case LDAP_REQ_DELETE: which = op_delete; break;
248 	case LDAP_REQ_MODIFY: which = op_modify; break;
249 	case LDAP_REQ_MODRDN: which = op_modrdn; break;
250 	case LDAP_REQ_EXTENDED: which = op_extended; break;
251 	default: assert( 0 ); break;
252 	}
253 
254 	bi1 = op->o_bd->bd_info;
255 	rc = (&bi1->bi_op_bind)[ which ] ?
256 		(&bi1->bi_op_bind)[ which ]( op, rs ) : SLAP_CB_BYPASS;
257 
258 	op->o_bd = b0;
259 	op->o_bd->bd_info = bi0;
260 	return rc;
261 }
262 
263 static int
glue_op_abandon(Operation * op,SlapReply * rs)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
glue_response(Operation * op,SlapReply * rs)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 primary 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
glue_chk_referrals(Operation * op,SlapReply * rs)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
glue_chk_controls(Operation * op,SlapReply * rs)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 primary 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
glue_sub_search(Operation * op,SlapReply * rs,BackendDB * b0,slap_overinst * on)363 glue_sub_search( Operation *op, SlapReply *rs, BackendDB *b0,
364 	slap_overinst *on )
365 {
366 	/* Process any overlays on the primary 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
glue_op_search(Operation * op,SlapReply * rs)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
glue_tool_entry_open(BackendDB * b0,int mode)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 );
791 					return LDAP_OTHER;
792 				}
793 			}
794 		}
795 	}
796 
797 	return 0;
798 }
799 
800 static int
glue_tool_entry_close(BackendDB * b0)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 *
glue_tool_inst(BackendInfo * bi)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
glue_open(BackendInfo * bi)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
glue_close(BackendInfo * bi)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
glue_entry_get_rw(Operation * op,struct berval * dn,ObjectClass * oc,AttributeDescription * ad,int rw,Entry ** e)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
glue_entry_release_rw(Operation * op,Entry * e,int rw)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
glue_tool_entry_first(BackendDB * b0)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
glue_tool_entry_first_x(BackendDB * b0,struct berval * base,int scope,Filter * f)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
glue_tool_entry_next(BackendDB * b0)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
glue_tool_dn2id_get(BackendDB * b0,struct berval * dn)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 *
glue_tool_entry_get(BackendDB * b0,ID id)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
glue_tool_entry_put(BackendDB * b0,Entry * e,struct berval * text)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
glue_tool_entry_modify(BackendDB * b0,Entry * e,struct berval * text)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
glue_tool_entry_reindex(BackendDB * b0,ID id,AttributeDescription ** adv)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
glue_tool_sync(BackendDB * b0)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
glue_db_init(BackendDB * be,ConfigReply * cr)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 );
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 && ( slapMode & SLAP_SERVER_MODE ) ) {
1318 		be->bd_info = (BackendInfo *)oi;
1319 		glue_sub_attach( 1 );
1320 	}
1321 
1322 	return 0;
1323 }
1324 
1325 static int
glue_db_destroy(BackendDB * be,ConfigReply * cr)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 0;
1336 }
1337 
1338 static int
glue_db_close(BackendDB * be,ConfigReply * cr)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
glue_sub_del(BackendDB * b0)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
glue_sub_attach(int online)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 );
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
glue_sub_add(BackendDB * be,int advert,int online)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 );
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
glue_access_allowed(Operation * op,Entry * e,AttributeDescription * desc,struct berval * val,slap_access_t access,AccessControlState * state,slap_mask_t * maskp)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
glue_sub_init()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