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