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