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