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