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