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