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