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