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