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