1/*	$NetBSD$	*/
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 */
45int
46meta_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 */
72static int
73meta_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 */
102int
103meta_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 */
122int
123meta_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
144static void
145meta_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
164static void
165meta_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 */
187static char* priv2str[] = {
188	"privileged",
189	"privileged/TLS",
190	"anonymous",
191	"anonymous/TLS",
192	"bind",
193	"bind/TLS",
194	NULL
195};
196
197void
198meta_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 */
237static metaconn_t *
238metaconn_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 */
267int
268meta_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
331retry_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
447retry:;
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
634error_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 */
665int
666meta_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 */
823static int
824meta_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
845static int
846meta_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
927static void	*meta_back_candidates_dummy;
928
929static void
930meta_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
940SlapReply *
941meta_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 */
1020metaconn_t *
1021meta_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 */
1085retry_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 ) ) {
1380retry_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
1595done:;
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
1709void
1710meta_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
1776void
1777meta_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
1848done:;
1849	ldap_pvt_thread_mutex_unlock( &mt->mt_quarantine_mutex );
1850}
1851
1852