xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-meta/conn.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: conn.c,v 1.1.1.6 2018/02/06 01:53:16 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2017 The OpenLDAP Foundation.
7  * Portions Copyright 2001-2003 Pierangelo Masarati.
8  * Portions Copyright 1999-2003 Howard Chu.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* ACKNOWLEDGEMENTS:
20  * This work was initially developed by the Howard Chu for inclusion
21  * in OpenLDAP Software and subsequently enhanced by Pierangelo
22  * Masarati.
23  */
24 
25 #include <sys/cdefs.h>
26 __RCSID("$NetBSD: conn.c,v 1.1.1.6 2018/02/06 01:53:16 christos Exp $");
27 
28 #include "portable.h"
29 
30 #include <stdio.h>
31 
32 #include <ac/errno.h>
33 #include <ac/socket.h>
34 #include <ac/string.h>
35 
36 
37 #define AVL_INTERNAL
38 #include "slap.h"
39 #include "../back-ldap/back-ldap.h"
40 #include "back-meta.h"
41 
42 /*
43  * meta_back_conndn_cmp
44  *
45  * compares two struct metaconn based on the value of the conn pointer
46  * and of the local DN; used by avl stuff
47  */
48 int
49 meta_back_conndn_cmp(
50 	const void *c1,
51 	const void *c2 )
52 {
53 	metaconn_t	*mc1 = ( metaconn_t * )c1;
54         metaconn_t	*mc2 = ( metaconn_t * )c2;
55 	int		rc;
56 
57 	/* If local DNs don't match, it is definitely not a match */
58 	/* For shared sessions, conn is NULL. Only explicitly
59 	 * bound sessions will have non-NULL conn.
60 	 */
61 	rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn );
62 	if ( rc == 0 ) {
63 		rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn );
64 	}
65 
66 	return rc;
67 }
68 
69 /*
70  * meta_back_conndnmc_cmp
71  *
72  * compares two struct metaconn based on the value of the conn pointer,
73  * the local DN and the struct pointer; used by avl stuff
74  */
75 static int
76 meta_back_conndnmc_cmp(
77 	const void *c1,
78 	const void *c2 )
79 {
80 	metaconn_t	*mc1 = ( metaconn_t * )c1;
81         metaconn_t	*mc2 = ( metaconn_t * )c2;
82 	int		rc;
83 
84 	/* If local DNs don't match, it is definitely not a match */
85 	/* For shared sessions, conn is NULL. Only explicitly
86 	 * bound sessions will have non-NULL conn.
87 	 */
88 	rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn );
89 	if ( rc == 0 ) {
90 		rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn );
91 		if ( rc == 0 ) {
92 			rc = SLAP_PTRCMP( mc1, mc2 );
93 		}
94 	}
95 
96 	return rc;
97 }
98 
99 /*
100  * meta_back_conn_cmp
101  *
102  * compares two struct metaconn based on the value of the conn pointer;
103  * used by avl stuff
104  */
105 int
106 meta_back_conn_cmp(
107 	const void *c1,
108 	const void *c2 )
109 {
110 	metaconn_t	*mc1 = ( metaconn_t * )c1;
111         metaconn_t	*mc2 = ( metaconn_t * )c2;
112 
113 	/* For shared sessions, conn is NULL. Only explicitly
114 	 * bound sessions will have non-NULL conn.
115 	 */
116 	return SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn );
117 }
118 
119 /*
120  * meta_back_conndn_dup
121  *
122  * returns -1 in case a duplicate struct metaconn has been inserted;
123  * used by avl stuff
124  */
125 int
126 meta_back_conndn_dup(
127 	void *c1,
128 	void *c2 )
129 {
130 	metaconn_t	*mc1 = ( metaconn_t * )c1;
131 	metaconn_t	*mc2 = ( metaconn_t * )c2;
132 
133 	/* Cannot have more than one shared session with same DN */
134 	if ( mc1->mc_conn == mc2->mc_conn &&
135 		dn_match( &mc1->mc_local_ndn, &mc2->mc_local_ndn ) )
136 	{
137 		return -1;
138 	}
139 
140 	return 0;
141 }
142 
143 /*
144  * Debug stuff (got it from libavl)
145  */
146 #if META_BACK_PRINT_CONNTREE > 0
147 static void
148 meta_back_print( metaconn_t *mc, char *avlstr )
149 {
150 	int	i;
151 
152 	fputs( "targets=[", stderr );
153 	for ( i = 0; i < mc->mc_info->mi_ntargets; i++ ) {
154 		fputc( mc->mc_conns[ i ].msc_ld ? '*' : 'o', stderr);
155 	}
156 	fputc( ']', stderr );
157 
158 	fprintf( stderr, " mc=%p local=\"%s\" conn=%p refcnt=%d%s %s\n",
159 		(void *)mc,
160 		mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "",
161 		(void *)mc->mc_conn,
162 		mc->mc_refcnt,
163 		LDAP_BACK_CONN_TAINTED( mc ) ? " tainted" : "",
164 		avlstr );
165 }
166 
167 static void
168 meta_back_ravl_print( Avlnode *root, int depth )
169 {
170 	int     	i;
171 
172 	if ( root == 0 ) {
173 		return;
174 	}
175 
176 	meta_back_ravl_print( root->avl_right, depth + 1 );
177 
178 	for ( i = 0; i < depth; i++ ) {
179 		fprintf( stderr, "-" );
180 	}
181 	fputc( ' ', stderr );
182 
183 	meta_back_print( (metaconn_t *)root->avl_data,
184 		avl_bf2str( root->avl_bf ) );
185 
186 	meta_back_ravl_print( root->avl_left, depth + 1 );
187 }
188 
189 /* NOTE: duplicate from back-ldap/bind.c */
190 static char* priv2str[] = {
191 	"privileged",
192 	"privileged/TLS",
193 	"anonymous",
194 	"anonymous/TLS",
195 	"bind",
196 	"bind/TLS",
197 	NULL
198 };
199 
200 void
201 meta_back_print_conntree( metainfo_t *mi, char *msg )
202 {
203 	int	c;
204 
205 	fprintf( stderr, "========> %s\n", msg );
206 
207 	for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
208 		int		i = 0;
209 		metaconn_t	*mc;
210 
211 		fprintf( stderr, "  %s[%d]\n", priv2str[ c ], mi->mi_conn_priv[ c ].mic_num );
212 
213 		LDAP_TAILQ_FOREACH( mc, &mi->mi_conn_priv[ c ].mic_priv, mc_q )
214 		{
215 			fprintf( stderr, "    [%d] ", i );
216 			meta_back_print( mc, "" );
217 			i++;
218 		}
219 	}
220 
221 	if ( mi->mi_conninfo.lai_tree == NULL ) {
222 		fprintf( stderr, "\t(empty)\n" );
223 
224 	} else {
225 		meta_back_ravl_print( mi->mi_conninfo.lai_tree, 0 );
226 	}
227 
228 	fprintf( stderr, "<======== %s\n", msg );
229 }
230 #endif /* META_BACK_PRINT_CONNTREE */
231 /*
232  * End of debug stuff
233  */
234 
235 /*
236  * metaconn_alloc
237  *
238  * Allocates a connection structure, making room for all the referenced targets
239  */
240 static metaconn_t *
241 metaconn_alloc(
242        	Operation 		*op )
243 {
244 	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
245 	metaconn_t	*mc;
246 	int		ntargets = mi->mi_ntargets;
247 
248 	assert( ntargets > 0 );
249 
250 	/* malloc all in one */
251 	mc = ( metaconn_t * )ch_calloc( 1, sizeof( metaconn_t )
252 		+ sizeof( metasingleconn_t ) * ( ntargets - 1 ) );
253 	if ( mc == NULL ) {
254 		return NULL;
255 	}
256 
257 	mc->mc_info = mi;
258 
259 	mc->mc_authz_target = META_BOUND_NONE;
260 	mc->mc_refcnt = 1;
261 
262 	return mc;
263 }
264 
265 /*
266  * meta_back_init_one_conn
267  *
268  * Initializes one connection
269  */
270 int
271 meta_back_init_one_conn(
272 	Operation		*op,
273 	SlapReply		*rs,
274 	metaconn_t		*mc,
275 	int			candidate,
276 	int			ispriv,
277 	ldap_back_send_t	sendok,
278 	int			dolock )
279 {
280 	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
281 	metatarget_t		*mt = mi->mi_targets[ candidate ];
282 	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
283 	int			version;
284 	dncookie		dc;
285 	int			isauthz = ( candidate == mc->mc_authz_target );
286 	int			do_return = 0;
287 #ifdef HAVE_TLS
288 	int			is_ldaps = 0;
289 	int			do_start_tls = 0;
290 #endif /* HAVE_TLS */
291 
292 	/* if the server is quarantined, and
293 	 * - the current interval did not expire yet, or
294 	 * - no more retries should occur,
295 	 * don't return the connection */
296 	if ( mt->mt_isquarantined ) {
297 		slap_retry_info_t	*ri = &mt->mt_quarantine;
298 		int			dont_retry = 0;
299 
300 		if ( mt->mt_quarantine.ri_interval ) {
301 			ldap_pvt_thread_mutex_lock( &mt->mt_quarantine_mutex );
302 			dont_retry = ( mt->mt_isquarantined > LDAP_BACK_FQ_NO );
303 			if ( dont_retry ) {
304 				dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
305 					|| slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
306 				if ( !dont_retry ) {
307 					if ( LogTest( LDAP_DEBUG_ANY ) ) {
308 						char	buf[ SLAP_TEXT_BUFLEN ];
309 
310 						snprintf( buf, sizeof( buf ),
311 							"meta_back_init_one_conn[%d]: quarantine "
312 							"retry block #%d try #%d",
313 							candidate, ri->ri_idx, ri->ri_count );
314 						Debug( LDAP_DEBUG_ANY, "%s %s.\n",
315 							op->o_log_prefix, buf, 0 );
316 					}
317 
318 					mt->mt_isquarantined = LDAP_BACK_FQ_RETRYING;
319 				}
320 
321 			}
322 			ldap_pvt_thread_mutex_unlock( &mt->mt_quarantine_mutex );
323 		}
324 
325 		if ( dont_retry ) {
326 			rs->sr_err = LDAP_UNAVAILABLE;
327 			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
328 				rs->sr_text = "Target is quarantined";
329 				send_ldap_result( op, rs );
330 			}
331 			return rs->sr_err;
332 		}
333 	}
334 
335 retry_lock:;
336 	if ( dolock ) {
337 		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
338 	}
339 
340 	/*
341 	 * Already init'ed
342 	 */
343 	if ( LDAP_BACK_CONN_ISBOUND( msc )
344 		|| LDAP_BACK_CONN_ISANON( msc ) )
345 	{
346 		assert( msc->msc_ld != NULL );
347 		rs->sr_err = LDAP_SUCCESS;
348 		do_return = 1;
349 
350 	} else if ( META_BACK_CONN_CREATING( msc )
351 		|| LDAP_BACK_CONN_BINDING( msc ) )
352 	{
353 		if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
354 			if ( dolock ) {
355 				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
356 			}
357 
358 			ldap_pvt_thread_yield();
359 			goto retry_lock;
360 		}
361 
362 		/* sounds more appropriate */
363 		rs->sr_err = LDAP_BUSY;
364 		rs->sr_text = "No connections to target are available";
365 		do_return = 1;
366 
367 	} else if ( META_BACK_CONN_INITED( msc ) ) {
368 		assert( msc->msc_ld != NULL );
369 		rs->sr_err = LDAP_SUCCESS;
370 		do_return = 1;
371 
372 	} else {
373 		/*
374 		 * creating...
375 		 */
376 		META_BACK_CONN_CREATING_SET( msc );
377 	}
378 
379 	if ( dolock ) {
380 		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
381 	}
382 
383 	if ( do_return ) {
384 		if ( rs->sr_err != LDAP_SUCCESS
385 			&& op->o_conn
386 			&& ( sendok & LDAP_BACK_SENDERR ) )
387 		{
388 			send_ldap_result( op, rs );
389 		}
390 
391 		return rs->sr_err;
392 	}
393 
394 	assert( msc->msc_ld == NULL );
395 
396 	/*
397 	 * Attempts to initialize the connection to the target ds
398 	 */
399 	ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
400 	rs->sr_err = ldap_initialize( &msc->msc_ld, mt->mt_uri );
401 #ifdef HAVE_TLS
402 	is_ldaps = ldap_is_ldaps_url( mt->mt_uri );
403 #endif /* HAVE_TLS */
404 	ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
405 	if ( rs->sr_err != LDAP_SUCCESS ) {
406 		goto error_return;
407 	}
408 
409 	/*
410 	 * Set LDAP version. This will always succeed: If the client
411 	 * bound with a particular version, then so can we.
412 	 */
413 	if ( mt->mt_version != 0 ) {
414 		version = mt->mt_version;
415 
416 	} else if ( op->o_conn->c_protocol != 0 ) {
417 		version = op->o_conn->c_protocol;
418 
419 	} else {
420 		version = LDAP_VERSION3;
421 	}
422 	ldap_set_option( msc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &version );
423 	ldap_set_urllist_proc( msc->msc_ld, mt->mt_urllist_f, mt->mt_urllist_p );
424 
425 	/* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
426 	ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS,
427 		META_BACK_TGT_CHASE_REFERRALS( mt ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
428 
429 	slap_client_keepalive(msc->msc_ld, &mt->mt_tls.sb_keepalive);
430 
431 #ifdef HAVE_TLS
432 	{
433 		slap_bindconf *sb = NULL;
434 
435 		if ( ispriv ) {
436 			sb = &mt->mt_idassert.si_bc;
437 		} else {
438 			sb = &mt->mt_tls;
439 		}
440 
441 		if ( sb->sb_tls_do_init ) {
442 			bindconf_tls_set( sb, msc->msc_ld );
443 		} else if ( sb->sb_tls_ctx ) {
444 			ldap_set_option( msc->msc_ld, LDAP_OPT_X_TLS_CTX, sb->sb_tls_ctx );
445 		}
446 
447 		if ( !is_ldaps ) {
448 			if ( sb == &mt->mt_idassert.si_bc && sb->sb_tls_ctx ) {
449 				do_start_tls = 1;
450 
451 			} else if ( META_BACK_TGT_USE_TLS( mt )
452 				|| ( op->o_conn->c_is_tls && META_BACK_TGT_PROPAGATE_TLS( mt ) ) )
453 			{
454 				do_start_tls = 1;
455 			}
456 		}
457 	}
458 
459 	/* start TLS ("tls [try-]{start|propagate}" statement) */
460 	if ( do_start_tls ) {
461 #ifdef SLAP_STARTTLS_ASYNCHRONOUS
462 		/*
463 		 * use asynchronous StartTLS; in case, chase referral
464 		 * FIXME: OpenLDAP does not return referral on StartTLS yet
465 		 */
466 		int		msgid;
467 
468 		rs->sr_err = ldap_start_tls( msc->msc_ld, NULL, NULL, &msgid );
469 		if ( rs->sr_err == LDAP_SUCCESS ) {
470 			LDAPMessage	*res = NULL;
471 			int		rc, nretries = mt->mt_nretries;
472 			struct timeval	tv;
473 
474 			LDAP_BACK_TV_SET( &tv );
475 
476 retry:;
477 			rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
478 			switch ( rc ) {
479 			case -1:
480 				rs->sr_err = LDAP_UNAVAILABLE;
481 				rs->sr_text = "Remote server down";
482 				break;
483 
484 			case 0:
485 				if ( nretries != 0 ) {
486 					if ( nretries > 0 ) {
487 						nretries--;
488 					}
489 					LDAP_BACK_TV_SET( &tv );
490 					goto retry;
491 				}
492 				rs->sr_err = LDAP_OTHER;
493 				rs->sr_text = "Timeout, no more retries";
494 				break;
495 
496 			default:
497 				/* only touch when activity actually took place... */
498 				if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
499 					msc->msc_time = op->o_time;
500 				}
501 				break;
502 			}
503 
504 			if ( rc == LDAP_RES_EXTENDED ) {
505 				struct berval	*data = NULL;
506 
507 				/* NOTE: right now, data is unused, so don't get it */
508 				rs->sr_err = ldap_parse_extended_result( msc->msc_ld,
509 					res, NULL, NULL /* &data */ , 0 );
510 				if ( rs->sr_err == LDAP_SUCCESS ) {
511 					int		err;
512 
513 					/* FIXME: matched? referrals? response controls? */
514 					rs->sr_err = ldap_parse_result( msc->msc_ld,
515 						res, &err, NULL, NULL, NULL, NULL, 1 );
516 					res = NULL;
517 
518 					if ( rs->sr_err == LDAP_SUCCESS ) {
519 						rs->sr_err = err;
520 					}
521 					rs->sr_err = slap_map_api2result( rs );
522 
523 					/* FIXME: in case a referral
524 					 * is returned, should we try
525 					 * using it instead of the
526 					 * configured URI? */
527 					if ( rs->sr_err == LDAP_SUCCESS ) {
528 						ldap_install_tls( msc->msc_ld );
529 
530 					} else if ( rs->sr_err == LDAP_REFERRAL ) {
531 						/* FIXME: LDAP_OPERATIONS_ERROR? */
532 						rs->sr_err = LDAP_OTHER;
533 						rs->sr_text = "Unwilling to chase referral "
534 							"returned by Start TLS exop";
535 					}
536 
537 					if ( data ) {
538 						ber_bvfree( data );
539 					}
540 				}
541 
542 			} else {
543 				rs->sr_err = LDAP_OTHER;
544 				rs->sr_text = "Unknown response to StartTLS request :"
545 					" an ExtendedResponse is expected";
546 			}
547 
548 			if ( res != NULL ) {
549 				ldap_msgfree( res );
550 			}
551 		}
552 #else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
553 		/*
554 		 * use synchronous StartTLS
555 		 */
556 		rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL );
557 #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
558 
559 		/* if StartTLS is requested, only attempt it if the URL
560 		 * is not "ldaps://"; this may occur not only in case
561 		 * of misconfiguration, but also when used in the chain
562 		 * overlay, where the "uri" can be parsed out of a referral */
563 		if ( rs->sr_err == LDAP_SERVER_DOWN
564 			|| ( rs->sr_err != LDAP_SUCCESS
565 				&& META_BACK_TGT_TLS_CRITICAL( mt ) ) )
566 		{
567 
568 #ifdef DEBUG_205
569 			Debug( LDAP_DEBUG_ANY,
570 				"### %s meta_back_init_one_conn(TLS) "
571 				"ldap_unbind_ext[%d] ld=%p\n",
572 				op->o_log_prefix, candidate,
573 				(void *)msc->msc_ld );
574 #endif /* DEBUG_205 */
575 
576 			/* need to trash a failed Start TLS */
577 			meta_clear_one_candidate( op, mc, candidate );
578 			goto error_return;
579 		}
580 	}
581 #endif /* HAVE_TLS */
582 
583 	/*
584 	 * Set the network timeout if set
585 	 */
586 	if ( mt->mt_network_timeout != 0 ) {
587 		struct timeval	network_timeout;
588 
589 		network_timeout.tv_usec = 0;
590 		network_timeout.tv_sec = mt->mt_network_timeout;
591 
592 		ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT,
593 				(void *)&network_timeout );
594 	}
595 
596 	/*
597 	 * If the connection DN is not null, an attempt to rewrite it is made
598 	 */
599 
600 	if ( ispriv ) {
601 		if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) ) {
602 			ber_bvreplace( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN );
603 			if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) {
604 				if ( !BER_BVISNULL( &msc->msc_cred ) ) {
605 					memset( msc->msc_cred.bv_val, 0,
606 						msc->msc_cred.bv_len );
607 				}
608 				ber_bvreplace( &msc->msc_cred, &mt->mt_idassert_passwd );
609 			}
610 			LDAP_BACK_CONN_ISIDASSERT_SET( msc );
611 
612 		} else {
613 			ber_bvreplace( &msc->msc_bound_ndn, &slap_empty_bv );
614 		}
615 
616 	} else {
617 		if ( !BER_BVISNULL( &msc->msc_cred ) ) {
618 			memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
619 			ber_memfree_x( msc->msc_cred.bv_val, NULL );
620 			BER_BVZERO( &msc->msc_cred );
621 		}
622 		if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
623 			ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL );
624 			BER_BVZERO( &msc->msc_bound_ndn );
625 		}
626 		if ( !BER_BVISEMPTY( &op->o_ndn )
627 			&& SLAP_IS_AUTHZ_BACKEND( op )
628 			&& isauthz )
629 		{
630 			dc.target = mt;
631 			dc.conn = op->o_conn;
632 			dc.rs = rs;
633 			dc.ctx = "bindDN";
634 
635 			/*
636 			 * Rewrite the bind dn if needed
637 			 */
638 			if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn,
639 						&msc->msc_bound_ndn ) )
640 			{
641 
642 #ifdef DEBUG_205
643 				Debug( LDAP_DEBUG_ANY,
644 					"### %s meta_back_init_one_conn(rewrite) "
645 					"ldap_unbind_ext[%d] ld=%p\n",
646 					op->o_log_prefix, candidate,
647 					(void *)msc->msc_ld );
648 #endif /* DEBUG_205 */
649 
650 				/* need to trash a connection not fully established */
651 				meta_clear_one_candidate( op, mc, candidate );
652 				goto error_return;
653 			}
654 
655 			/* copy the DN if needed */
656 			if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) {
657 				ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn );
658 			}
659 
660 			assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
661 
662 		} else {
663 			ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv );
664 		}
665 	}
666 
667 	assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
668 
669 error_return:;
670 	if ( dolock ) {
671 		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
672 	}
673 	META_BACK_CONN_CREATING_CLEAR( msc );
674 	if ( rs->sr_err == LDAP_SUCCESS ) {
675 		/*
676 		 * Sets a cookie for the rewrite session
677 		 */
678 		( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn );
679 		META_BACK_CONN_INITED_SET( msc );
680 	}
681 	if ( dolock ) {
682 		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
683 	}
684 
685 	if ( rs->sr_err != LDAP_SUCCESS ) {
686 		/* Get the error message and print it in TRACE mode */
687 		if ( LogTest( LDAP_DEBUG_TRACE ) ) {
688 			Log4( LDAP_DEBUG_TRACE, ldap_syslog_level, "%s: meta_back_init_one_conn[%d] failed err=%d text=%s\n",
689 				op->o_log_prefix, candidate, rs->sr_err, rs->sr_text );
690 		}
691 
692 		rs->sr_err = slap_map_api2result( rs );
693 		if ( sendok & LDAP_BACK_SENDERR ) {
694 			send_ldap_result( op, rs );
695 		}
696 	}
697 
698 	return rs->sr_err;
699 }
700 
701 /*
702  * meta_back_retry
703  *
704  * Retries one connection
705  */
706 int
707 meta_back_retry(
708 	Operation		*op,
709 	SlapReply		*rs,
710 	metaconn_t		**mcp,
711 	int			candidate,
712 	ldap_back_send_t	sendok )
713 {
714 	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
715 	metatarget_t		*mt = mi->mi_targets[ candidate ];
716 	metaconn_t		*mc = *mcp;
717 	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
718 	int			rc = LDAP_UNAVAILABLE,
719 				binding,
720 				quarantine = 1;
721 
722 	ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
723 
724 	assert( !META_BACK_CONN_CREATING( msc ) );
725 	binding = LDAP_BACK_CONN_BINDING( msc );
726 	LDAP_BACK_CONN_BINDING_CLEAR( msc );
727 
728 	assert( mc->mc_refcnt > 0 );
729 	if ( mc->mc_refcnt == 1 ) {
730 		struct berval save_cred;
731 
732 		if ( LogTest( LDAP_DEBUG_ANY ) ) {
733 			char	buf[ SLAP_TEXT_BUFLEN ];
734 
735 			/* this lock is required; however,
736 			 * it's invoked only when logging is on */
737 			ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
738 			snprintf( buf, sizeof( buf ),
739 				"retrying URI=\"%s\" DN=\"%s\"",
740 				mt->mt_uri,
741 				BER_BVISNULL( &msc->msc_bound_ndn ) ?
742 					"" : msc->msc_bound_ndn.bv_val );
743 			ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
744 
745 			Debug( LDAP_DEBUG_ANY,
746 				"%s meta_back_retry[%d]: %s.\n",
747 				op->o_log_prefix, candidate, buf );
748 		}
749 
750 		/* save credentials, if any, for later use;
751 		 * meta_clear_one_candidate() would free them */
752 		save_cred = msc->msc_cred;
753 		BER_BVZERO( &msc->msc_cred );
754 
755 		meta_clear_one_candidate( op, mc, candidate );
756 		LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
757 
758 		( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
759 
760 		/* mc here must be the regular mc, reset and ready for init */
761 		rc = meta_back_init_one_conn( op, rs, mc, candidate,
762 			LDAP_BACK_CONN_ISPRIV( mc ), sendok, 0 );
763 
764 		/* restore credentials, if any and if needed;
765 		 * meta_back_init_one_conn() restores msc_bound_ndn, if any;
766 		 * if no msc_bound_ndn is restored, destroy credentials */
767 		if ( !BER_BVISNULL( &msc->msc_bound_ndn )
768 			&& BER_BVISNULL( &msc->msc_cred ) )
769 		{
770 			msc->msc_cred = save_cred;
771 
772 		} else if ( !BER_BVISNULL( &save_cred ) ) {
773 			memset( save_cred.bv_val, 0, save_cred.bv_len );
774 			ber_memfree_x( save_cred.bv_val, NULL );
775 		}
776 
777 		/* restore the "binding" flag, in case */
778 		if ( binding ) {
779 			LDAP_BACK_CONN_BINDING_SET( msc );
780 		}
781 
782 		if ( rc == LDAP_SUCCESS ) {
783 			quarantine = 0;
784 			LDAP_BACK_CONN_BINDING_SET( msc ); binding = 1;
785 			rc = meta_back_single_dobind( op, rs, mcp, candidate,
786 				sendok, mt->mt_nretries, 0 );
787 
788 			Debug( LDAP_DEBUG_ANY,
789 				"%s meta_back_retry[%d]: "
790 				"meta_back_single_dobind=%d\n",
791 				op->o_log_prefix, candidate, rc );
792 			if ( rc == LDAP_SUCCESS ) {
793 				if ( !BER_BVISNULL( &msc->msc_bound_ndn ) &&
794 					!BER_BVISEMPTY( &msc->msc_bound_ndn ) )
795 				{
796 					LDAP_BACK_CONN_ISBOUND_SET( msc );
797 
798 				} else {
799 					LDAP_BACK_CONN_ISANON_SET( msc );
800 				}
801 
802 				/* when bound, dispose of the "binding" flag */
803 				if ( binding ) {
804 					LDAP_BACK_CONN_BINDING_CLEAR( msc );
805 				}
806 			}
807 		}
808 
809 #if 0	/* ITS#7591, following stmt drops needed result msgs */
810 		/* don't send twice */
811 		sendok &= ~LDAP_BACK_SENDERR;
812 #endif
813 	}
814 
815 	if ( rc != LDAP_SUCCESS ) {
816 		SlapReply		*candidates = meta_back_candidates_get( op );
817 
818 		candidates[ candidate ].sr_err = rc;
819 
820 		if ( *mcp != NULL ) {
821 			if ( mc->mc_refcnt == 1 ) {
822 				if ( binding ) {
823 					LDAP_BACK_CONN_BINDING_CLEAR( msc );
824 				}
825 				(void)meta_clear_one_candidate( op, mc, candidate );
826 			}
827 
828 			LDAP_BACK_CONN_TAINTED_SET( mc );
829 			/* only release if mandatory; otherwise
830 			 * let the caller do what's best before
831 			 * releasing */
832 			if ( META_BACK_ONERR_STOP( mi ) ) {
833 				meta_back_release_conn_lock( mi, mc, 0 );
834 				*mcp = NULL;
835 
836 			} else {
837 #if META_BACK_PRINT_CONNTREE > 0
838 				meta_back_print_conntree( mi, ">>> meta_back_retry" );
839 #endif /* META_BACK_PRINT_CONNTREE */
840 
841 				/* FIXME: could be done better, reworking meta_back_release_conn_lock() */
842 				if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
843 					if ( mc->mc_q.tqe_prev != NULL ) {
844 						assert( LDAP_BACK_CONN_CACHED( mc ) );
845 						assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 );
846 						LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
847 							mc, mc_q );
848 						mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--;
849 						LDAP_TAILQ_ENTRY_INIT( mc, mc_q );
850 
851 					} else {
852 						assert( !LDAP_BACK_CONN_CACHED( mc ) );
853 					}
854 
855 				} else {
856 					/* FIXME: check if in tree, for consistency? */
857 					(void)avl_delete( &mi->mi_conninfo.lai_tree,
858 						( caddr_t )mc, meta_back_conndnmc_cmp );
859 				}
860 				LDAP_BACK_CONN_CACHED_CLEAR( mc );
861 
862 #if META_BACK_PRINT_CONNTREE > 0
863 				meta_back_print_conntree( mi, "<<< meta_back_retry" );
864 #endif /* META_BACK_PRINT_CONNTREE */
865 			}
866 		}
867 
868 		if ( sendok & LDAP_BACK_SENDERR ) {
869 			rs->sr_err = rc;
870 			rs->sr_text = "Unable to retry";
871 			send_ldap_result( op, rs );
872 		}
873 	}
874 
875 	if ( quarantine && META_BACK_TGT_QUARANTINE( mt ) ) {
876 		meta_back_quarantine( op, rs, candidate );
877 	}
878 
879 	ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
880 
881 	return rc == LDAP_SUCCESS ? 1 : 0;
882 }
883 
884 /*
885  * callback for unique candidate selection
886  */
887 static int
888 meta_back_conn_cb( Operation *op, SlapReply *rs )
889 {
890 	assert( op->o_tag == LDAP_REQ_SEARCH );
891 
892 	switch ( rs->sr_type ) {
893 	case REP_SEARCH:
894 		((long *)op->o_callback->sc_private)[0] = (long)op->o_private;
895 		break;
896 
897 	case REP_SEARCHREF:
898 	case REP_RESULT:
899 		break;
900 
901 	default:
902 		return rs->sr_err;
903 	}
904 
905 	return 0;
906 }
907 
908 
909 static int
910 meta_back_get_candidate(
911 	Operation	*op,
912 	SlapReply	*rs,
913 	struct berval	*ndn )
914 {
915 	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
916 	long		candidate;
917 
918 	/*
919 	 * tries to get a unique candidate
920 	 * (takes care of default target)
921 	 */
922 	candidate = meta_back_select_unique_candidate( mi, ndn );
923 
924 	/*
925 	 * if any is found, inits the connection
926 	 */
927 	if ( candidate == META_TARGET_NONE ) {
928 		rs->sr_err = LDAP_NO_SUCH_OBJECT;
929 		rs->sr_text = "No suitable candidate target found";
930 
931 	} else if ( candidate == META_TARGET_MULTIPLE ) {
932 		Operation	op2 = *op;
933 		SlapReply	rs2 = { REP_RESULT };
934 		slap_callback	cb2 = { 0 };
935 		int		rc;
936 
937 		/* try to get a unique match for the request ndn
938 		 * among the multiple candidates available */
939 		op2.o_tag = LDAP_REQ_SEARCH;
940 		op2.o_req_dn = *ndn;
941 		op2.o_req_ndn = *ndn;
942 		op2.ors_scope = LDAP_SCOPE_BASE;
943 		op2.ors_deref = LDAP_DEREF_NEVER;
944 		op2.ors_attrs = slap_anlist_no_attrs;
945 		op2.ors_attrsonly = 0;
946 		op2.ors_limit = NULL;
947 		op2.ors_slimit = 1;
948 		op2.ors_tlimit = SLAP_NO_LIMIT;
949 
950 		op2.ors_filter = (Filter *)slap_filter_objectClass_pres;
951 		op2.ors_filterstr = *slap_filterstr_objectClass_pres;
952 
953 		op2.o_callback = &cb2;
954 		cb2.sc_response = meta_back_conn_cb;
955 		cb2.sc_private = (void *)&candidate;
956 
957 		rc = op->o_bd->be_search( &op2, &rs2 );
958 
959 		switch ( rs2.sr_err ) {
960 		case LDAP_SUCCESS:
961 		default:
962 			rs->sr_err = rs2.sr_err;
963 			break;
964 
965 		case LDAP_SIZELIMIT_EXCEEDED:
966 			/* if multiple candidates can serve the operation,
967 			 * and a default target is defined, and it is
968 			 * a candidate, try using it (FIXME: YMMV) */
969 			if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE
970 				&& meta_back_is_candidate( mi->mi_targets[ mi->mi_defaulttarget ],
971 						ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) )
972 			{
973 				candidate = mi->mi_defaulttarget;
974 				rs->sr_err = LDAP_SUCCESS;
975 				rs->sr_text = NULL;
976 
977 			} else {
978 				rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
979 				rs->sr_text = "Unable to select unique candidate target";
980 			}
981 			break;
982 		}
983 
984 	} else {
985 		rs->sr_err = LDAP_SUCCESS;
986 	}
987 
988 	return candidate;
989 }
990 
991 static void	*meta_back_candidates_dummy;
992 
993 static void
994 meta_back_candidates_keyfree(
995 	void		*key,
996 	void		*data )
997 {
998 	metacandidates_t	*mc = (metacandidates_t *)data;
999 
1000 	ber_memfree_x( mc->mc_candidates, NULL );
1001 	ber_memfree_x( data, NULL );
1002 }
1003 
1004 SlapReply *
1005 meta_back_candidates_get( Operation *op )
1006 {
1007 	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
1008 	metacandidates_t	*mc;
1009 
1010 	if ( op->o_threadctx ) {
1011 		void		*data = NULL;
1012 
1013 		ldap_pvt_thread_pool_getkey( op->o_threadctx,
1014 				&meta_back_candidates_dummy, &data, NULL );
1015 		mc = (metacandidates_t *)data;
1016 
1017 	} else {
1018 		mc = mi->mi_candidates;
1019 	}
1020 
1021 	if ( mc == NULL ) {
1022 		mc = ch_calloc( sizeof( metacandidates_t ), 1 );
1023 		mc->mc_ntargets = mi->mi_ntargets;
1024 		mc->mc_candidates = ch_calloc( sizeof( SlapReply ), mc->mc_ntargets );
1025 		if ( op->o_threadctx ) {
1026 			void		*data = NULL;
1027 
1028 			data = (void *)mc;
1029 			ldap_pvt_thread_pool_setkey( op->o_threadctx,
1030 					&meta_back_candidates_dummy, data,
1031 					meta_back_candidates_keyfree,
1032 					NULL, NULL );
1033 
1034 		} else {
1035 			mi->mi_candidates = mc;
1036 		}
1037 
1038 	} else if ( mc->mc_ntargets < mi->mi_ntargets ) {
1039 		/* NOTE: in the future, may want to allow back-config
1040 		 * to add/remove targets from back-meta... */
1041 		mc->mc_candidates = ch_realloc( mc->mc_candidates,
1042 				sizeof( SlapReply ) * mi->mi_ntargets );
1043 		memset( &mc->mc_candidates[ mc->mc_ntargets ], 0,
1044 			sizeof( SlapReply ) * ( mi->mi_ntargets - mc->mc_ntargets ) );
1045 		mc->mc_ntargets = mi->mi_ntargets;
1046 	}
1047 
1048 	return mc->mc_candidates;
1049 }
1050 
1051 /*
1052  * meta_back_getconn
1053  *
1054  * Prepares the connection structure
1055  *
1056  * RATIONALE:
1057  *
1058  * - determine what DN is being requested:
1059  *
1060  *	op	requires candidate	checks
1061  *
1062  *	add	unique			parent of o_req_ndn
1063  *	bind	unique^*[/all]		o_req_ndn [no check]
1064  *	compare	unique^+		o_req_ndn
1065  *	delete	unique			o_req_ndn
1066  *	modify	unique			o_req_ndn
1067  *	search	any			o_req_ndn
1068  *	modrdn	unique[, unique]	o_req_ndn[, orr_nnewSup]
1069  *
1070  * - for ops that require the candidate to be unique, in case of multiple
1071  *   occurrences an internal search with sizeLimit=1 is performed
1072  *   if a unique candidate can actually be determined.  If none is found,
1073  *   the operation aborts; if multiple are found, the default target
1074  *   is used if defined and candidate; otherwise the operation aborts.
1075  *
1076  * *^note: actually, the bind operation is handled much like a search;
1077  *   i.e. the bind is broadcast to all candidate targets.
1078  *
1079  * +^note: actually, the compare operation is handled much like a search;
1080  *   i.e. the compare is broadcast to all candidate targets, while checking
1081  *   that exactly none (noSuchObject) or one (TRUE/FALSE/UNDEFINED) is
1082  *   returned.
1083  */
1084 metaconn_t *
1085 meta_back_getconn(
1086        	Operation 		*op,
1087 	SlapReply		*rs,
1088 	int 			*candidate,
1089 	ldap_back_send_t	sendok )
1090 {
1091 	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
1092 	metaconn_t	*mc = NULL,
1093 			mc_curr = {{ 0 }};
1094 	int		cached = META_TARGET_NONE,
1095 			i = META_TARGET_NONE,
1096 			err = LDAP_SUCCESS,
1097 			new_conn = 0,
1098 			ncandidates = 0;
1099 
1100 
1101 	meta_op_type	op_type = META_OP_REQUIRE_SINGLE;
1102 	enum		{
1103 		META_DNTYPE_ENTRY,
1104 		META_DNTYPE_PARENT,
1105 		META_DNTYPE_NEWPARENT
1106 	}		dn_type = META_DNTYPE_ENTRY;
1107 	struct berval	ndn = op->o_req_ndn,
1108 			pndn;
1109 
1110 	SlapReply	*candidates = meta_back_candidates_get( op );
1111 
1112 	/* Internal searches are privileged and shared. So is root. */
1113 	if ( ( !BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_ALWAYS( mi ) )
1114 		|| ( BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_ANON( mi ) )
1115 		|| op->o_do_not_cache || be_isroot( op ) )
1116 	{
1117 		LDAP_BACK_CONN_ISPRIV_SET( &mc_curr );
1118 		mc_curr.mc_local_ndn = op->o_bd->be_rootndn;
1119 		LDAP_BACK_PCONN_ROOTDN_SET( &mc_curr, op );
1120 
1121 	} else if ( BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_NOANON( mi ) )
1122 	{
1123 		LDAP_BACK_CONN_ISANON_SET( &mc_curr );
1124 		BER_BVSTR( &mc_curr.mc_local_ndn, "" );
1125 		LDAP_BACK_PCONN_ANON_SET( &mc_curr, op );
1126 
1127 	} else {
1128 		mc_curr.mc_local_ndn = op->o_ndn;
1129 
1130 		/* Explicit binds must not be shared */
1131 		if ( !BER_BVISEMPTY( &op->o_ndn )
1132 			|| op->o_tag == LDAP_REQ_BIND
1133 			|| SLAP_IS_AUTHZ_BACKEND( op ) )
1134 		{
1135 			mc_curr.mc_conn = op->o_conn;
1136 
1137 		} else {
1138 			LDAP_BACK_CONN_ISANON_SET( &mc_curr );
1139 			LDAP_BACK_PCONN_ANON_SET( &mc_curr, op );
1140 		}
1141 	}
1142 
1143 	/* Explicit Bind requests always get their own conn */
1144 	if ( sendok & LDAP_BACK_BINDING ) {
1145 		mc_curr.mc_conn = op->o_conn;
1146 
1147 	} else {
1148 		/* Searches for a metaconn in the avl tree */
1149 retry_lock:;
1150 		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1151 		if ( LDAP_BACK_PCONN_ISPRIV( &mc_curr ) ) {
1152 			/* lookup a conn that's not binding */
1153 			LDAP_TAILQ_FOREACH( mc,
1154 				&mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv,
1155 				mc_q )
1156 			{
1157 				if ( !LDAP_BACK_CONN_BINDING( mc ) && mc->mc_refcnt == 0 ) {
1158 					break;
1159 				}
1160 			}
1161 
1162 			if ( mc != NULL ) {
1163 				/* move to tail of queue */
1164 				if ( mc != LDAP_TAILQ_LAST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
1165 					mc_conn_priv_q ) )
1166 				{
1167 					LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
1168 						mc, mc_q );
1169 					LDAP_TAILQ_ENTRY_INIT( mc, mc_q );
1170 					LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
1171 						mc, mc_q );
1172 				}
1173 
1174 			} else if ( !LDAP_BACK_USE_TEMPORARIES( mi )
1175 				&& mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_num == mi->mi_conn_priv_max )
1176 			{
1177 				mc = LDAP_TAILQ_FIRST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv );
1178 			}
1179 
1180 
1181 		} else {
1182 			mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree,
1183 				(caddr_t)&mc_curr, meta_back_conndn_cmp );
1184 		}
1185 
1186 		if ( mc ) {
1187 			/* catch taint errors */
1188 			assert( !LDAP_BACK_CONN_TAINTED( mc ) );
1189 
1190 			/* Don't reuse connections while they're still binding
1191 			 * NOTE: only makes sense for binds */
1192 			if ( LDAP_BACK_CONN_BINDING( mc ) ) {
1193 				if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
1194 					ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1195 
1196 					ldap_pvt_thread_yield();
1197 					goto retry_lock;
1198 				}
1199 
1200 				/* release conn, and create a temporary */
1201 				mc = NULL;
1202 
1203 			} else {
1204 				if ( mc->mc_refcnt == 0 && (( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )
1205 					|| ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout )) )
1206 				{
1207 #if META_BACK_PRINT_CONNTREE > 0
1208 					meta_back_print_conntree( mi,
1209 						">>> meta_back_getconn(expired)" );
1210 #endif /* META_BACK_PRINT_CONNTREE */
1211 
1212 					/* don't let anyone else use this expired connection */
1213 					if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
1214 						if ( mc->mc_q.tqe_prev != NULL ) {
1215 							assert( LDAP_BACK_CONN_CACHED( mc ) );
1216 							assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 );
1217 							LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
1218 								mc, mc_q );
1219 							mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--;
1220 							LDAP_TAILQ_ENTRY_INIT( mc, mc_q );
1221 
1222 						} else {
1223 							assert( !LDAP_BACK_CONN_CACHED( mc ) );
1224 						}
1225 
1226 					} else {
1227 						(void)avl_delete( &mi->mi_conninfo.lai_tree,
1228 							(caddr_t)mc, meta_back_conndnmc_cmp );
1229 					}
1230 
1231 #if META_BACK_PRINT_CONNTREE > 0
1232 					meta_back_print_conntree( mi,
1233 						"<<< meta_back_getconn(expired)" );
1234 #endif /* META_BACK_PRINT_CONNTREE */
1235 					LDAP_BACK_CONN_TAINTED_SET( mc );
1236 					LDAP_BACK_CONN_CACHED_CLEAR( mc );
1237 
1238 					if ( LogTest( LDAP_DEBUG_TRACE ) ) {
1239 						char buf[STRLENOF("4294967295U") + 1] = { 0 };
1240 						mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
1241 
1242 						Debug( LDAP_DEBUG_TRACE,
1243 							"%s meta_back_getconn: mc=%p conn=%s expired (tainted).\n",
1244 							op->o_log_prefix, (void *)mc, buf );
1245 					}
1246 				}
1247 
1248 				mc->mc_refcnt++;
1249 			}
1250 		}
1251 		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1252 	}
1253 
1254 	switch ( op->o_tag ) {
1255 	case LDAP_REQ_ADD:
1256 		/* if we go to selection, the entry must not exist,
1257 		 * and we must be able to resolve the parent */
1258 		dn_type = META_DNTYPE_PARENT;
1259 		dnParent( &ndn, &pndn );
1260 		break;
1261 
1262 	case LDAP_REQ_MODRDN:
1263 		/* if nnewSuperior is not NULL, it must resolve
1264 		 * to the same candidate as the req_ndn */
1265 		if ( op->orr_nnewSup ) {
1266 			dn_type = META_DNTYPE_NEWPARENT;
1267 		}
1268 		break;
1269 
1270 	case LDAP_REQ_BIND:
1271 		/* if bound as rootdn, the backend must bind to all targets
1272 		 * with the administrative identity
1273 		 * (unless pseoudoroot-bind-defer is TRUE) */
1274 		if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) {
1275 			op_type = META_OP_REQUIRE_ALL;
1276 		}
1277 		break;
1278 
1279 	case LDAP_REQ_COMPARE:
1280 	case LDAP_REQ_DELETE:
1281 	case LDAP_REQ_MODIFY:
1282 		/* just a unique candidate */
1283 		break;
1284 
1285 	case LDAP_REQ_SEARCH:
1286 		/* allow multiple candidates for the searchBase */
1287 		op_type = META_OP_ALLOW_MULTIPLE;
1288 		break;
1289 
1290 	default:
1291 		/* right now, just break (exop?) */
1292 		break;
1293 	}
1294 
1295 	/*
1296 	 * require all connections ...
1297 	 */
1298 	if ( op_type == META_OP_REQUIRE_ALL ) {
1299 
1300 		/* Looks like we didn't get a bind. Open a new session... */
1301 		if ( mc == NULL ) {
1302 			assert( new_conn == 0 );
1303 			mc = metaconn_alloc( op );
1304 			mc->mc_conn = mc_curr.mc_conn;
1305 			ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn );
1306 			new_conn = 1;
1307 			if ( sendok & LDAP_BACK_BINDING ) {
1308 				LDAP_BACK_CONN_BINDING_SET( mc );
1309 			}
1310 			if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
1311 				LDAP_BACK_CONN_ISPRIV_SET( mc );
1312 
1313 			} else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) {
1314 				LDAP_BACK_CONN_ISANON_SET( mc );
1315 			}
1316 
1317 		} else if ( 0 ) {
1318 			/* TODO: if any of the connections is binding,
1319 			 * release mc and create a new one */
1320 		}
1321 
1322 		for ( i = 0; i < mi->mi_ntargets; i++ ) {
1323 			/*
1324 			 * The target is activated; if needed, it is
1325 			 * also init'd
1326 			 */
1327 			candidates[ i ].sr_err = meta_back_init_one_conn( op,
1328 				rs, mc, i, LDAP_BACK_CONN_ISPRIV( &mc_curr ),
1329 				LDAP_BACK_DONTSEND, !new_conn );
1330 			if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
1331 				if ( new_conn && ( sendok & LDAP_BACK_BINDING ) ) {
1332 					LDAP_BACK_CONN_BINDING_SET( &mc->mc_conns[ i ] );
1333 				}
1334 				META_CANDIDATE_SET( &candidates[ i ] );
1335 				ncandidates++;
1336 
1337 			} else {
1338 
1339 				/*
1340 				 * FIXME: in case one target cannot
1341 				 * be init'd, should the other ones
1342 				 * be tried?
1343 				 */
1344 				META_CANDIDATE_RESET( &candidates[ i ] );
1345 				err = candidates[ i ].sr_err;
1346 				continue;
1347 			}
1348 		}
1349 
1350 		if ( ncandidates == 0 ) {
1351 			if ( new_conn ) {
1352 				mc->mc_refcnt = 0;
1353 				meta_back_conn_free( mc );
1354 
1355 			} else {
1356 				meta_back_release_conn( mi, mc );
1357 			}
1358 
1359 			rs->sr_err = LDAP_NO_SUCH_OBJECT;
1360 			rs->sr_text = "Unable to select valid candidates";
1361 
1362 			if ( sendok & LDAP_BACK_SENDERR ) {
1363 				if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
1364 					rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val;
1365 				}
1366 				send_ldap_result( op, rs );
1367 				rs->sr_matched = NULL;
1368 			}
1369 
1370 			return NULL;
1371 		}
1372 
1373 		goto done;
1374 	}
1375 
1376 	/*
1377 	 * looks in cache, if any
1378 	 */
1379 	if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
1380 		cached = i = meta_dncache_get_target( &mi->mi_cache, &op->o_req_ndn );
1381 	}
1382 
1383 	if ( op_type == META_OP_REQUIRE_SINGLE ) {
1384 		metatarget_t		*mt = NULL;
1385 		metasingleconn_t	*msc = NULL;
1386 
1387 		int			j;
1388 
1389 		for ( j = 0; j < mi->mi_ntargets; j++ ) {
1390 			META_CANDIDATE_RESET( &candidates[ j ] );
1391 		}
1392 
1393 		/*
1394 		 * tries to get a unique candidate
1395 		 * (takes care of default target)
1396 		 */
1397 		if ( i == META_TARGET_NONE ) {
1398 			i = meta_back_get_candidate( op, rs, &ndn );
1399 
1400 			if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && dn_type == META_DNTYPE_PARENT ) {
1401 				i = meta_back_get_candidate( op, rs, &pndn );
1402 			}
1403 
1404 			if ( i < 0 || rs->sr_err != LDAP_SUCCESS ) {
1405 				if ( mc != NULL ) {
1406 					meta_back_release_conn( mi, mc );
1407 				}
1408 
1409 				if ( sendok & LDAP_BACK_SENDERR ) {
1410 					if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
1411 						rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val;
1412 					}
1413 					send_ldap_result( op, rs );
1414 					rs->sr_matched = NULL;
1415 				}
1416 
1417 				return NULL;
1418 			}
1419 		}
1420 
1421 		if ( dn_type == META_DNTYPE_NEWPARENT && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i )
1422 		{
1423 			if ( mc != NULL ) {
1424 				meta_back_release_conn( mi, mc );
1425 			}
1426 
1427 			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1428 			rs->sr_text = "Cross-target rename not supported";
1429 			if ( sendok & LDAP_BACK_SENDERR ) {
1430 				send_ldap_result( op, rs );
1431 			}
1432 
1433 			return NULL;
1434 		}
1435 
1436 		Debug( LDAP_DEBUG_TRACE,
1437 	"==>meta_back_getconn: got target=%d for ndn=\"%s\" from cache\n",
1438 				i, op->o_req_ndn.bv_val, 0 );
1439 
1440 		if ( mc == NULL ) {
1441 			/* Retries searching for a metaconn in the avl tree
1442 			 * the reason is that the connection might have been
1443 			 * created by meta_back_get_candidate() */
1444 			if ( !( sendok & LDAP_BACK_BINDING ) ) {
1445 retry_lock2:;
1446 				ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1447 				mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree,
1448 					(caddr_t)&mc_curr, meta_back_conndn_cmp );
1449 				if ( mc != NULL ) {
1450 					/* catch taint errors */
1451 					assert( !LDAP_BACK_CONN_TAINTED( mc ) );
1452 
1453 					/* Don't reuse connections while they're still binding */
1454 					if ( META_BACK_CONN_CREATING( &mc->mc_conns[ i ] )
1455 						|| LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) )
1456 					{
1457 						if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
1458 							ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1459 							ldap_pvt_thread_yield();
1460 							goto retry_lock2;
1461 						}
1462 
1463 						mc = NULL;
1464 
1465 					} else {
1466 						mc->mc_refcnt++;
1467 					}
1468 				}
1469 				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1470 			}
1471 
1472 			/* Looks like we didn't get a bind. Open a new session... */
1473 			if ( mc == NULL ) {
1474 				assert( new_conn == 0 );
1475 				mc = metaconn_alloc( op );
1476 				mc->mc_conn = mc_curr.mc_conn;
1477 				ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn );
1478 				new_conn = 1;
1479 				if ( sendok & LDAP_BACK_BINDING ) {
1480 					LDAP_BACK_CONN_BINDING_SET( mc );
1481 				}
1482 				if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
1483 					LDAP_BACK_CONN_ISPRIV_SET( mc );
1484 
1485 				} else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) {
1486 					LDAP_BACK_CONN_ISANON_SET( mc );
1487 				}
1488 			}
1489 		}
1490 
1491 		/*
1492 		 * Clear all other candidates
1493 		 */
1494 		( void )meta_clear_unused_candidates( op, i );
1495 
1496 		mt = mi->mi_targets[ i ];
1497 		msc = &mc->mc_conns[ i ];
1498 
1499 		/*
1500 		 * The target is activated; if needed, it is
1501 		 * also init'd. In case of error, meta_back_init_one_conn
1502 		 * sends the appropriate result.
1503 		 */
1504 		err = meta_back_init_one_conn( op, rs, mc, i,
1505 			LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok, !new_conn );
1506 		if ( err != LDAP_SUCCESS ) {
1507 			/*
1508 			 * FIXME: in case one target cannot
1509 			 * be init'd, should the other ones
1510 			 * be tried?
1511 			 */
1512 			META_CANDIDATE_RESET( &candidates[ i ] );
1513  			if ( new_conn ) {
1514 				mc->mc_refcnt = 0;
1515 				meta_back_conn_free( mc );
1516 
1517 			} else {
1518 				meta_back_release_conn( mi, mc );
1519 			}
1520 			return NULL;
1521 		}
1522 
1523 		if ( new_conn && ( sendok & LDAP_BACK_BINDING ) ) {
1524 			LDAP_BACK_CONN_BINDING_SET( &mc->mc_conns[ i ] );
1525 		}
1526 
1527 		candidates[ i ].sr_err = LDAP_SUCCESS;
1528 		META_CANDIDATE_SET( &candidates[ i ] );
1529 		ncandidates++;
1530 
1531 		if ( candidate ) {
1532 			*candidate = i;
1533 		}
1534 
1535 	/*
1536 	 * if no unique candidate ...
1537 	 */
1538 	} else {
1539 
1540 		/* Looks like we didn't get a bind. Open a new session... */
1541 		if ( mc == NULL ) {
1542 			assert( new_conn == 0 );
1543 			mc = metaconn_alloc( op );
1544 			mc->mc_conn = mc_curr.mc_conn;
1545 			ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn );
1546 			new_conn = 1;
1547 			if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
1548 				LDAP_BACK_CONN_ISPRIV_SET( mc );
1549 
1550 			} else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) {
1551 				LDAP_BACK_CONN_ISANON_SET( mc );
1552 			}
1553 		}
1554 
1555 		for ( i = 0; i < mi->mi_ntargets; i++ ) {
1556 			metatarget_t		*mt = mi->mi_targets[ i ];
1557 
1558 			META_CANDIDATE_RESET( &candidates[ i ] );
1559 
1560 			if ( i == cached
1561 				|| meta_back_is_candidate( mt, &op->o_req_ndn,
1562 					op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_SUBTREE ) )
1563 			{
1564 
1565 				/*
1566 				 * The target is activated; if needed, it is
1567 				 * also init'd
1568 				 */
1569 				int lerr = meta_back_init_one_conn( op, rs, mc, i,
1570 					LDAP_BACK_CONN_ISPRIV( &mc_curr ),
1571 					LDAP_BACK_DONTSEND, !new_conn );
1572 				candidates[ i ].sr_err = lerr;
1573 				if ( lerr == LDAP_SUCCESS ) {
1574 					META_CANDIDATE_SET( &candidates[ i ] );
1575 					ncandidates++;
1576 
1577 					Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d]\n",
1578 						op->o_log_prefix, i, 0 );
1579 
1580 				} else if ( lerr == LDAP_UNAVAILABLE && !META_BACK_ONERR_STOP( mi ) ) {
1581 					META_CANDIDATE_SET( &candidates[ i ] );
1582 
1583 					Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] %s\n",
1584 						op->o_log_prefix, i,
1585 						mt->mt_isquarantined != LDAP_BACK_FQ_NO ? "quarantined" : "unavailable" );
1586 
1587 				} else {
1588 
1589 					/*
1590 					 * FIXME: in case one target cannot
1591 					 * be init'd, should the other ones
1592 					 * be tried?
1593 					 */
1594 					if ( new_conn ) {
1595 						( void )meta_clear_one_candidate( op, mc, i );
1596 					}
1597 					/* leave the target candidate, but record the error for later use */
1598 					err = lerr;
1599 
1600 					if ( lerr == LDAP_UNAVAILABLE && mt->mt_isquarantined != LDAP_BACK_FQ_NO ) {
1601 						Log4( LDAP_DEBUG_TRACE, ldap_syslog_level, "%s: meta_back_getconn[%d] quarantined err=%d text=%s\n",
1602 							op->o_log_prefix, i, lerr, rs->sr_text );
1603 
1604 					} else {
1605 						Log4( LDAP_DEBUG_ANY, ldap_syslog, "%s: meta_back_getconn[%d] failed err=%d text=%s\n",
1606 							op->o_log_prefix, i, lerr, rs->sr_text );
1607 					}
1608 
1609 					if ( META_BACK_ONERR_STOP( mi ) ) {
1610 						if ( sendok & LDAP_BACK_SENDERR ) {
1611 							send_ldap_result( op, rs );
1612 						}
1613 						if ( new_conn ) {
1614 							mc->mc_refcnt = 0;
1615 							meta_back_conn_free( mc );
1616 
1617 						} else {
1618 							meta_back_release_conn( mi, mc );
1619 						}
1620 
1621 						return NULL;
1622 					}
1623 
1624 					continue;
1625 				}
1626 
1627 			} else {
1628 				if ( new_conn ) {
1629 					( void )meta_clear_one_candidate( op, mc, i );
1630 				}
1631 			}
1632 		}
1633 
1634 		if ( ncandidates == 0 ) {
1635 			if ( new_conn ) {
1636 				mc->mc_refcnt = 0;
1637 				meta_back_conn_free( mc );
1638 
1639 			} else {
1640 				meta_back_release_conn( mi, mc );
1641 			}
1642 
1643 			if ( rs->sr_err == LDAP_SUCCESS ) {
1644 				rs->sr_err = LDAP_NO_SUCH_OBJECT;
1645 				rs->sr_text = "Unable to select valid candidates";
1646 			}
1647 
1648 			if ( sendok & LDAP_BACK_SENDERR ) {
1649 				if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
1650 					rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val;
1651 				}
1652 				send_ldap_result( op, rs );
1653 				rs->sr_matched = NULL;
1654 			}
1655 
1656 			return NULL;
1657 		}
1658 	}
1659 
1660 done:;
1661 	/* clear out meta_back_init_one_conn non-fatal errors */
1662 	rs->sr_err = LDAP_SUCCESS;
1663 	rs->sr_text = NULL;
1664 
1665 	/* touch the timestamp */
1666 	if ( mi->mi_idle_timeout != 0 ) {
1667 		mc->mc_time = op->o_time;
1668 	}
1669 
1670 	if ( new_conn ) {
1671 		if ( mi->mi_conn_ttl ) {
1672 			mc->mc_create_time = op->o_time;
1673 		}
1674 
1675 		/*
1676 		 * Inserts the newly created metaconn in the avl tree
1677 		 */
1678 		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1679 #if META_BACK_PRINT_CONNTREE > 0
1680 		meta_back_print_conntree( mi, ">>> meta_back_getconn" );
1681 #endif /* META_BACK_PRINT_CONNTREE */
1682 
1683 		err = 0;
1684 		if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
1685 			if ( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num < mi->mi_conn_priv_max ) {
1686 				LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q );
1687 				mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num++;
1688 				LDAP_BACK_CONN_CACHED_SET( mc );
1689 
1690 			} else {
1691 				LDAP_BACK_CONN_TAINTED_SET( mc );
1692 			}
1693 			rs->sr_err = 0;
1694 
1695 		} else if ( !( sendok & LDAP_BACK_BINDING ) ) {
1696 			err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
1697 			       	meta_back_conndn_cmp, meta_back_conndn_dup );
1698 			LDAP_BACK_CONN_CACHED_SET( mc );
1699 		}
1700 
1701 #if META_BACK_PRINT_CONNTREE > 0
1702 		meta_back_print_conntree( mi, "<<< meta_back_getconn" );
1703 #endif /* META_BACK_PRINT_CONNTREE */
1704 		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1705 
1706 		if ( !LDAP_BACK_PCONN_ISPRIV( mc ) ) {
1707 			/*
1708 			 * Err could be -1 in case a duplicate metaconn is inserted
1709 			 */
1710 			switch ( err ) {
1711 			case 0:
1712 				break;
1713 
1714 			case -1:
1715 				LDAP_BACK_CONN_CACHED_CLEAR( mc );
1716 				/* duplicate: free and try to get the newly created one */
1717 				if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
1718 					mc->mc_refcnt = 0;
1719 					meta_back_conn_free( mc );
1720 
1721 					new_conn = 0;
1722 					goto retry_lock;
1723 				}
1724 
1725 				LDAP_BACK_CONN_TAINTED_SET( mc );
1726 				break;
1727 
1728 			default:
1729 				LDAP_BACK_CONN_CACHED_CLEAR( mc );
1730 				if ( LogTest( LDAP_DEBUG_ANY ) ) {
1731 					char buf[STRLENOF("4294967295U") + 1] = { 0 };
1732 					mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
1733 
1734 					Debug( LDAP_DEBUG_ANY,
1735 						"%s meta_back_getconn: candidates=%d conn=%s insert failed\n",
1736 						op->o_log_prefix, ncandidates, buf );
1737 				}
1738 
1739 				mc->mc_refcnt = 0;
1740 				meta_back_conn_free( mc );
1741 
1742 				rs->sr_err = LDAP_OTHER;
1743 				rs->sr_text = "Proxy bind collision";
1744 				if ( sendok & LDAP_BACK_SENDERR ) {
1745 					send_ldap_result( op, rs );
1746 				}
1747 				return NULL;
1748 			}
1749 		}
1750 
1751 		if ( LogTest( LDAP_DEBUG_TRACE ) ) {
1752 			char buf[STRLENOF("4294967295U") + 1] = { 0 };
1753 			mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
1754 
1755 			Debug( LDAP_DEBUG_TRACE,
1756 				"%s meta_back_getconn: candidates=%d conn=%s inserted\n",
1757 				op->o_log_prefix, ncandidates, buf );
1758 		}
1759 
1760 	} else {
1761 		if ( LogTest( LDAP_DEBUG_TRACE ) ) {
1762 			char buf[STRLENOF("4294967295U") + 1] = { 0 };
1763 			mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
1764 
1765 			Debug( LDAP_DEBUG_TRACE,
1766 				"%s meta_back_getconn: candidates=%d conn=%s fetched\n",
1767 				op->o_log_prefix, ncandidates, buf );
1768 		}
1769 	}
1770 
1771 	return mc;
1772 }
1773 
1774 void
1775 meta_back_release_conn_lock(
1776        	metainfo_t		*mi,
1777 	metaconn_t		*mc,
1778 	int			dolock )
1779 {
1780 	assert( mc != NULL );
1781 
1782 	if ( dolock ) {
1783 		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1784 	}
1785 	assert( mc->mc_refcnt > 0 );
1786 	mc->mc_refcnt--;
1787 	/* NOTE: the connection is removed if either it is tainted
1788 	 * or if it is shared and no one else is using it.  This needs
1789 	 * to occur because for intrinsic reasons cached connections
1790 	 * that are not privileged would live forever and pollute
1791 	 * the connection space (and eat up resources).  Maybe this
1792 	 * should be configurable... */
1793 	if ( LDAP_BACK_CONN_TAINTED( mc ) || !LDAP_BACK_CONN_CACHED( mc ) ) {
1794 #if META_BACK_PRINT_CONNTREE > 0
1795 		meta_back_print_conntree( mi, ">>> meta_back_release_conn" );
1796 #endif /* META_BACK_PRINT_CONNTREE */
1797 
1798 		if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
1799 			if ( mc->mc_q.tqe_prev != NULL ) {
1800 				assert( LDAP_BACK_CONN_CACHED( mc ) );
1801 				assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 );
1802 				LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q );
1803 				mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--;
1804 				LDAP_TAILQ_ENTRY_INIT( mc, mc_q );
1805 
1806 			} else {
1807 				assert( !LDAP_BACK_CONN_CACHED( mc ) );
1808 			}
1809 
1810 		} else if ( LDAP_BACK_CONN_CACHED( mc ) ) {
1811 			metaconn_t	*tmpmc;
1812 
1813 			tmpmc = avl_delete( &mi->mi_conninfo.lai_tree,
1814 				( caddr_t )mc, meta_back_conndnmc_cmp );
1815 
1816 			/* Overparanoid, but useful... */
1817 			assert( tmpmc == NULL || tmpmc == mc );
1818 		}
1819 
1820 		LDAP_BACK_CONN_CACHED_CLEAR( mc );
1821 
1822 #if META_BACK_PRINT_CONNTREE > 0
1823 		meta_back_print_conntree( mi, "<<< meta_back_release_conn" );
1824 #endif /* META_BACK_PRINT_CONNTREE */
1825 
1826 		if ( mc->mc_refcnt == 0 ) {
1827 			meta_back_conn_free( mc );
1828 			mc = NULL;
1829 		}
1830 	}
1831 
1832 	if ( mc != NULL && LDAP_BACK_CONN_BINDING( mc ) ) {
1833 		LDAP_BACK_CONN_BINDING_CLEAR( mc );
1834 	}
1835 
1836 	if ( dolock ) {
1837 		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1838 	}
1839 }
1840 
1841 void
1842 meta_back_quarantine(
1843 	Operation	*op,
1844 	SlapReply	*rs,
1845 	int		candidate )
1846 {
1847 	metainfo_t		*mi = (metainfo_t *)op->o_bd->be_private;
1848 	metatarget_t		*mt = mi->mi_targets[ candidate ];
1849 
1850 	slap_retry_info_t	*ri = &mt->mt_quarantine;
1851 
1852 	ldap_pvt_thread_mutex_lock( &mt->mt_quarantine_mutex );
1853 
1854 	if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1855 		time_t	new_last = slap_get_time();
1856 
1857 		switch ( mt->mt_isquarantined ) {
1858 		case LDAP_BACK_FQ_NO:
1859 			if ( ri->ri_last == new_last ) {
1860 				goto done;
1861 			}
1862 
1863 			Debug( LDAP_DEBUG_ANY,
1864 				"%s meta_back_quarantine[%d]: enter.\n",
1865 				op->o_log_prefix, candidate, 0 );
1866 
1867 			ri->ri_idx = 0;
1868 			ri->ri_count = 0;
1869 			break;
1870 
1871 		case LDAP_BACK_FQ_RETRYING:
1872 			if ( LogTest( LDAP_DEBUG_ANY ) ) {
1873 				char	buf[ SLAP_TEXT_BUFLEN ];
1874 
1875 				snprintf( buf, sizeof( buf ),
1876 					"meta_back_quarantine[%d]: block #%d try #%d failed",
1877 					candidate, ri->ri_idx, ri->ri_count );
1878 				Debug( LDAP_DEBUG_ANY, "%s %s.\n",
1879 					op->o_log_prefix, buf, 0 );
1880 			}
1881 
1882 			++ri->ri_count;
1883 			if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER
1884 				&& ri->ri_count == ri->ri_num[ ri->ri_idx ] )
1885 			{
1886 				ri->ri_count = 0;
1887 				++ri->ri_idx;
1888 			}
1889 			break;
1890 
1891 		default:
1892 			break;
1893 		}
1894 
1895 		mt->mt_isquarantined = LDAP_BACK_FQ_YES;
1896 		ri->ri_last = new_last;
1897 
1898 	} else if ( mt->mt_isquarantined == LDAP_BACK_FQ_RETRYING ) {
1899 		Debug( LDAP_DEBUG_ANY,
1900 			"%s meta_back_quarantine[%d]: exit.\n",
1901 			op->o_log_prefix, candidate, 0 );
1902 
1903 		if ( mi->mi_quarantine_f ) {
1904 			(void)mi->mi_quarantine_f( mi, candidate,
1905 				mi->mi_quarantine_p );
1906 		}
1907 
1908 		ri->ri_count = 0;
1909 		ri->ri_idx = 0;
1910 		mt->mt_isquarantined = LDAP_BACK_FQ_NO;
1911 	}
1912 
1913 done:;
1914 	ldap_pvt_thread_mutex_unlock( &mt->mt_quarantine_mutex );
1915 }
1916