xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-meta/bind.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: bind.c,v 1.1.1.6 2018/02/06 01:53:16 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2017 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: bind.c,v 1.1.1.6 2018/02/06 01:53:16 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 #include "lutil_ldap.h"
43 
44 static int
45 meta_back_proxy_authz_bind(
46 	metaconn_t		*mc,
47 	int			candidate,
48 	Operation		*op,
49 	SlapReply		*rs,
50 	ldap_back_send_t	sendok,
51 	int			dolock );
52 
53 static int
54 meta_back_single_bind(
55 	Operation		*op,
56 	SlapReply		*rs,
57 	metaconn_t		*mc,
58 	int			candidate );
59 
60 int
61 meta_back_bind( Operation *op, SlapReply *rs )
62 {
63 	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
64 	metaconn_t	*mc = NULL;
65 
66 	int		rc = LDAP_OTHER,
67 			i,
68 			gotit = 0,
69 			isroot = 0;
70 
71 	SlapReply	*candidates;
72 
73 	rs->sr_err = LDAP_SUCCESS;
74 
75 	Debug( LDAP_DEBUG_ARGS, "%s meta_back_bind: dn=\"%s\".\n",
76 		op->o_log_prefix, op->o_req_dn.bv_val, 0 );
77 
78 	/* the test on the bind method should be superfluous */
79 	switch ( be_rootdn_bind( op, rs ) ) {
80 	case LDAP_SUCCESS:
81 		if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) {
82 			/* frontend will return success */
83 			return rs->sr_err;
84 		}
85 
86 		isroot = 1;
87 		/* fallthru */
88 
89 	case SLAP_CB_CONTINUE:
90 		break;
91 
92 	default:
93 		/* be_rootdn_bind() sent result */
94 		return rs->sr_err;
95 	}
96 
97 	/* we need meta_back_getconn() not send result even on error,
98 	 * because we want to intercept the error and make it
99 	 * invalidCredentials */
100 	mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND );
101 	if ( !mc ) {
102 		if ( LogTest( LDAP_DEBUG_ANY ) ) {
103 			char	buf[ SLAP_TEXT_BUFLEN ];
104 
105 			snprintf( buf, sizeof( buf ),
106 				"meta_back_bind: no target "
107 				"for dn \"%s\" (%d%s%s).",
108 				op->o_req_dn.bv_val, rs->sr_err,
109 				rs->sr_text ? ". " : "",
110 				rs->sr_text ? rs->sr_text : "" );
111 			Debug( LDAP_DEBUG_ANY,
112 				"%s %s\n",
113 				op->o_log_prefix, buf, 0 );
114 		}
115 
116 		/* FIXME: there might be cases where we don't want
117 		 * to map the error onto invalidCredentials */
118 		switch ( rs->sr_err ) {
119 		case LDAP_NO_SUCH_OBJECT:
120 		case LDAP_UNWILLING_TO_PERFORM:
121 			rs->sr_err = LDAP_INVALID_CREDENTIALS;
122 			rs->sr_text = NULL;
123 			break;
124 		}
125 		send_ldap_result( op, rs );
126 		return rs->sr_err;
127 	}
128 
129 	candidates = meta_back_candidates_get( op );
130 
131 	/*
132 	 * Each target is scanned ...
133 	 */
134 	mc->mc_authz_target = META_BOUND_NONE;
135 	for ( i = 0; i < mi->mi_ntargets; i++ ) {
136 		metatarget_t	*mt = mi->mi_targets[ i ];
137 		int		lerr;
138 
139 		/*
140 		 * Skip non-candidates
141 		 */
142 		if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
143 			continue;
144 		}
145 
146 		if ( gotit == 0 ) {
147 			/* set rc to LDAP_SUCCESS only if at least
148 			 * one candidate has been tried */
149 			rc = LDAP_SUCCESS;
150 			gotit = 1;
151 
152 		} else if ( !isroot ) {
153 			/*
154 			 * A bind operation is expected to have
155 			 * ONE CANDIDATE ONLY!
156 			 */
157 			Debug( LDAP_DEBUG_ANY,
158 				"### %s meta_back_bind: more than one"
159 				" candidate selected...\n",
160 				op->o_log_prefix, 0, 0 );
161 		}
162 
163 		if ( isroot ) {
164 			if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE
165 				|| BER_BVISNULL( &mt->mt_idassert_authcDN ) )
166 			{
167 				metasingleconn_t	*msc = &mc->mc_conns[ i ];
168 
169 				/* skip the target if no pseudorootdn is provided */
170 				if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
171 					ch_free( msc->msc_bound_ndn.bv_val );
172 					BER_BVZERO( &msc->msc_bound_ndn );
173 				}
174 
175 				if ( !BER_BVISNULL( &msc->msc_cred ) ) {
176 					/* destroy sensitive data */
177 					memset( msc->msc_cred.bv_val, 0,
178 						msc->msc_cred.bv_len );
179 					ch_free( msc->msc_cred.bv_val );
180 					BER_BVZERO( &msc->msc_cred );
181 				}
182 
183 				continue;
184 			}
185 
186 
187 			(void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND, 1 );
188 			lerr = rs->sr_err;
189 
190 		} else {
191 			lerr = meta_back_single_bind( op, rs, mc, i );
192 		}
193 
194 		if ( lerr != LDAP_SUCCESS ) {
195 			rc = rs->sr_err = lerr;
196 
197 			/* FIXME: in some cases (e.g. unavailable)
198 			 * do not assume it's not candidate; rather
199 			 * mark this as an error to be eventually
200 			 * reported to client */
201 			META_CANDIDATE_CLEAR( &candidates[ i ] );
202 			break;
203 		}
204 	}
205 
206 	/* must re-insert if local DN changed as result of bind */
207 	if ( rc == LDAP_SUCCESS ) {
208 		if ( isroot ) {
209 			mc->mc_authz_target = META_BOUND_ALL;
210 		}
211 
212 		if ( !LDAP_BACK_PCONN_ISPRIV( mc )
213 			&& !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) )
214 		{
215 			int		lerr;
216 
217 			/* wait for all other ops to release the connection */
218 			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
219 			assert( mc->mc_refcnt == 1 );
220 #if META_BACK_PRINT_CONNTREE > 0
221 			meta_back_print_conntree( mi, ">>> meta_back_bind" );
222 #endif /* META_BACK_PRINT_CONNTREE */
223 
224 			/* delete all cached connections with the current connection */
225 			if ( LDAP_BACK_SINGLECONN( mi ) ) {
226 				metaconn_t	*tmpmc;
227 
228 				while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )
229 				{
230 					assert( !LDAP_BACK_PCONN_ISPRIV( mc ) );
231 					Debug( LDAP_DEBUG_TRACE,
232 						"=>meta_back_bind: destroying conn %lu (refcnt=%u)\n",
233 						mc->mc_conn->c_connid, mc->mc_refcnt, 0 );
234 
235 					if ( tmpmc->mc_refcnt != 0 ) {
236 						/* taint it */
237 						LDAP_BACK_CONN_TAINTED_SET( tmpmc );
238 
239 					} else {
240 						/*
241 						 * Needs a test because the handler may be corrupted,
242 						 * and calling ldap_unbind on a corrupted header results
243 						 * in a segmentation fault
244 						 */
245 						meta_back_conn_free( tmpmc );
246 					}
247 				}
248 			}
249 
250 			ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
251 			lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
252 				meta_back_conndn_cmp, meta_back_conndn_dup );
253 #if META_BACK_PRINT_CONNTREE > 0
254 			meta_back_print_conntree( mi, "<<< meta_back_bind" );
255 #endif /* META_BACK_PRINT_CONNTREE */
256 			if ( lerr == 0 ) {
257 #if 0
258 				/* NOTE: a connection cannot be privileged
259 				 * and be in the avl tree at the same time
260 				 */
261 				if ( isroot ) {
262 					LDAP_BACK_CONN_ISPRIV_SET( mc );
263 					LDAP_BACK_PCONN_SET( mc, op );
264 				}
265 #endif
266 				LDAP_BACK_CONN_CACHED_SET( mc );
267 
268 			} else {
269 				LDAP_BACK_CONN_CACHED_CLEAR( mc );
270 			}
271 			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
272 		}
273 	}
274 
275 	if ( mc != NULL ) {
276 		meta_back_release_conn( mi, mc );
277 	}
278 
279 	/*
280 	 * rc is LDAP_SUCCESS if at least one bind succeeded,
281 	 * err is the last error that occurred during a bind;
282 	 * if at least (and at most?) one bind succeeds, fine.
283 	 */
284 	if ( rc != LDAP_SUCCESS ) {
285 
286 		/*
287 		 * deal with bind failure ...
288 		 */
289 
290 		/*
291 		 * no target was found within the naming context,
292 		 * so bind must fail with invalid credentials
293 		 */
294 		if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {
295 			rs->sr_err = LDAP_INVALID_CREDENTIALS;
296 		} else {
297 			rs->sr_err = slap_map_api2result( rs );
298 		}
299 		send_ldap_result( op, rs );
300 		return rs->sr_err;
301 
302 	}
303 
304 	return LDAP_SUCCESS;
305 }
306 
307 static int
308 meta_back_bind_op_result(
309 	Operation		*op,
310 	SlapReply		*rs,
311 	metaconn_t		*mc,
312 	int			candidate,
313 	int			msgid,
314 	ldap_back_send_t	sendok,
315 	int			dolock )
316 {
317 	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
318 	metatarget_t		*mt = mi->mi_targets[ candidate ];
319 	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
320 	LDAPMessage		*res;
321 	struct timeval		tv;
322 	int			rc;
323 	int			nretries = mt->mt_nretries;
324 	char			buf[ SLAP_TEXT_BUFLEN ];
325 
326 	Debug( LDAP_DEBUG_TRACE,
327 		">>> %s meta_back_bind_op_result[%d]\n",
328 		op->o_log_prefix, candidate, 0 );
329 
330 	/* make sure this is clean */
331 	assert( rs->sr_ctrls == NULL );
332 
333 	if ( rs->sr_err == LDAP_SUCCESS ) {
334 		time_t		stoptime = (time_t)(-1),
335 				timeout;
336 		int		timeout_err = op->o_protocol >= LDAP_VERSION3 ?
337 				LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
338 		const char	*timeout_text = "Operation timed out";
339 		slap_op_t	opidx = slap_req2op( op->o_tag );
340 
341 		/* since timeout is not specified, compute and use
342 		 * the one specific to the ongoing operation */
343 		if ( opidx == LDAP_REQ_SEARCH ) {
344 			if ( op->ors_tlimit <= 0 ) {
345 				timeout = 0;
346 
347 			} else {
348 				timeout = op->ors_tlimit;
349 				timeout_err = LDAP_TIMELIMIT_EXCEEDED;
350 				timeout_text = NULL;
351 			}
352 
353 		} else {
354 			timeout = mt->mt_timeout[ opidx ];
355 		}
356 
357 		/* better than nothing :) */
358 		if ( timeout == 0 ) {
359 			if ( mi->mi_idle_timeout ) {
360 				timeout = mi->mi_idle_timeout;
361 
362 			} else if ( mi->mi_conn_ttl ) {
363 				timeout = mi->mi_conn_ttl;
364 			}
365 		}
366 
367 		if ( timeout ) {
368 			stoptime = op->o_time + timeout;
369 		}
370 
371 		LDAP_BACK_TV_SET( &tv );
372 
373 		/*
374 		 * handle response!!!
375 		 */
376 retry:;
377 		rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
378 		switch ( rc ) {
379 		case 0:
380 			if ( nretries != META_RETRY_NEVER
381 				|| ( timeout && slap_get_time() <= stoptime ) )
382 			{
383 				ldap_pvt_thread_yield();
384 				if ( nretries > 0 ) {
385 					nretries--;
386 				}
387 				tv = mt->mt_bind_timeout;
388 				goto retry;
389 			}
390 
391 			/* don't let anyone else use this handler,
392 			 * because there's a pending bind that will not
393 			 * be acknowledged */
394 			if ( dolock) {
395 				ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
396 			}
397 			assert( LDAP_BACK_CONN_BINDING( msc ) );
398 
399 #ifdef DEBUG_205
400 			Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n",
401 				op->o_log_prefix, candidate, (void *)msc->msc_ld );
402 #endif /* DEBUG_205 */
403 
404 			meta_clear_one_candidate( op, mc, candidate );
405 			if ( dolock ) {
406 				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
407 			}
408 
409 			rs->sr_err = timeout_err;
410 			rs->sr_text = timeout_text;
411 			break;
412 
413 		case -1:
414 			ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
415 				&rs->sr_err );
416 
417 			snprintf( buf, sizeof( buf ),
418 				"err=%d (%s) nretries=%d",
419 				rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
420 			Debug( LDAP_DEBUG_ANY,
421 				"### %s meta_back_bind_op_result[%d]: %s.\n",
422 				op->o_log_prefix, candidate, buf );
423 			break;
424 
425 		default:
426 			/* only touch when activity actually took place... */
427 			if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
428 				msc->msc_time = op->o_time;
429 			}
430 
431 			/* FIXME: matched? referrals? response controls? */
432 			rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
433 					NULL, NULL, NULL, NULL, 1 );
434 			if ( rc != LDAP_SUCCESS ) {
435 				rs->sr_err = rc;
436 			}
437 			rs->sr_err = slap_map_api2result( rs );
438 			break;
439 		}
440 	}
441 
442 	rs->sr_err = slap_map_api2result( rs );
443 
444 	Debug( LDAP_DEBUG_TRACE,
445 		"<<< %s meta_back_bind_op_result[%d] err=%d\n",
446 		op->o_log_prefix, candidate, rs->sr_err );
447 
448 	return rs->sr_err;
449 }
450 
451 /*
452  * meta_back_single_bind
453  *
454  * attempts to perform a bind with creds
455  */
456 static int
457 meta_back_single_bind(
458 	Operation		*op,
459 	SlapReply		*rs,
460 	metaconn_t		*mc,
461 	int			candidate )
462 {
463 	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
464 	metatarget_t		*mt = mi->mi_targets[ candidate ];
465 	struct berval		mdn = BER_BVNULL;
466 	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
467 	int			msgid;
468 	dncookie		dc;
469 	struct berval		save_o_dn;
470 	int			save_o_do_not_cache;
471 	LDAPControl		**ctrls = NULL;
472 
473 	if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
474 		ch_free( msc->msc_bound_ndn.bv_val );
475 		BER_BVZERO( &msc->msc_bound_ndn );
476 	}
477 
478 	if ( !BER_BVISNULL( &msc->msc_cred ) ) {
479 		/* destroy sensitive data */
480 		memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
481 		ch_free( msc->msc_cred.bv_val );
482 		BER_BVZERO( &msc->msc_cred );
483 	}
484 
485 	/*
486 	 * Rewrite the bind dn if needed
487 	 */
488 	dc.target = mt;
489 	dc.conn = op->o_conn;
490 	dc.rs = rs;
491 	dc.ctx = "bindDN";
492 
493 	if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
494 		rs->sr_text = "DN rewrite error";
495 		rs->sr_err = LDAP_OTHER;
496 		return rs->sr_err;
497 	}
498 
499 	/* don't add proxyAuthz; set the bindDN */
500 	save_o_dn = op->o_dn;
501 	save_o_do_not_cache = op->o_do_not_cache;
502 	op->o_do_not_cache = 1;
503 	op->o_dn = op->o_req_dn;
504 
505 	ctrls = op->o_ctrls;
506 	rs->sr_err = meta_back_controls_add( op, rs, mc, candidate, &ctrls );
507 	op->o_dn = save_o_dn;
508 	op->o_do_not_cache = save_o_do_not_cache;
509 	if ( rs->sr_err != LDAP_SUCCESS ) {
510 		goto return_results;
511 	}
512 
513 	/* FIXME: this fixes the bind problem right now; we need
514 	 * to use the asynchronous version to get the "matched"
515 	 * and more in case of failure ... */
516 	/* FIXME: should we check if at least some of the op->o_ctrls
517 	 * can/should be passed? */
518 	for (;;) {
519 		rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val,
520 			LDAP_SASL_SIMPLE, &op->orb_cred,
521 			ctrls, NULL, &msgid );
522 		if ( rs->sr_err != LDAP_X_CONNECTING ) {
523 			break;
524 		}
525 		ldap_pvt_thread_yield();
526 	}
527 
528 	mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
529 
530 	meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND, 1 );
531 	if ( rs->sr_err != LDAP_SUCCESS ) {
532 		goto return_results;
533 	}
534 
535 	/* If defined, proxyAuthz will be used also when
536 	 * back-ldap is the authorizing backend; for this
537 	 * purpose, a successful bind is followed by a
538 	 * bind with the configured identity assertion */
539 	/* NOTE: use with care */
540 	if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
541 		meta_back_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR, 1 );
542 		if ( !LDAP_BACK_CONN_ISBOUND( msc ) ) {
543 			goto return_results;
544 		}
545 		goto cache_refresh;
546 	}
547 
548 	ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_ndn );
549 	LDAP_BACK_CONN_ISBOUND_SET( msc );
550 	mc->mc_authz_target = candidate;
551 
552 	if ( META_BACK_TGT_SAVECRED( mt ) ) {
553 		if ( !BER_BVISNULL( &msc->msc_cred ) ) {
554 			memset( msc->msc_cred.bv_val, 0,
555 				msc->msc_cred.bv_len );
556 		}
557 		ber_bvreplace( &msc->msc_cred, &op->orb_cred );
558 		ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
559 	}
560 
561 cache_refresh:;
562 	if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED
563 			&& !BER_BVISEMPTY( &op->o_req_ndn ) )
564 	{
565 		( void )meta_dncache_update_entry( &mi->mi_cache,
566 				&op->o_req_ndn, candidate );
567 	}
568 
569 return_results:;
570 	if ( mdn.bv_val != op->o_req_dn.bv_val ) {
571 		free( mdn.bv_val );
572 	}
573 
574 	if ( META_BACK_TGT_QUARANTINE( mt ) ) {
575 		meta_back_quarantine( op, rs, candidate );
576 	}
577 
578 	return rs->sr_err;
579 }
580 
581 /*
582  * meta_back_single_dobind
583  */
584 int
585 meta_back_single_dobind(
586 	Operation		*op,
587 	SlapReply		*rs,
588 	metaconn_t		**mcp,
589 	int			candidate,
590 	ldap_back_send_t	sendok,
591 	int			nretries,
592 	int			dolock )
593 {
594 	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
595 	metatarget_t		*mt = mi->mi_targets[ candidate ];
596 	metaconn_t		*mc = *mcp;
597 	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
598 	int			msgid;
599 
600 	assert( !LDAP_BACK_CONN_ISBOUND( msc ) );
601 
602 	/* NOTE: this obsoletes pseudorootdn */
603 	if ( op->o_conn != NULL &&
604 		!op->o_do_not_cache &&
605 		( BER_BVISNULL( &msc->msc_bound_ndn ) ||
606 			BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
607 			( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) ||
608 			( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
609 	{
610 		(void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok, dolock );
611 
612 	} else {
613 		char *binddn = "";
614 		struct berval cred = BER_BVC( "" );
615 
616 		/* use credentials if available */
617 		if ( !BER_BVISNULL( &msc->msc_bound_ndn )
618 			&& !BER_BVISNULL( &msc->msc_cred ) )
619 		{
620 			binddn = msc->msc_bound_ndn.bv_val;
621 			cred = msc->msc_cred;
622 		}
623 
624 		/* FIXME: should we check if at least some of the op->o_ctrls
625 		 * can/should be passed? */
626 		if(!dolock) {
627 			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
628 		}
629 
630 		for (;;) {
631 			rs->sr_err = ldap_sasl_bind( msc->msc_ld,
632 				binddn, LDAP_SASL_SIMPLE, &cred,
633 				NULL, NULL, &msgid );
634 			if ( rs->sr_err != LDAP_X_CONNECTING ) {
635 				break;
636 			}
637 			ldap_pvt_thread_yield();
638 		}
639 
640 		if(!dolock) {
641 			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
642 		}
643 
644 		rs->sr_err = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
645 
646 		/* if bind succeeded, but anonymous, clear msc_bound_ndn */
647 		if ( rs->sr_err != LDAP_SUCCESS || binddn[0] == '\0' ) {
648 			if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
649 				ber_memfree( msc->msc_bound_ndn.bv_val );
650 				BER_BVZERO( &msc->msc_bound_ndn );
651 			}
652 
653 			if ( !BER_BVISNULL( &msc->msc_cred ) ) {
654 				memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
655 				ber_memfree( msc->msc_cred.bv_val );
656 				BER_BVZERO( &msc->msc_cred );
657 			}
658 		}
659 	}
660 
661 	if ( rs->sr_err != LDAP_SUCCESS ) {
662 		if ( dolock ) {
663 			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
664 		}
665 		LDAP_BACK_CONN_BINDING_CLEAR( msc );
666 		if ( META_BACK_ONERR_STOP( mi ) ) {
667 			LDAP_BACK_CONN_TAINTED_SET( mc );
668 			meta_back_release_conn_lock( mi, mc, 0 );
669 			*mcp = NULL;
670 		}
671 		if ( dolock ) {
672 			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
673 		}
674 	}
675 
676 	if ( META_BACK_TGT_QUARANTINE( mt ) ) {
677 		meta_back_quarantine( op, rs, candidate );
678 	}
679 
680 	return rs->sr_err;
681 }
682 
683 /*
684  * meta_back_dobind
685  */
686 int
687 meta_back_dobind(
688 	Operation		*op,
689 	SlapReply		*rs,
690 	metaconn_t		*mc,
691 	ldap_back_send_t	sendok )
692 {
693 	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
694 
695 	int			bound = 0,
696 				i,
697 				isroot = 0;
698 
699 	SlapReply		*candidates;
700 
701 	if ( be_isroot( op ) ) {
702 		isroot = 1;
703 	}
704 
705 	if ( LogTest( LDAP_DEBUG_TRACE ) ) {
706 		char buf[STRLENOF("4294967295U") + 1] = { 0 };
707 		mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
708 
709 		Debug( LDAP_DEBUG_TRACE,
710 			"%s meta_back_dobind: conn=%s%s\n",
711 			op->o_log_prefix, buf,
712 			isroot ? " (isroot)" : "" );
713 	}
714 
715 	/*
716 	 * all the targets are bound as pseudoroot
717 	 */
718 	if ( mc->mc_authz_target == META_BOUND_ALL ) {
719 		bound = 1;
720 		goto done;
721 	}
722 
723 	candidates = meta_back_candidates_get( op );
724 
725 	for ( i = 0; i < mi->mi_ntargets; i++ ) {
726 		metatarget_t		*mt = mi->mi_targets[ i ];
727 		metasingleconn_t	*msc = &mc->mc_conns[ i ];
728 		int			rc;
729 
730 		/*
731 		 * Not a candidate
732 		 */
733 		if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
734 			continue;
735 		}
736 
737 		assert( msc->msc_ld != NULL );
738 
739 		/*
740 		 * If the target is already bound it is skipped
741 		 */
742 
743 retry_binding:;
744 		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
745 		if ( LDAP_BACK_CONN_ISBOUND( msc )
746 			|| ( LDAP_BACK_CONN_ISANON( msc )
747 				&& mt->mt_idassert_authmethod == LDAP_AUTH_NONE ) )
748 		{
749 			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
750 			++bound;
751 			continue;
752 
753 		} else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) )
754 		{
755 			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
756 			ldap_pvt_thread_yield();
757 			goto retry_binding;
758 
759 		}
760 
761 		LDAP_BACK_CONN_BINDING_SET( msc );
762 		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
763 
764 		rc = meta_back_single_dobind( op, rs, &mc, i,
765 			LDAP_BACK_DONTSEND, mt->mt_nretries, 1 );
766 		/*
767 		 * NOTE: meta_back_single_dobind() already retries;
768 		 * in case of failure, it resets mc...
769 		 */
770 		if ( rc != LDAP_SUCCESS ) {
771 			char		buf[ SLAP_TEXT_BUFLEN ];
772 
773 			if ( mc == NULL ) {
774 				/* meta_back_single_dobind() already sent
775 				 * response and released connection */
776 				goto send_err;
777 			}
778 
779 
780 			if ( rc == LDAP_UNAVAILABLE ) {
781 				/* FIXME: meta_back_retry() already re-calls
782 				 * meta_back_single_dobind() */
783 				if ( meta_back_retry( op, rs, &mc, i, sendok ) ) {
784 					goto retry_ok;
785 				}
786 
787 				if ( mc != NULL ) {
788 					ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
789 					LDAP_BACK_CONN_BINDING_CLEAR( msc );
790 					meta_back_release_conn_lock( mi, mc, 0 );
791 					ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
792 				}
793 
794 				return 0;
795 			}
796 
797 			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
798 			LDAP_BACK_CONN_BINDING_CLEAR( msc );
799 			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
800 
801 			snprintf( buf, sizeof( buf ),
802 				"meta_back_dobind[%d]: (%s) err=%d (%s).",
803 				i, isroot ? op->o_bd->be_rootdn.bv_val : "anonymous",
804 				rc, ldap_err2string( rc ) );
805 			Debug( LDAP_DEBUG_ANY,
806 				"%s %s\n",
807 				op->o_log_prefix, buf, 0 );
808 
809 			/*
810 			 * null cred bind should always succeed
811 			 * as anonymous, so a failure means
812 			 * the target is no longer candidate possibly
813 			 * due to technical reasons (remote host down?)
814 			 * so better clear the handle
815 			 */
816 			/* leave the target candidate, but record the error for later use */
817 			candidates[ i ].sr_err = rc;
818 			if ( META_BACK_ONERR_STOP( mi ) ) {
819 				bound = 0;
820 				goto done;
821 			}
822 
823 			continue;
824 		} /* else */
825 
826 retry_ok:;
827 		Debug( LDAP_DEBUG_TRACE,
828 			"%s meta_back_dobind[%d]: "
829 			"(%s)\n",
830 			op->o_log_prefix, i,
831 			isroot ? op->o_bd->be_rootdn.bv_val : "anonymous" );
832 
833 		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
834 		LDAP_BACK_CONN_BINDING_CLEAR( msc );
835 		if ( isroot ) {
836 			LDAP_BACK_CONN_ISBOUND_SET( msc );
837 		} else {
838 			LDAP_BACK_CONN_ISANON_SET( msc );
839 		}
840 		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
841 		++bound;
842 	}
843 
844 done:;
845 	if ( LogTest( LDAP_DEBUG_TRACE ) ) {
846 		char buf[STRLENOF("4294967295U") + 1] = { 0 };
847 		mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
848 
849 		Debug( LDAP_DEBUG_TRACE,
850 			"%s meta_back_dobind: conn=%s bound=%d\n",
851 			op->o_log_prefix, buf, bound );
852 	}
853 
854 	if ( bound == 0 ) {
855 		meta_back_release_conn( mi, mc );
856 
857 send_err:;
858 		if ( sendok & LDAP_BACK_SENDERR ) {
859 			if ( rs->sr_err == LDAP_SUCCESS ) {
860 				rs->sr_err = LDAP_BUSY;
861 			}
862 			send_ldap_result( op, rs );
863 		}
864 
865 		return 0;
866 	}
867 
868 	return ( bound > 0 );
869 }
870 
871 /*
872  * meta_back_default_rebind
873  *
874  * This is a callback used for chasing referrals using the same
875  * credentials as the original user on this session.
876  */
877 int
878 meta_back_default_rebind(
879 	LDAP			*ld,
880 	LDAP_CONST char		*url,
881 	ber_tag_t		request,
882 	ber_int_t		msgid,
883 	void			*params )
884 {
885 	metasingleconn_t	*msc = ( metasingleconn_t * )params;
886 
887 	return ldap_sasl_bind_s( ld, msc->msc_bound_ndn.bv_val,
888 			LDAP_SASL_SIMPLE, &msc->msc_cred,
889 			NULL, NULL, NULL );
890 }
891 
892 /*
893  * meta_back_default_urllist
894  *
895  * This is a callback used for mucking with the urllist
896  */
897 int
898 meta_back_default_urllist(
899 	LDAP		*ld,
900 	LDAPURLDesc	**urllist,
901 	LDAPURLDesc	**url,
902 	void		*params )
903 {
904 	metatarget_t	*mt = (metatarget_t *)params;
905 	LDAPURLDesc	**urltail;
906 
907 	if ( urllist == url ) {
908 		return LDAP_SUCCESS;
909 	}
910 
911 	for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
912 		/* count */ ;
913 
914 	*urltail = *urllist;
915 	*urllist = *url;
916 	*url = NULL;
917 
918 	ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
919 	if ( mt->mt_uri ) {
920 		ch_free( mt->mt_uri );
921 	}
922 
923 	ldap_get_option( ld, LDAP_OPT_URI, (void *)&mt->mt_uri );
924 	ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
925 
926 	return LDAP_SUCCESS;
927 }
928 
929 int
930 meta_back_cancel(
931 	metaconn_t		*mc,
932 	Operation		*op,
933 	SlapReply		*rs,
934 	ber_int_t		msgid,
935 	int			candidate,
936 	ldap_back_send_t	sendok )
937 {
938 	metainfo_t		*mi = (metainfo_t *)op->o_bd->be_private;
939 
940 	metatarget_t		*mt = mi->mi_targets[ candidate ];
941 	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
942 
943 	int			rc = LDAP_OTHER;
944 
945 	Debug( LDAP_DEBUG_TRACE, ">>> %s meta_back_cancel[%d] msgid=%d\n",
946 		op->o_log_prefix, candidate, msgid );
947 
948 	/* default behavior */
949 	if ( META_BACK_TGT_ABANDON( mt ) ) {
950 		rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
951 
952 	} else if ( META_BACK_TGT_IGNORE( mt ) ) {
953 		rc = ldap_pvt_discard( msc->msc_ld, msgid );
954 
955 	} else if ( META_BACK_TGT_CANCEL( mt ) ) {
956 		rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL );
957 
958 	} else {
959 		assert( 0 );
960 	}
961 
962 	Debug( LDAP_DEBUG_TRACE, "<<< %s meta_back_cancel[%d] err=%d\n",
963 		op->o_log_prefix, candidate, rc );
964 
965 	return rc;
966 }
967 
968 
969 
970 /*
971  * FIXME: error return must be handled in a cleaner way ...
972  */
973 int
974 meta_back_op_result(
975 	metaconn_t		*mc,
976 	Operation		*op,
977 	SlapReply		*rs,
978 	int			candidate,
979 	ber_int_t		msgid,
980 	time_t			timeout,
981 	ldap_back_send_t	sendok )
982 {
983 	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
984 
985 	const char	*save_text = rs->sr_text,
986 			*save_matched = rs->sr_matched;
987 	BerVarray	save_ref = rs->sr_ref;
988 	LDAPControl	**save_ctrls = rs->sr_ctrls;
989 	void		*matched_ctx = NULL;
990 
991 	char		*matched = NULL;
992 	char		*text = NULL;
993 	char		**refs = NULL;
994 	LDAPControl	**ctrls = NULL;
995 
996 	assert( mc != NULL );
997 
998 	rs->sr_text = NULL;
999 	rs->sr_matched = NULL;
1000 	rs->sr_ref = NULL;
1001 	rs->sr_ctrls = NULL;
1002 
1003 	if ( candidate != META_TARGET_NONE ) {
1004 		metatarget_t		*mt = mi->mi_targets[ candidate ];
1005 		metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
1006 
1007 		if ( LDAP_ERR_OK( rs->sr_err ) ) {
1008 			int		rc;
1009 			struct timeval	tv;
1010 			LDAPMessage	*res = NULL;
1011 			time_t		stoptime = (time_t)(-1);
1012 			int		timeout_err = op->o_protocol >= LDAP_VERSION3 ?
1013 						LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
1014 			const char	*timeout_text = "Operation timed out";
1015 
1016 			/* if timeout is not specified, compute and use
1017 			 * the one specific to the ongoing operation */
1018 			if ( timeout == (time_t)(-1) ) {
1019 				slap_op_t	opidx = slap_req2op( op->o_tag );
1020 
1021 				if ( opidx == SLAP_OP_SEARCH ) {
1022 					if ( op->ors_tlimit <= 0 ) {
1023 						timeout = 0;
1024 
1025 					} else {
1026 						timeout = op->ors_tlimit;
1027 						timeout_err = LDAP_TIMELIMIT_EXCEEDED;
1028 						timeout_text = NULL;
1029 					}
1030 
1031 				} else {
1032 					timeout = mt->mt_timeout[ opidx ];
1033 				}
1034 			}
1035 
1036 			/* better than nothing :) */
1037 			if ( timeout == 0 ) {
1038 				if ( mi->mi_idle_timeout ) {
1039 					timeout = mi->mi_idle_timeout;
1040 
1041 				} else if ( mi->mi_conn_ttl ) {
1042 					timeout = mi->mi_conn_ttl;
1043 				}
1044 			}
1045 
1046 			if ( timeout ) {
1047 				stoptime = op->o_time + timeout;
1048 			}
1049 
1050 			LDAP_BACK_TV_SET( &tv );
1051 
1052 retry:;
1053 			rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
1054 			switch ( rc ) {
1055 			case 0:
1056 				if ( timeout && slap_get_time() > stoptime ) {
1057 					(void)meta_back_cancel( mc, op, rs, msgid, candidate, sendok );
1058 					rs->sr_err = timeout_err;
1059 					rs->sr_text = timeout_text;
1060 					break;
1061 				}
1062 
1063 				LDAP_BACK_TV_SET( &tv );
1064 				ldap_pvt_thread_yield();
1065 				goto retry;
1066 
1067 			case -1:
1068 				ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,
1069 						&rs->sr_err );
1070 				break;
1071 
1072 
1073 			/* otherwise get the result; if it is not
1074 			 * LDAP_SUCCESS, record it in the reply
1075 			 * structure (this includes
1076 			 * LDAP_COMPARE_{TRUE|FALSE}) */
1077 			default:
1078 				/* only touch when activity actually took place... */
1079 				if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
1080 					msc->msc_time = op->o_time;
1081 				}
1082 
1083 				rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
1084 						&matched, &text, &refs, &ctrls, 1 );
1085 				res = NULL;
1086 				if ( rc == LDAP_SUCCESS ) {
1087 					rs->sr_text = text;
1088 				} else {
1089 					rs->sr_err = rc;
1090 				}
1091 				rs->sr_err = slap_map_api2result( rs );
1092 
1093 				/* RFC 4511: referrals can only appear
1094 				 * if result code is LDAP_REFERRAL */
1095 				if ( refs != NULL
1096 					&& refs[ 0 ] != NULL
1097 					&& refs[ 0 ][ 0 ] != '\0' )
1098 				{
1099 					if ( rs->sr_err != LDAP_REFERRAL ) {
1100 						Debug( LDAP_DEBUG_ANY,
1101 							"%s meta_back_op_result[%d]: "
1102 							"got referrals with err=%d\n",
1103 							op->o_log_prefix,
1104 							candidate, rs->sr_err );
1105 
1106 					} else {
1107 						int	i;
1108 
1109 						for ( i = 0; refs[ i ] != NULL; i++ )
1110 							/* count */ ;
1111 						rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
1112 							op->o_tmpmemctx );
1113 						for ( i = 0; refs[ i ] != NULL; i++ ) {
1114 							ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
1115 						}
1116 						BER_BVZERO( &rs->sr_ref[ i ] );
1117 					}
1118 
1119 				} else if ( rs->sr_err == LDAP_REFERRAL ) {
1120 					Debug( LDAP_DEBUG_ANY,
1121 						"%s meta_back_op_result[%d]: "
1122 						"got err=%d with null "
1123 						"or empty referrals\n",
1124 						op->o_log_prefix,
1125 						candidate, rs->sr_err );
1126 
1127 					rs->sr_err = LDAP_NO_SUCH_OBJECT;
1128 				}
1129 
1130 				if ( ctrls != NULL ) {
1131 					rs->sr_ctrls = ctrls;
1132 				}
1133 			}
1134 
1135 			assert( res == NULL );
1136 		}
1137 
1138 		/* if the error in the reply structure is not
1139 		 * LDAP_SUCCESS, try to map it from client
1140 		 * to server error */
1141 		if ( !LDAP_ERR_OK( rs->sr_err ) ) {
1142 			rs->sr_err = slap_map_api2result( rs );
1143 
1144 			/* internal ops ( op->o_conn == NULL )
1145 			 * must not reply to client */
1146 			if ( op->o_conn && !op->o_do_not_cache && matched ) {
1147 
1148 				/* record the (massaged) matched
1149 				 * DN into the reply structure */
1150 				rs->sr_matched = matched;
1151 			}
1152 		}
1153 
1154 		if ( META_BACK_TGT_QUARANTINE( mt ) ) {
1155 			meta_back_quarantine( op, rs, candidate );
1156 		}
1157 
1158 	} else {
1159 		int	i,
1160 			err = rs->sr_err;
1161 
1162 		for ( i = 0; i < mi->mi_ntargets; i++ ) {
1163 			metasingleconn_t	*msc = &mc->mc_conns[ i ];
1164 			char			*xtext = NULL;
1165 			char			*xmatched = NULL;
1166 
1167 			if ( msc->msc_ld == NULL ) {
1168 				continue;
1169 			}
1170 
1171 			rs->sr_err = LDAP_SUCCESS;
1172 
1173 			ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err );
1174 			if ( rs->sr_err != LDAP_SUCCESS ) {
1175 				/*
1176 				 * better check the type of error. In some cases
1177 				 * (search ?) it might be better to return a
1178 				 * success if at least one of the targets gave
1179 				 * positive result ...
1180 				 */
1181 				ldap_get_option( msc->msc_ld,
1182 						LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext );
1183 				if ( xtext != NULL && xtext [ 0 ] == '\0' ) {
1184 					ldap_memfree( xtext );
1185 					xtext = NULL;
1186 				}
1187 
1188 				ldap_get_option( msc->msc_ld,
1189 						LDAP_OPT_MATCHED_DN, &xmatched );
1190 				if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) {
1191 					ldap_memfree( xmatched );
1192 					xmatched = NULL;
1193 				}
1194 
1195 				rs->sr_err = slap_map_api2result( rs );
1196 
1197 				if ( LogTest( LDAP_DEBUG_ANY ) ) {
1198 					char	buf[ SLAP_TEXT_BUFLEN ];
1199 
1200 					snprintf( buf, sizeof( buf ),
1201 						"meta_back_op_result[%d] "
1202 						"err=%d text=\"%s\" matched=\"%s\"",
1203 						i, rs->sr_err,
1204 						( xtext ? xtext : "" ),
1205 						( xmatched ? xmatched : "" ) );
1206 					Debug( LDAP_DEBUG_ANY, "%s %s.\n",
1207 						op->o_log_prefix, buf, 0 );
1208 				}
1209 
1210 				/*
1211 				 * FIXME: need to rewrite "match" (need rwinfo)
1212 				 */
1213 				switch ( rs->sr_err ) {
1214 				default:
1215 					err = rs->sr_err;
1216 					if ( xtext != NULL ) {
1217 						if ( text ) {
1218 							ldap_memfree( text );
1219 						}
1220 						text = xtext;
1221 						xtext = NULL;
1222 					}
1223 					if ( xmatched != NULL ) {
1224 						if ( matched ) {
1225 							ldap_memfree( matched );
1226 						}
1227 						matched = xmatched;
1228 						xmatched = NULL;
1229 					}
1230 					break;
1231 				}
1232 
1233 				if ( xtext ) {
1234 					ldap_memfree( xtext );
1235 				}
1236 
1237 				if ( xmatched ) {
1238 					ldap_memfree( xmatched );
1239 				}
1240 			}
1241 
1242 			if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
1243 				meta_back_quarantine( op, rs, i );
1244 			}
1245 		}
1246 
1247 		if ( err != LDAP_SUCCESS ) {
1248 			rs->sr_err = err;
1249 		}
1250 	}
1251 
1252 	if ( matched != NULL ) {
1253 		struct berval	dn, pdn;
1254 
1255 		ber_str2bv( matched, 0, 0, &dn );
1256 		if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
1257 			ldap_memfree( matched );
1258 			matched_ctx = op->o_tmpmemctx;
1259 			matched = pdn.bv_val;
1260 		}
1261 		rs->sr_matched = matched;
1262 	}
1263 
1264 	if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1265 		if ( !( sendok & LDAP_BACK_RETRYING ) ) {
1266 			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
1267 				if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
1268 				send_ldap_result( op, rs );
1269 			}
1270 		}
1271 
1272 	} else if ( op->o_conn &&
1273 		( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
1274 			|| ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
1275 	{
1276 		send_ldap_result( op, rs );
1277 	}
1278 	if ( matched ) {
1279 		op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
1280 	}
1281 	if ( text ) {
1282 		ldap_memfree( text );
1283 	}
1284 	if ( rs->sr_ref ) {
1285 		op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
1286 		rs->sr_ref = NULL;
1287 	}
1288 	if ( refs ) {
1289 		ber_memvfree( (void **)refs );
1290 	}
1291 	if ( ctrls ) {
1292 		assert( rs->sr_ctrls != NULL );
1293 		ldap_controls_free( ctrls );
1294 	}
1295 
1296 	rs->sr_text = save_text;
1297 	rs->sr_matched = save_matched;
1298 	rs->sr_ref = save_ref;
1299 	rs->sr_ctrls = save_ctrls;
1300 
1301 	return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
1302 }
1303 
1304 /*
1305  * meta_back_proxy_authz_cred()
1306  *
1307  * prepares credentials & method for meta_back_proxy_authz_bind();
1308  * or, if method is SASL, performs the SASL bind directly.
1309  */
1310 int
1311 meta_back_proxy_authz_cred(
1312 	metaconn_t		*mc,
1313 	int			candidate,
1314 	Operation		*op,
1315 	SlapReply		*rs,
1316 	ldap_back_send_t	sendok,
1317 	struct berval		*binddn,
1318 	struct berval		*bindcred,
1319 	int			*method )
1320 {
1321 	metainfo_t		*mi = (metainfo_t *)op->o_bd->be_private;
1322 	metatarget_t		*mt = mi->mi_targets[ candidate ];
1323 	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
1324 	struct berval		ndn;
1325 	int			dobind = 0;
1326 
1327 	/* don't proxyAuthz if protocol is not LDAPv3 */
1328 	switch ( mt->mt_version ) {
1329 	case LDAP_VERSION3:
1330 		break;
1331 
1332 	case 0:
1333 		if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
1334 			break;
1335 		}
1336 		/* fall thru */
1337 
1338 	default:
1339 		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1340 		if ( sendok & LDAP_BACK_SENDERR ) {
1341 			send_ldap_result( op, rs );
1342 		}
1343 		LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1344 		goto done;
1345 	}
1346 
1347 	if ( op->o_tag == LDAP_REQ_BIND ) {
1348 		ndn = op->o_req_ndn;
1349 
1350 	} else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
1351 		ndn = op->o_conn->c_ndn;
1352 
1353 	} else {
1354 		ndn = op->o_ndn;
1355 	}
1356 	rs->sr_err = LDAP_SUCCESS;
1357 
1358 	/*
1359 	 * FIXME: we need to let clients use proxyAuthz
1360 	 * otherwise we cannot do symmetric pools of servers;
1361 	 * we have to live with the fact that a user can
1362 	 * authorize itself as any ID that is allowed
1363 	 * by the authzTo directive of the "proxyauthzdn".
1364 	 */
1365 	/*
1366 	 * NOTE: current Proxy Authorization specification
1367 	 * and implementation do not allow proxy authorization
1368 	 * control to be provided with Bind requests
1369 	 */
1370 	/*
1371 	 * if no bind took place yet, but the connection is bound
1372 	 * and the "proxyauthzdn" is set, then bind as
1373 	 * "proxyauthzdn" and explicitly add the proxyAuthz
1374 	 * control to every operation with the dn bound
1375 	 * to the connection as control value.
1376 	 */
1377 
1378 	/* bind as proxyauthzdn only if no idassert mode
1379 	 * is requested, or if the client's identity
1380 	 * is authorized */
1381 	switch ( mt->mt_idassert_mode ) {
1382 	case LDAP_BACK_IDASSERT_LEGACY:
1383 		if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
1384 			if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) && !BER_BVISEMPTY( &mt->mt_idassert_authcDN ) )
1385 			{
1386 				*binddn = mt->mt_idassert_authcDN;
1387 				*bindcred = mt->mt_idassert_passwd;
1388 				dobind = 1;
1389 			}
1390 		}
1391 		break;
1392 
1393 	default:
1394 		/* NOTE: rootdn can always idassert */
1395 		if ( BER_BVISNULL( &ndn )
1396 			&& mt->mt_idassert_authz == NULL
1397 			&& !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
1398 		{
1399 			if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1400 				rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1401 				if ( sendok & LDAP_BACK_SENDERR ) {
1402 					send_ldap_result( op, rs );
1403 				}
1404 				LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1405 				goto done;
1406 
1407 			}
1408 
1409 			rs->sr_err = LDAP_SUCCESS;
1410 			*binddn = slap_empty_bv;
1411 			*bindcred = slap_empty_bv;
1412 			break;
1413 
1414 		} else if ( mt->mt_idassert_authz && !be_isroot( op ) ) {
1415 			struct berval authcDN;
1416 
1417 			if ( BER_BVISNULL( &ndn ) ) {
1418 				authcDN = slap_empty_bv;
1419 
1420 			} else {
1421 				authcDN = ndn;
1422 			}
1423 			rs->sr_err = slap_sasl_matches( op, mt->mt_idassert_authz,
1424 					&authcDN, &authcDN );
1425 			if ( rs->sr_err != LDAP_SUCCESS ) {
1426 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1427 					if ( sendok & LDAP_BACK_SENDERR ) {
1428 						send_ldap_result( op, rs );
1429 					}
1430 					LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1431 					goto done;
1432 				}
1433 
1434 				rs->sr_err = LDAP_SUCCESS;
1435 				*binddn = slap_empty_bv;
1436 				*bindcred = slap_empty_bv;
1437 				break;
1438 			}
1439 		}
1440 
1441 		*binddn = mt->mt_idassert_authcDN;
1442 		*bindcred = mt->mt_idassert_passwd;
1443 		dobind = 1;
1444 		break;
1445 	}
1446 
1447 	if ( dobind && mt->mt_idassert_authmethod == LDAP_AUTH_SASL ) {
1448 #ifdef HAVE_CYRUS_SASL
1449 		void		*defaults = NULL;
1450 		struct berval	authzID = BER_BVNULL;
1451 		int		freeauthz = 0;
1452 
1453 		/* if SASL supports native authz, prepare for it */
1454 		if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
1455 				( mt->mt_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
1456 		{
1457 			switch ( mt->mt_idassert_mode ) {
1458 			case LDAP_BACK_IDASSERT_OTHERID:
1459 			case LDAP_BACK_IDASSERT_OTHERDN:
1460 				authzID = mt->mt_idassert_authzID;
1461 				break;
1462 
1463 			case LDAP_BACK_IDASSERT_ANONYMOUS:
1464 				BER_BVSTR( &authzID, "dn:" );
1465 				break;
1466 
1467 			case LDAP_BACK_IDASSERT_SELF:
1468 				if ( BER_BVISNULL( &ndn ) ) {
1469 					/* connection is not authc'd, so don't idassert */
1470 					BER_BVSTR( &authzID, "dn:" );
1471 					break;
1472 				}
1473 				authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
1474 				authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
1475 				AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
1476 				AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
1477 						ndn.bv_val, ndn.bv_len + 1 );
1478 				freeauthz = 1;
1479 				break;
1480 
1481 			default:
1482 				break;
1483 			}
1484 		}
1485 
1486 		if ( mt->mt_idassert_secprops != NULL ) {
1487 			rs->sr_err = ldap_set_option( msc->msc_ld,
1488 				LDAP_OPT_X_SASL_SECPROPS,
1489 				(void *)mt->mt_idassert_secprops );
1490 
1491 			if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
1492 				rs->sr_err = LDAP_OTHER;
1493 				if ( sendok & LDAP_BACK_SENDERR ) {
1494 					send_ldap_result( op, rs );
1495 				}
1496 				LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1497 				goto done;
1498 			}
1499 		}
1500 
1501 		defaults = lutil_sasl_defaults( msc->msc_ld,
1502 				mt->mt_idassert_sasl_mech.bv_val,
1503 				mt->mt_idassert_sasl_realm.bv_val,
1504 				mt->mt_idassert_authcID.bv_val,
1505 				mt->mt_idassert_passwd.bv_val,
1506 				authzID.bv_val );
1507 		if ( defaults == NULL ) {
1508 			rs->sr_err = LDAP_OTHER;
1509 			LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1510 			if ( sendok & LDAP_BACK_SENDERR ) {
1511 				send_ldap_result( op, rs );
1512 			}
1513 			goto done;
1514 		}
1515 
1516 		rs->sr_err = ldap_sasl_interactive_bind_s( msc->msc_ld, binddn->bv_val,
1517 				mt->mt_idassert_sasl_mech.bv_val, NULL, NULL,
1518 				LDAP_SASL_QUIET, lutil_sasl_interact,
1519 				defaults );
1520 
1521 		rs->sr_err = slap_map_api2result( rs );
1522 		if ( rs->sr_err != LDAP_SUCCESS ) {
1523 			LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1524 			if ( sendok & LDAP_BACK_SENDERR ) {
1525 				send_ldap_result( op, rs );
1526 			}
1527 
1528 		} else {
1529 			LDAP_BACK_CONN_ISBOUND_SET( msc );
1530 		}
1531 
1532 		lutil_sasl_freedefs( defaults );
1533 		if ( freeauthz ) {
1534 			slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
1535 		}
1536 
1537 		goto done;
1538 #endif /* HAVE_CYRUS_SASL */
1539 	}
1540 
1541 	*method = mt->mt_idassert_authmethod;
1542 	switch ( mt->mt_idassert_authmethod ) {
1543 	case LDAP_AUTH_NONE:
1544 		BER_BVSTR( binddn, "" );
1545 		BER_BVSTR( bindcred, "" );
1546 		/* fallthru */
1547 
1548 	case LDAP_AUTH_SIMPLE:
1549 		break;
1550 
1551 	default:
1552 		/* unsupported! */
1553 		LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1554 		rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
1555 		if ( sendok & LDAP_BACK_SENDERR ) {
1556 			send_ldap_result( op, rs );
1557 		}
1558 		break;
1559 	}
1560 
1561 done:;
1562 
1563 	if ( !BER_BVISEMPTY( binddn ) ) {
1564 		LDAP_BACK_CONN_ISIDASSERT_SET( msc );
1565 	}
1566 
1567 	return rs->sr_err;
1568 }
1569 
1570 static int
1571 meta_back_proxy_authz_bind(
1572 	metaconn_t *mc,
1573 	int candidate,
1574 	Operation *op,
1575 	SlapReply *rs,
1576 	ldap_back_send_t sendok,
1577 	int dolock )
1578 {
1579 	metainfo_t		*mi = (metainfo_t *)op->o_bd->be_private;
1580 	metatarget_t		*mt = mi->mi_targets[ candidate ];
1581 	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
1582 	struct berval		binddn = BER_BVC( "" ),
1583 				cred = BER_BVC( "" );
1584 	int			method = LDAP_AUTH_NONE,
1585 				rc;
1586 
1587 	rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, sendok, &binddn, &cred, &method );
1588 	if ( rc == LDAP_SUCCESS && !LDAP_BACK_CONN_ISBOUND( msc ) ) {
1589 		int	msgid;
1590 
1591 		switch ( method ) {
1592 		case LDAP_AUTH_NONE:
1593 		case LDAP_AUTH_SIMPLE:
1594 
1595 			if(!dolock) {
1596 				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1597 			}
1598 
1599 			for (;;) {
1600 				rs->sr_err = ldap_sasl_bind( msc->msc_ld,
1601 					binddn.bv_val, LDAP_SASL_SIMPLE,
1602 					&cred, NULL, NULL, &msgid );
1603 				if ( rs->sr_err != LDAP_X_CONNECTING ) {
1604 					break;
1605 				}
1606 				ldap_pvt_thread_yield();
1607 			}
1608 
1609 			if(!dolock) {
1610 				ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1611 			}
1612 
1613 			rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
1614 			if ( rc == LDAP_SUCCESS ) {
1615 				/* set rebind stuff in case of successful proxyAuthz bind,
1616 				 * so that referral chasing is attempted using the right
1617 				 * identity */
1618 				LDAP_BACK_CONN_ISBOUND_SET( msc );
1619 				ber_bvreplace( &msc->msc_bound_ndn, &binddn );
1620 
1621 				if ( META_BACK_TGT_SAVECRED( mt ) ) {
1622 					if ( !BER_BVISNULL( &msc->msc_cred ) ) {
1623 						memset( msc->msc_cred.bv_val, 0,
1624 							msc->msc_cred.bv_len );
1625 					}
1626 					ber_bvreplace( &msc->msc_cred, &cred );
1627 					ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
1628 				}
1629 			}
1630 			break;
1631 
1632 		default:
1633 			assert( 0 );
1634 			break;
1635 		}
1636 	}
1637 
1638 	return LDAP_BACK_CONN_ISBOUND( msc );
1639 }
1640 
1641 /*
1642  * Add controls;
1643  *
1644  * if any needs to be added, it is prepended to existing ones,
1645  * in a newly allocated array.  The companion function
1646  * mi->mi_ldap_extra->controls_free() must be used to restore the original
1647  * status of op->o_ctrls.
1648  */
1649 int
1650 meta_back_controls_add(
1651 		Operation	*op,
1652 		SlapReply	*rs,
1653 		metaconn_t	*mc,
1654 		int		candidate,
1655 		LDAPControl	***pctrls )
1656 {
1657 	metainfo_t		*mi = (metainfo_t *)op->o_bd->be_private;
1658 	metatarget_t		*mt = mi->mi_targets[ candidate ];
1659 	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
1660 
1661 	LDAPControl		**ctrls = NULL;
1662 	/* set to the maximum number of controls this backend can add */
1663 	LDAPControl		c[ 2 ] = {{ 0 }};
1664 	int			n = 0, i, j1 = 0, j2 = 0;
1665 
1666 	*pctrls = NULL;
1667 
1668 	rs->sr_err = LDAP_SUCCESS;
1669 
1670 	/* don't add controls if protocol is not LDAPv3 */
1671 	switch ( mt->mt_version ) {
1672 	case LDAP_VERSION3:
1673 		break;
1674 
1675 	case 0:
1676 		if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
1677 			break;
1678 		}
1679 		/* fall thru */
1680 
1681 	default:
1682 		goto done;
1683 	}
1684 
1685 	/* put controls that go __before__ existing ones here */
1686 
1687 	/* proxyAuthz for identity assertion */
1688 	switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn,
1689 		mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) )
1690 	{
1691 	case SLAP_CB_CONTINUE:
1692 		break;
1693 
1694 	case LDAP_SUCCESS:
1695 		j1++;
1696 		break;
1697 
1698 	default:
1699 		goto done;
1700 	}
1701 
1702 	/* put controls that go __after__ existing ones here */
1703 
1704 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1705 	/* session tracking */
1706 	if ( META_BACK_TGT_ST_REQUEST( mt ) ) {
1707 		switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) {
1708 		case SLAP_CB_CONTINUE:
1709 			break;
1710 
1711 		case LDAP_SUCCESS:
1712 			j2++;
1713 			break;
1714 
1715 		default:
1716 			goto done;
1717 		}
1718 	}
1719 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1720 
1721 	if ( rs->sr_err == SLAP_CB_CONTINUE ) {
1722 		rs->sr_err = LDAP_SUCCESS;
1723 	}
1724 
1725 	/* if nothing to do, just bail out */
1726 	if ( j1 == 0 && j2 == 0 ) {
1727 		goto done;
1728 	}
1729 
1730 	assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) );
1731 
1732 	if ( op->o_ctrls ) {
1733 		for ( n = 0; op->o_ctrls[ n ]; n++ )
1734 			/* just count ctrls */ ;
1735 	}
1736 
1737 	ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ),
1738 			op->o_tmpmemctx );
1739 	if ( j1 ) {
1740 		ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
1741 		*ctrls[ 0 ] = c[ 0 ];
1742 		for ( i = 1; i < j1; i++ ) {
1743 			ctrls[ i ] = &ctrls[ 0 ][ i ];
1744 			*ctrls[ i ] = c[ i ];
1745 		}
1746 	}
1747 
1748 	i = 0;
1749 	if ( op->o_ctrls ) {
1750 		for ( i = 0; op->o_ctrls[ i ]; i++ ) {
1751 			ctrls[ i + j1 ] = op->o_ctrls[ i ];
1752 		}
1753 	}
1754 
1755 	n += j1;
1756 	if ( j2 ) {
1757 		ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1;
1758 		*ctrls[ n ] = c[ j1 ];
1759 		for ( i = 1; i < j2; i++ ) {
1760 			ctrls[ n + i ] = &ctrls[ n ][ i ];
1761 			*ctrls[ n + i ] = c[ i ];
1762 		}
1763 	}
1764 
1765 	ctrls[ n + j2 ] = NULL;
1766 
1767 done:;
1768 	if ( ctrls == NULL ) {
1769 		ctrls = op->o_ctrls;
1770 	}
1771 
1772 	*pctrls = ctrls;
1773 
1774 	return rs->sr_err;
1775 }
1776 
1777