xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-ldap/bind.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: bind.c,v 1.1.1.6 2018/02/06 01:53:17 christos Exp $	*/
2 
3 /* bind.c - ldap backend bind function */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1999-2017 The OpenLDAP Foundation.
8  * Portions Copyright 2000-2003 Pierangelo Masarati.
9  * Portions Copyright 1999-2003 Howard Chu.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* ACKNOWLEDGEMENTS:
21  * This work was initially developed by Howard Chu for inclusion
22  * in OpenLDAP Software and subsequently enhanced by Pierangelo
23  * Masarati.
24  */
25 
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: bind.c,v 1.1.1.6 2018/02/06 01:53:17 christos Exp $");
28 
29 #include "portable.h"
30 
31 #include <stdio.h>
32 
33 #include <ac/errno.h>
34 #include <ac/socket.h>
35 #include <ac/string.h>
36 
37 #define AVL_INTERNAL
38 #include "slap.h"
39 #include "back-ldap.h"
40 #include "lutil.h"
41 #include "lutil_ldap.h"
42 
43 #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ	"2.16.840.1.113730.3.4.12"
44 
45 #ifdef LDAP_DEVEL
46 #define SLAP_AUTH_DN 1
47 #endif
48 
49 #if LDAP_BACK_PRINT_CONNTREE > 0
50 
51 static const struct {
52 	slap_mask_t	f;
53 	char		c;
54 } flagsmap[] = {
55 	{ LDAP_BACK_FCONN_ISBOUND,	'B' },
56 	{ LDAP_BACK_FCONN_ISANON,	'A' },
57 	{ LDAP_BACK_FCONN_ISPRIV,	'P' },
58 	{ LDAP_BACK_FCONN_ISTLS,	'T' },
59 	{ LDAP_BACK_FCONN_BINDING,	'X' },
60 	{ LDAP_BACK_FCONN_TAINTED,	'E' },
61 	{ LDAP_BACK_FCONN_ABANDON,	'N' },
62 	{ LDAP_BACK_FCONN_ISIDASR,	'S' },
63 	{ LDAP_BACK_FCONN_CACHED,	'C' },
64 	{ 0,				'\0' }
65 };
66 
67 static void
68 ldap_back_conn_print( ldapconn_t *lc, const char *avlstr )
69 {
70 	char buf[ SLAP_TEXT_BUFLEN ];
71 	char fbuf[ sizeof("BAPTIENSC") ];
72 	int i;
73 
74 	ldap_back_conn2str( &lc->lc_base, buf, sizeof( buf ) );
75 	for ( i = 0; flagsmap[ i ].c != '\0'; i++ ) {
76 		if ( lc->lc_lcflags & flagsmap[i].f ) {
77 			fbuf[i] = flagsmap[i].c;
78 
79 		} else {
80 			fbuf[i] = '.';
81 		}
82 	}
83 	fbuf[i] = '\0';
84 
85 	fprintf( stderr, "lc=%p %s %s flags=0x%08x (%s)\n",
86 		(void *)lc, buf, avlstr, lc->lc_lcflags, fbuf );
87 }
88 
89 static void
90 ldap_back_ravl_print( Avlnode *root, int depth )
91 {
92 	int		i;
93 	ldapconn_t	*lc;
94 
95 	if ( root == 0 ) {
96 		return;
97 	}
98 
99 	ldap_back_ravl_print( root->avl_right, depth+1 );
100 
101 	for ( i = 0; i < depth; i++ ) {
102 		fprintf( stderr, "-" );
103 	}
104 
105 	lc = root->avl_data;
106 	ldap_back_conn_print( lc, avl_bf2str( root->avl_bf ) );
107 
108 	ldap_back_ravl_print( root->avl_left, depth + 1 );
109 }
110 
111 static char* priv2str[] = {
112 	"privileged",
113 	"privileged/TLS",
114 	"anonymous",
115 	"anonymous/TLS",
116 	"bind",
117 	"bind/TLS",
118 	NULL
119 };
120 
121 void
122 ldap_back_print_conntree( ldapinfo_t *li, char *msg )
123 {
124 	int	c;
125 
126 	fprintf( stderr, "========> %s\n", msg );
127 
128 	for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
129 		int		i = 0;
130 		ldapconn_t	*lc;
131 
132 		fprintf( stderr, "  %s[%d]\n", priv2str[ c ], li->li_conn_priv[ c ].lic_num );
133 
134 		LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q )
135 		{
136 			fprintf( stderr, "    [%d] ", i );
137 			ldap_back_conn_print( lc, "" );
138 			i++;
139 		}
140 	}
141 
142 	if ( li->li_conninfo.lai_tree == 0 ) {
143 		fprintf( stderr, "\t(empty)\n" );
144 
145 	} else {
146 		ldap_back_ravl_print( li->li_conninfo.lai_tree, 0 );
147 	}
148 
149 	fprintf( stderr, "<======== %s\n", msg );
150 }
151 #endif /* LDAP_BACK_PRINT_CONNTREE */
152 
153 static int
154 ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock );
155 
156 static ldapconn_t *
157 ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
158 	struct berval *binddn, struct berval *bindcred );
159 
160 static int
161 ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
162 	struct berval *binddn, struct berval *bindcred );
163 
164 static int
165 ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs,
166 	ldap_back_send_t sendok, struct berval *binddn, struct berval *bindcred );
167 
168 static int
169 ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs,
170 	ldap_back_send_t sendok );
171 
172 static int
173 ldap_back_conndnlc_cmp( const void *c1, const void *c2 );
174 
175 ldapconn_t *
176 ldap_back_conn_delete( ldapinfo_t *li, ldapconn_t *lc )
177 {
178 	if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
179 		if ( LDAP_BACK_CONN_CACHED( lc ) ) {
180 			assert( lc->lc_q.tqe_prev != NULL );
181 			assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
182 			li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
183 			LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
184 			LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
185 			LDAP_BACK_CONN_CACHED_CLEAR( lc );
186 
187 		} else {
188 			assert( LDAP_BACK_CONN_TAINTED( lc ) );
189 			assert( lc->lc_q.tqe_prev == NULL );
190 		}
191 
192 	} else {
193 		ldapconn_t	*tmplc = NULL;
194 
195 		if ( LDAP_BACK_CONN_CACHED( lc ) ) {
196 			assert( !LDAP_BACK_CONN_TAINTED( lc ) );
197 			tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
198 				ldap_back_conndnlc_cmp );
199 			assert( tmplc == lc );
200 			LDAP_BACK_CONN_CACHED_CLEAR( lc );
201 		}
202 
203 		assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
204 	}
205 
206 	return lc;
207 }
208 
209 int
210 ldap_back_bind( Operation *op, SlapReply *rs )
211 {
212 	ldapinfo_t		*li = (ldapinfo_t *) op->o_bd->be_private;
213 	ldapconn_t		*lc;
214 
215 	LDAPControl		**ctrls = NULL;
216 	struct berval		save_o_dn;
217 	int			save_o_do_not_cache,
218 				rc = 0;
219 	ber_int_t		msgid;
220 	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
221 
222 	/* allow rootdn as a means to auth without the need to actually
223  	 * contact the proxied DSA */
224 	switch ( be_rootdn_bind( op, rs ) ) {
225 	case SLAP_CB_CONTINUE:
226 		break;
227 
228 	default:
229 		return rs->sr_err;
230 	}
231 
232 	lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );
233 	if ( !lc ) {
234 		return rs->sr_err;
235 	}
236 
237 	/* we can do (almost) whatever we want with this conn,
238 	 * because either it's temporary, or it's marked as binding */
239 	if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
240 		ch_free( lc->lc_bound_ndn.bv_val );
241 		BER_BVZERO( &lc->lc_bound_ndn );
242 	}
243 	if ( !BER_BVISNULL( &lc->lc_cred ) ) {
244 		memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len );
245 		ch_free( lc->lc_cred.bv_val );
246 		BER_BVZERO( &lc->lc_cred );
247 	}
248 	LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
249 
250 	/* don't add proxyAuthz; set the bindDN */
251 	save_o_dn = op->o_dn;
252 	save_o_do_not_cache = op->o_do_not_cache;
253 	op->o_dn = op->o_req_dn;
254 	op->o_do_not_cache = 1;
255 
256 	ctrls = op->o_ctrls;
257 	rc = ldap_back_controls_add( op, rs, lc, &ctrls );
258 	op->o_dn = save_o_dn;
259 	op->o_do_not_cache = save_o_do_not_cache;
260 	if ( rc != LDAP_SUCCESS ) {
261 		send_ldap_result( op, rs );
262 		ldap_back_release_conn( li, lc );
263 		return( rc );
264 	}
265 
266 retry:;
267 	/* method is always LDAP_AUTH_SIMPLE if we got here */
268 	rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
269 			LDAP_SASL_SIMPLE,
270 			&op->orb_cred, ctrls, NULL, &msgid );
271 	/* FIXME: should we always retry, or only when piping the bind
272 	 * in the "override" connection pool? */
273 	rc = ldap_back_op_result( lc, op, rs, msgid,
274 		li->li_timeout[ SLAP_OP_BIND ],
275 		LDAP_BACK_BIND_SERR | retrying );
276 	if ( rc == LDAP_UNAVAILABLE && retrying ) {
277 		retrying &= ~LDAP_BACK_RETRYING;
278 		if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_BIND_SERR ) ) {
279 			goto retry;
280 		}
281 		if ( !lc )
282 			return( rc );
283 	}
284 
285 	ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
286 	ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
287 	ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
288 
289 	ldap_back_controls_free( op, rs, &ctrls );
290 
291 	if ( rc == LDAP_SUCCESS ) {
292 		op->o_conn->c_authz_cookie = op->o_bd->be_private;
293 
294 		/* If defined, proxyAuthz will be used also when
295 		 * back-ldap is the authorizing backend; for this
296 		 * purpose, after a successful bind the connection
297 		 * is left for further binds, and further operations
298 		 * on this client connection will use a default
299 		 * connection with identity assertion */
300 		/* NOTE: use with care */
301 		if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
302 			ldap_back_release_conn( li, lc );
303 			return( rc );
304 		}
305 
306 		/* rebind is now done inside ldap_back_proxy_authz_bind()
307 		 * in case of success */
308 		LDAP_BACK_CONN_ISBOUND_SET( lc );
309 		ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
310 
311 		if ( !BER_BVISNULL( &lc->lc_cred ) ) {
312 			memset( lc->lc_cred.bv_val, 0,
313 					lc->lc_cred.bv_len );
314 		}
315 
316 		if ( LDAP_BACK_SAVECRED( li ) ) {
317 			ber_bvreplace( &lc->lc_cred, &op->orb_cred );
318 			ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
319 
320 		} else {
321 			lc->lc_cred.bv_len = 0;
322 		}
323 	}
324 
325 	/* must re-insert if local DN changed as result of bind */
326 	if ( !LDAP_BACK_CONN_ISBOUND( lc )
327 		|| ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )
328 			&& !LDAP_BACK_PCONN_ISPRIV( lc ) ) )
329 	{
330 		int		lerr = -1;
331 		ldapconn_t	*tmplc;
332 
333 		/* wait for all other ops to release the connection */
334 retry_lock:;
335 		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
336 		if ( lc->lc_refcnt > 1 ) {
337 			ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
338 			ldap_pvt_thread_yield();
339 			goto retry_lock;
340 		}
341 
342 #if LDAP_BACK_PRINT_CONNTREE > 0
343 		ldap_back_print_conntree( li, ">>> ldap_back_bind" );
344 #endif /* LDAP_BACK_PRINT_CONNTREE */
345 
346 		assert( lc->lc_refcnt == 1 );
347 		ldap_back_conn_delete( li, lc );
348 
349 		/* delete all cached connections with the current connection */
350 		if ( LDAP_BACK_SINGLECONN( li ) ) {
351 			while ( ( tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )
352 			{
353 				assert( !LDAP_BACK_PCONN_ISPRIV( lc ) );
354 				Debug( LDAP_DEBUG_TRACE,
355 					"=>ldap_back_bind: destroying conn %lu (refcnt=%u)\n",
356 					lc->lc_conn->c_connid, lc->lc_refcnt, 0 );
357 
358 				if ( tmplc->lc_refcnt != 0 ) {
359 					/* taint it */
360 					LDAP_BACK_CONN_TAINTED_SET( tmplc );
361 					LDAP_BACK_CONN_CACHED_CLEAR( tmplc );
362 
363 				} else {
364 					/*
365 					 * Needs a test because the handler may be corrupted,
366 					 * and calling ldap_unbind on a corrupted header results
367 					 * in a segmentation fault
368 					 */
369 					ldap_back_conn_free( tmplc );
370 				}
371 			}
372 		}
373 
374 		if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
375 			ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
376 			if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
377 				LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
378 			}
379 			lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
380 				ldap_back_conndn_cmp, ldap_back_conndn_dup );
381 		}
382 
383 #if LDAP_BACK_PRINT_CONNTREE > 0
384 		ldap_back_print_conntree( li, "<<< ldap_back_bind" );
385 #endif /* LDAP_BACK_PRINT_CONNTREE */
386 
387 		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
388 		switch ( lerr ) {
389 		case 0:
390 			LDAP_BACK_CONN_CACHED_SET( lc );
391 			break;
392 
393 		case -1:
394 			/* duplicate; someone else successfully bound
395 			 * on the same connection with the same identity;
396 			 * we can do this because lc_refcnt == 1 */
397 			ldap_back_conn_free( lc );
398 			lc = NULL;
399 		}
400 	}
401 
402 	if ( lc != NULL ) {
403 		ldap_back_release_conn( li, lc );
404 	}
405 
406 	return( rc );
407 }
408 
409 /*
410  * ldap_back_conndn_cmp
411  *
412  * compares two ldapconn_t based on the value of the conn pointer
413  * and of the local DN; used by avl stuff for insert, lookup
414  * and direct delete
415  */
416 int
417 ldap_back_conndn_cmp( const void *c1, const void *c2 )
418 {
419 	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;
420 	const ldapconn_t	*lc2 = (const ldapconn_t *)c2;
421 	int rc;
422 
423 	/* If local DNs don't match, it is definitely not a match */
424 	/* For shared sessions, conn is NULL. Only explicitly
425 	 * bound sessions will have non-NULL conn.
426 	 */
427 	rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
428 	if ( rc == 0 ) {
429 		rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
430 	}
431 
432 	return rc;
433 }
434 
435 /*
436  * ldap_back_conndnlc_cmp
437  *
438  * compares two ldapconn_t based on the value of the conn pointer,
439  * the local DN and the lc pointer; used by avl stuff for insert, lookup
440  * and direct delete
441  */
442 static int
443 ldap_back_conndnlc_cmp( const void *c1, const void *c2 )
444 {
445 	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;
446 	const ldapconn_t	*lc2 = (const ldapconn_t *)c2;
447 	int rc;
448 
449 	/* If local DNs don't match, it is definitely not a match */
450 	/* For shared sessions, conn is NULL. Only explicitly
451 	 * bound sessions will have non-NULL conn.
452 	 */
453 	rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
454 	if ( rc == 0 ) {
455 		rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
456 		if ( rc == 0 ) {
457 			rc = SLAP_PTRCMP( lc1, lc2 );
458 		}
459 	}
460 
461 	return rc;
462 }
463 
464 /*
465  * ldap_back_conn_cmp
466  *
467  * compares two ldapconn_t based on the value of the conn pointer;
468  * used by avl stuff for delete of all conns with the same connid
469  */
470 int
471 ldap_back_conn_cmp( const void *c1, const void *c2 )
472 {
473 	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;
474 	const ldapconn_t	*lc2 = (const ldapconn_t *)c2;
475 
476 	/* For shared sessions, conn is NULL. Only explicitly
477 	 * bound sessions will have non-NULL conn.
478 	 */
479 	return SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
480 }
481 
482 /*
483  * ldap_back_conndn_dup
484  *
485  * returns -1 in case a duplicate ldapconn_t has been inserted;
486  * used by avl stuff
487  */
488 int
489 ldap_back_conndn_dup( void *c1, void *c2 )
490 {
491 	ldapconn_t	*lc1 = (ldapconn_t *)c1;
492 	ldapconn_t	*lc2 = (ldapconn_t *)c2;
493 
494 	/* Cannot have more than one shared session with same DN */
495 	if ( lc1->lc_conn == lc2->lc_conn &&
496 		dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) )
497 	{
498 		return -1;
499 	}
500 
501 	return 0;
502 }
503 
504 static int
505 ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock )
506 {
507 	if ( dolock ) {
508 		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
509 	}
510 
511 #if LDAP_BACK_PRINT_CONNTREE > 0
512 	ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );
513 #endif /* LDAP_BACK_PRINT_CONNTREE */
514 
515 	(void)ldap_back_conn_delete( li, lc );
516 
517 	if ( lc->lc_refcnt == 0 ) {
518 		ldap_back_conn_free( (void *)lc );
519 	}
520 
521 #if LDAP_BACK_PRINT_CONNTREE > 0
522 	ldap_back_print_conntree( li, "<<< ldap_back_freeconn" );
523 #endif /* LDAP_BACK_PRINT_CONNTREE */
524 
525 	if ( dolock ) {
526 		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
527 	}
528 
529 	return 0;
530 }
531 
532 #ifdef HAVE_TLS
533 static int
534 ldap_back_start_tls(
535 	LDAP		*ld,
536 	int		protocol,
537 	int		*is_tls,
538 	const char	*url,
539 	unsigned	flags,
540 	int		retries,
541 	const char	**text )
542 {
543 	int		rc = LDAP_SUCCESS;
544 
545 	/* start TLS ("tls-[try-]{start,propagate}" statements) */
546 	if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )
547 				&& !ldap_is_ldaps_url( url ) )
548 	{
549 #ifdef SLAP_STARTTLS_ASYNCHRONOUS
550 		/*
551 		 * use asynchronous StartTLS
552 		 * in case, chase referral (not implemented yet)
553 		 */
554 		int		msgid;
555 
556 		if ( protocol == 0 ) {
557 			ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION,
558 					(void *)&protocol );
559 		}
560 
561 		if ( protocol < LDAP_VERSION3 ) {
562 			/* we should rather bail out... */
563 			rc = LDAP_UNWILLING_TO_PERFORM;
564 			*text = "invalid protocol version";
565 		}
566 
567 		if ( rc == LDAP_SUCCESS ) {
568 			rc = ldap_start_tls( ld, NULL, NULL, &msgid );
569 		}
570 
571 		if ( rc == LDAP_SUCCESS ) {
572 			LDAPMessage	*res = NULL;
573 			struct timeval	tv;
574 
575 			LDAP_BACK_TV_SET( &tv );
576 
577 retry:;
578 			rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
579 			if ( rc < 0 ) {
580 				rc = LDAP_UNAVAILABLE;
581 
582 			} else if ( rc == 0 ) {
583 				if ( retries != LDAP_BACK_RETRY_NEVER ) {
584 					ldap_pvt_thread_yield();
585 					if ( retries > 0 ) {
586 						retries--;
587 					}
588 					LDAP_BACK_TV_SET( &tv );
589 					goto retry;
590 				}
591 				rc = LDAP_UNAVAILABLE;
592 
593 			} else if ( rc == LDAP_RES_EXTENDED ) {
594 				struct berval	*data = NULL;
595 
596 				rc = ldap_parse_extended_result( ld, res,
597 						NULL, &data, 0 );
598 				if ( rc == LDAP_SUCCESS ) {
599 					SlapReply rs;
600 					rc = ldap_parse_result( ld, res, &rs.sr_err,
601 						NULL, NULL, NULL, NULL, 1 );
602 					if ( rc != LDAP_SUCCESS ) {
603 						rs.sr_err = rc;
604 					}
605 					rc = slap_map_api2result( &rs );
606 					res = NULL;
607 
608 					/* FIXME: in case a referral
609 					 * is returned, should we try
610 					 * using it instead of the
611 					 * configured URI? */
612 					if ( rc == LDAP_SUCCESS ) {
613 						rc = ldap_install_tls( ld );
614 
615 					} else if ( rc == LDAP_REFERRAL ) {
616 						rc = LDAP_UNWILLING_TO_PERFORM;
617 						*text = "unwilling to chase referral returned by Start TLS exop";
618 					}
619 
620 					if ( data ) {
621 						if ( data->bv_val ) {
622 							ber_memfree( data->bv_val );
623 						}
624 						ber_memfree( data );
625 					}
626 				}
627 
628 			} else {
629 				rc = LDAP_OTHER;
630 			}
631 
632 			if ( res != NULL ) {
633 				ldap_msgfree( res );
634 			}
635 		}
636 #else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
637 		/*
638 		 * use synchronous StartTLS
639 		 */
640 		rc = ldap_start_tls_s( ld, NULL, NULL );
641 #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
642 
643 		/* if StartTLS is requested, only attempt it if the URL
644 		 * is not "ldaps://"; this may occur not only in case
645 		 * of misconfiguration, but also when used in the chain
646 		 * overlay, where the "uri" can be parsed out of a referral */
647 		switch ( rc ) {
648 		case LDAP_SUCCESS:
649 			*is_tls = 1;
650 			break;
651 
652 		case LDAP_SERVER_DOWN:
653 			break;
654 
655 		default:
656 			if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
657 				*text = "could not start TLS";
658 				break;
659 			}
660 
661 			/* in case Start TLS is not critical */
662 			*is_tls = 0;
663 			rc = LDAP_SUCCESS;
664 			break;
665 		}
666 
667 	} else {
668 		*is_tls = 0;
669 	}
670 
671 	return rc;
672 }
673 #endif /* HAVE_TLS */
674 
675 static int
676 ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
677 {
678 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
679 	int		version;
680 	LDAP		*ld = NULL;
681 #ifdef HAVE_TLS
682 	int		is_tls = op->o_conn->c_is_tls;
683 	int		flags = li->li_flags;
684 	time_t		lctime = (time_t)(-1);
685 	slap_bindconf *sb;
686 #endif /* HAVE_TLS */
687 
688 	ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
689 	rs->sr_err = ldap_initialize( &ld, li->li_uri );
690 	ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
691 	if ( rs->sr_err != LDAP_SUCCESS ) {
692 		goto error_return;
693 	}
694 
695 	if ( li->li_urllist_f ) {
696 		ldap_set_urllist_proc( ld, li->li_urllist_f, li->li_urllist_p );
697 	}
698 
699 	/* Set LDAP version. This will always succeed: If the client
700 	 * bound with a particular version, then so can we.
701 	 */
702 	if ( li->li_version != 0 ) {
703 		version = li->li_version;
704 
705 	} else if ( op->o_protocol != 0 ) {
706 		version = op->o_protocol;
707 
708 	} else {
709 		/* assume it's an internal op; set to LDAPv3 */
710 		version = LDAP_VERSION3;
711 	}
712 	ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version );
713 
714 	/* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
715 	ldap_set_option( ld, LDAP_OPT_REFERRALS,
716 		LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
717 
718 	if ( li->li_network_timeout > 0 ) {
719 		struct timeval		tv;
720 
721 		tv.tv_sec = li->li_network_timeout;
722 		tv.tv_usec = 0;
723 		ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&tv );
724 	}
725 
726 	/* turn on network keepalive, if configured so */
727 	slap_client_keepalive(ld, &li->li_tls.sb_keepalive);
728 
729 #ifdef HAVE_TLS
730 	if ( LDAP_BACK_CONN_ISPRIV( lc ) ) {
731 		/* See "rationale" comment in ldap_back_getconn() */
732 		if ( li->li_acl_authmethod == LDAP_AUTH_NONE &&
733 			 li->li_idassert_authmethod != LDAP_AUTH_NONE )
734 			sb = &li->li_idassert.si_bc;
735 		else
736 			sb = &li->li_acl;
737 
738 	} else if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) {
739 		sb = &li->li_idassert.si_bc;
740 
741 	} else {
742 		sb = &li->li_tls;
743 	}
744 
745 	if ( sb->sb_tls_do_init ) {
746 		bindconf_tls_set( sb, ld );
747 	} else if ( sb->sb_tls_ctx ) {
748 		ldap_set_option( ld, LDAP_OPT_X_TLS_CTX, sb->sb_tls_ctx );
749 	}
750 
751 	/* if required by the bindconf configuration, force TLS */
752 	if ( ( sb == &li->li_acl || sb == &li->li_idassert.si_bc ) &&
753 		sb->sb_tls_ctx )
754 	{
755 		flags |= LDAP_BACK_F_USE_TLS;
756 	}
757 
758 	ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
759 	assert( li->li_uri_mutex_do_not_lock == 0 );
760 	li->li_uri_mutex_do_not_lock = 1;
761 	rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
762 			li->li_uri, flags, li->li_nretries, &rs->sr_text );
763 	li->li_uri_mutex_do_not_lock = 0;
764 	ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
765 	if ( rs->sr_err != LDAP_SUCCESS ) {
766 		ldap_unbind_ext( ld, NULL, NULL );
767 		rs->sr_text = "Start TLS failed";
768 		goto error_return;
769 
770 	} else if ( li->li_idle_timeout ) {
771 		/* only touch when activity actually took place... */
772 		lctime = op->o_time;
773 	}
774 #endif /* HAVE_TLS */
775 
776 	lc->lc_ld = ld;
777 	lc->lc_refcnt = 1;
778 #ifdef HAVE_TLS
779 	if ( is_tls ) {
780 		LDAP_BACK_CONN_ISTLS_SET( lc );
781 	} else {
782 		LDAP_BACK_CONN_ISTLS_CLEAR( lc );
783 	}
784 	if ( lctime != (time_t)(-1) ) {
785 		lc->lc_time = lctime;
786 	}
787 #endif /* HAVE_TLS */
788 
789 error_return:;
790 	if ( rs->sr_err != LDAP_SUCCESS ) {
791 		rs->sr_err = slap_map_api2result( rs );
792 		if ( sendok & LDAP_BACK_SENDERR ) {
793 			if ( rs->sr_text == NULL ) {
794 				rs->sr_text = "Proxy connection initialization failed";
795 			}
796 			send_ldap_result( op, rs );
797 		}
798 
799 	} else {
800 		if ( li->li_conn_ttl > 0 ) {
801 			lc->lc_create_time = op->o_time;
802 		}
803 	}
804 
805 	return rs->sr_err;
806 }
807 
808 static ldapconn_t *
809 ldap_back_getconn(
810 	Operation		*op,
811 	SlapReply		*rs,
812 	ldap_back_send_t	sendok,
813 	struct berval		*binddn,
814 	struct berval		*bindcred )
815 {
816 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
817 	ldapconn_t	*lc = NULL,
818 			lc_curr = {{ 0 }};
819 	int		refcnt = 1,
820 			lookupconn = !( sendok & LDAP_BACK_BINDING );
821 
822 	/* if the server is quarantined, and
823 	 * - the current interval did not expire yet, or
824 	 * - no more retries should occur,
825 	 * don't return the connection */
826 	if ( li->li_isquarantined ) {
827 		slap_retry_info_t	*ri = &li->li_quarantine;
828 		int			dont_retry = 1;
829 
830 		if ( li->li_quarantine.ri_interval ) {
831 			ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
832 			if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) {
833 				dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
834 					|| slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
835 				if ( !dont_retry ) {
836 					Debug( LDAP_DEBUG_ANY,
837 						"%s: ldap_back_getconn quarantine "
838 						"retry block #%d try #%d.\n",
839 						op->o_log_prefix, ri->ri_idx, ri->ri_count );
840 					li->li_isquarantined = LDAP_BACK_FQ_RETRYING;
841 				}
842 			}
843 			ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
844 		}
845 
846 		if ( dont_retry ) {
847 			rs->sr_err = LDAP_UNAVAILABLE;
848 			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
849 				rs->sr_text = "Target is quarantined";
850 				send_ldap_result( op, rs );
851 			}
852 			return NULL;
853 		}
854 	}
855 
856 	/* Internal searches are privileged and shared. So is root. */
857 	if ( op->o_do_not_cache || be_isroot( op ) ) {
858 		LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
859 		lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
860 		LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
861 
862 	} else {
863 		struct berval	tmpbinddn,
864 				tmpbindcred,
865 				save_o_dn,
866 				save_o_ndn;
867 		int		isproxyauthz;
868 
869 		/* need cleanup */
870 		if ( binddn == NULL ) {
871 			binddn = &tmpbinddn;
872 		}
873 		if ( bindcred == NULL ) {
874 			bindcred = &tmpbindcred;
875 		}
876 		if ( op->o_tag == LDAP_REQ_BIND ) {
877 			save_o_dn = op->o_dn;
878 			save_o_ndn = op->o_ndn;
879 			op->o_dn = op->o_req_dn;
880 			op->o_ndn = op->o_req_ndn;
881 		}
882 		isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred );
883 		if ( op->o_tag == LDAP_REQ_BIND ) {
884 			op->o_dn = save_o_dn;
885 			op->o_ndn = save_o_ndn;
886 		}
887 		if ( isproxyauthz == -1 ) {
888 			return NULL;
889 		}
890 
891 		lc_curr.lc_local_ndn = op->o_ndn;
892 		/* Explicit binds must not be shared;
893 		 * however, explicit binds are piped in a special connection
894 		 * when idassert is to occur with "override" set */
895 		if ( op->o_tag == LDAP_REQ_BIND && !isproxyauthz ) {
896 			lc_curr.lc_conn = op->o_conn;
897 
898 		} else {
899 			if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
900 				lc_curr.lc_local_ndn = *binddn;
901 				LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
902 				LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
903 
904 			} else if ( isproxyauthz && ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) {
905 				lc_curr.lc_local_ndn = slap_empty_bv;
906 				LDAP_BACK_PCONN_BIND_SET( &lc_curr, op );
907 				LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
908 				lookupconn = 1;
909 
910 			} else if ( SLAP_IS_AUTHZ_BACKEND( op ) ) {
911 				lc_curr.lc_conn = op->o_conn;
912 
913 			} else {
914 				LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
915 			}
916 		}
917 	}
918 
919 	/* Explicit Bind requests always get their own conn */
920 	if ( lookupconn ) {
921 retry_lock:
922 		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
923 		if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr ) ) {
924 			/* lookup a conn that's not binding */
925 			LDAP_TAILQ_FOREACH( lc,
926 				&li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv,
927 				lc_q )
928 			{
929 				if ( !LDAP_BACK_CONN_BINDING( lc ) && lc->lc_refcnt == 0 ) {
930 					break;
931 				}
932 			}
933 
934 			if ( lc != NULL ) {
935 				if ( lc != LDAP_TAILQ_LAST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
936 					lc_conn_priv_q ) )
937 				{
938 					LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
939 						lc, lc_q );
940 					LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
941 					LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
942 						lc, lc_q );
943 				}
944 
945 			} else if ( !LDAP_BACK_USE_TEMPORARIES( li )
946 				&& li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_num == li->li_conn_priv_max )
947 			{
948 				lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv );
949 			}
950 
951 		} else {
952 
953 			/* Searches for a ldapconn in the avl tree */
954 			lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
955 					(caddr_t)&lc_curr, ldap_back_conndn_cmp );
956 		}
957 
958 		if ( lc != NULL ) {
959 			/* Don't reuse connections while they're still binding */
960 			if ( LDAP_BACK_CONN_BINDING( lc ) ) {
961 				if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) {
962 					ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
963 
964 					ldap_pvt_thread_yield();
965 					goto retry_lock;
966 				}
967 				lc = NULL;
968 			}
969 
970 			if ( lc != NULL ) {
971 				if ( op->o_tag == LDAP_REQ_BIND ) {
972 					/* right now, this is the only possible case */
973 					assert( ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) );
974 					LDAP_BACK_CONN_BINDING_SET( lc );
975 				}
976 
977 				refcnt = ++lc->lc_refcnt;
978 			}
979 		}
980 		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
981 	}
982 
983 	/* Looks like we didn't get a bind. Open a new session... */
984 	if ( lc == NULL ) {
985 		lc = (ldapconn_t *)ch_calloc( 1, sizeof( ldapconn_t ) );
986 		lc->lc_flags = li->li_flags;
987 		lc->lc_lcflags = lc_curr.lc_lcflags;
988 		if ( ldap_back_prepare_conn( lc, op, rs, sendok ) != LDAP_SUCCESS ) {
989 			ch_free( lc );
990 			return NULL;
991 		}
992 
993 		if ( sendok & LDAP_BACK_BINDING ) {
994 			LDAP_BACK_CONN_BINDING_SET( lc );
995 		}
996 
997 		lc->lc_conn = lc_curr.lc_conn;
998 		ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn );
999 
1000 		/*
1001 		 * the rationale is: connections as the rootdn are privileged,
1002 		 * so li_acl is to be used; however, in some cases
1003 		 * one already configured identity assertion with a highly
1004 		 * privileged idassert_authcDN, so if li_acl is not configured
1005 		 * and idassert is, use idassert instead.
1006 		 *
1007 		 * might change in the future, because it's preferable
1008 		 * to make clear what identity is being used, since
1009 		 * the only drawback is that one risks to configure
1010 		 * the same identity twice...
1011 		 */
1012 		if ( LDAP_BACK_CONN_ISPRIV( &lc_curr ) ) {
1013 			if ( li->li_acl_authmethod == LDAP_AUTH_NONE &&
1014 				 li->li_idassert_authmethod != LDAP_AUTH_NONE ) {
1015 				ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
1016 				ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
1017 
1018 			} else {
1019 				ber_dupbv( &lc->lc_bound_ndn, &li->li_acl_authcDN );
1020 				ber_dupbv( &lc->lc_cred, &li->li_acl_passwd );
1021 			}
1022 			LDAP_BACK_CONN_ISPRIV_SET( lc );
1023 
1024 		} else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr ) ) {
1025 			if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr ) ) {
1026 				ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
1027 				ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
1028 			}
1029 			LDAP_BACK_CONN_ISIDASSERT_SET( lc );
1030 
1031 		} else {
1032 			BER_BVZERO( &lc->lc_cred );
1033 			BER_BVZERO( &lc->lc_bound_ndn );
1034 			if ( !BER_BVISEMPTY( &op->o_ndn )
1035 				&& SLAP_IS_AUTHZ_BACKEND( op ) )
1036 			{
1037 				ber_dupbv( &lc->lc_bound_ndn, &op->o_ndn );
1038 			}
1039 		}
1040 
1041 #ifdef HAVE_TLS
1042 		/* if start TLS failed but it was not mandatory,
1043 		 * check if the non-TLS connection was already
1044 		 * in cache; in case, destroy the newly created
1045 		 * connection and use the existing one */
1046 		if ( LDAP_BACK_PCONN_ISTLS( lc )
1047 				&& !ldap_tls_inplace( lc->lc_ld ) )
1048 		{
1049 			ldapconn_t	*tmplc = NULL;
1050 			int		idx = LDAP_BACK_CONN2PRIV( &lc_curr ) - 1;
1051 
1052 			ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1053 			LDAP_TAILQ_FOREACH( tmplc,
1054 				&li->li_conn_priv[ idx ].lic_priv,
1055 				lc_q )
1056 			{
1057 				if ( !LDAP_BACK_CONN_BINDING( tmplc ) ) {
1058 					break;
1059 				}
1060 			}
1061 
1062 			if ( tmplc != NULL ) {
1063 				refcnt = ++tmplc->lc_refcnt;
1064 				ldap_back_conn_free( lc );
1065 				lc = tmplc;
1066 			}
1067 			ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1068 
1069 			if ( tmplc != NULL ) {
1070 				goto done;
1071 			}
1072 		}
1073 #endif /* HAVE_TLS */
1074 
1075 		/* Inserts the newly created ldapconn in the avl tree */
1076 		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1077 
1078 		LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
1079 		lc->lc_connid = li->li_conn_nextid++;
1080 
1081 		assert( lc->lc_refcnt == 1 );
1082 
1083 #if LDAP_BACK_PRINT_CONNTREE > 0
1084 		ldap_back_print_conntree( li, ">>> ldap_back_getconn(insert)" );
1085 #endif /* LDAP_BACK_PRINT_CONNTREE */
1086 
1087 		if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
1088 			if ( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num < li->li_conn_priv_max ) {
1089 				LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
1090 				li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num++;
1091 				LDAP_BACK_CONN_CACHED_SET( lc );
1092 
1093 			} else {
1094 				LDAP_BACK_CONN_TAINTED_SET( lc );
1095 			}
1096 			rs->sr_err = 0;
1097 
1098 		} else {
1099 			rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
1100 				ldap_back_conndn_cmp, ldap_back_conndn_dup );
1101 			LDAP_BACK_CONN_CACHED_SET( lc );
1102 		}
1103 
1104 #if LDAP_BACK_PRINT_CONNTREE > 0
1105 		ldap_back_print_conntree( li, "<<< ldap_back_getconn(insert)" );
1106 #endif /* LDAP_BACK_PRINT_CONNTREE */
1107 
1108 		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1109 
1110 		if ( LogTest( LDAP_DEBUG_TRACE ) ) {
1111 			char	buf[ SLAP_TEXT_BUFLEN ];
1112 
1113 			snprintf( buf, sizeof( buf ),
1114 				"lc=%p inserted refcnt=%u rc=%d",
1115 				(void *)lc, refcnt, rs->sr_err );
1116 
1117 			Debug( LDAP_DEBUG_TRACE,
1118 				"=>ldap_back_getconn: %s: %s\n",
1119 				op->o_log_prefix, buf, 0 );
1120 		}
1121 
1122 		if ( !LDAP_BACK_PCONN_ISPRIV( lc ) ) {
1123 			/* Err could be -1 in case a duplicate ldapconn is inserted */
1124 			switch ( rs->sr_err ) {
1125 			case 0:
1126 				break;
1127 
1128 			case -1:
1129 				LDAP_BACK_CONN_CACHED_CLEAR( lc );
1130 				if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) {
1131 					/* duplicate: free and try to get the newly created one */
1132 					ldap_back_conn_free( lc );
1133 					lc = NULL;
1134 					goto retry_lock;
1135 				}
1136 
1137 				/* taint connection, so that it'll be freed when released */
1138 				LDAP_BACK_CONN_TAINTED_SET( lc );
1139 				break;
1140 
1141 			default:
1142 				LDAP_BACK_CONN_CACHED_CLEAR( lc );
1143 				ldap_back_conn_free( lc );
1144 				rs->sr_err = LDAP_OTHER;
1145 				rs->sr_text = "Proxy bind collision";
1146 				if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
1147 					send_ldap_result( op, rs );
1148 				}
1149 				return NULL;
1150 			}
1151 		}
1152 
1153 	} else {
1154 		int	expiring = 0;
1155 
1156 		if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout )
1157 			|| ( li->li_conn_ttl != 0 && op->o_time > lc->lc_create_time + li->li_conn_ttl ) )
1158 		{
1159 			expiring = 1;
1160 
1161 			/* let it be used, but taint/delete it so that
1162 			 * no-one else can look it up any further */
1163 			ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1164 
1165 #if LDAP_BACK_PRINT_CONNTREE > 0
1166 			ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
1167 #endif /* LDAP_BACK_PRINT_CONNTREE */
1168 
1169 			(void)ldap_back_conn_delete( li, lc );
1170 			LDAP_BACK_CONN_TAINTED_SET( lc );
1171 
1172 #if LDAP_BACK_PRINT_CONNTREE > 0
1173 			ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
1174 #endif /* LDAP_BACK_PRINT_CONNTREE */
1175 
1176 			ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1177 		}
1178 
1179 		if ( LogTest( LDAP_DEBUG_TRACE ) ) {
1180 			char	buf[ SLAP_TEXT_BUFLEN ];
1181 
1182 			snprintf( buf, sizeof( buf ),
1183 				"conn %p fetched refcnt=%u%s",
1184 				(void *)lc, refcnt,
1185 				expiring ? " expiring" : "" );
1186 			Debug( LDAP_DEBUG_TRACE,
1187 				"=>ldap_back_getconn: %s.\n", buf, 0, 0 );
1188 		}
1189 	}
1190 
1191 #ifdef HAVE_TLS
1192 done:;
1193 #endif /* HAVE_TLS */
1194 
1195 	return lc;
1196 }
1197 
1198 void
1199 ldap_back_release_conn_lock(
1200 	ldapinfo_t		*li,
1201 	ldapconn_t		**lcp,
1202 	int			dolock )
1203 {
1204 
1205 	ldapconn_t	*lc = *lcp;
1206 
1207 	if ( dolock ) {
1208 		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1209 	}
1210 	assert( lc->lc_refcnt > 0 );
1211 	LDAP_BACK_CONN_BINDING_CLEAR( lc );
1212 	lc->lc_refcnt--;
1213 	if ( LDAP_BACK_CONN_TAINTED( lc ) ) {
1214 		ldap_back_freeconn( li, lc, 0 );
1215 		*lcp = NULL;
1216 	}
1217 	if ( dolock ) {
1218 		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1219 	}
1220 }
1221 
1222 void
1223 ldap_back_quarantine(
1224 	Operation	*op,
1225 	SlapReply	*rs )
1226 {
1227 	ldapinfo_t		*li = (ldapinfo_t *)op->o_bd->be_private;
1228 
1229 	slap_retry_info_t	*ri = &li->li_quarantine;
1230 
1231 	ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
1232 
1233 	if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1234 		time_t		new_last = slap_get_time();
1235 
1236 		switch ( li->li_isquarantined ) {
1237 		case LDAP_BACK_FQ_NO:
1238 			if ( ri->ri_last == new_last ) {
1239 				goto done;
1240 			}
1241 
1242 			Debug( LDAP_DEBUG_ANY,
1243 				"%s: ldap_back_quarantine enter.\n",
1244 				op->o_log_prefix, 0, 0 );
1245 
1246 			ri->ri_idx = 0;
1247 			ri->ri_count = 0;
1248 			break;
1249 
1250 		case LDAP_BACK_FQ_RETRYING:
1251 			Debug( LDAP_DEBUG_ANY,
1252 				"%s: ldap_back_quarantine block #%d try #%d failed.\n",
1253 				op->o_log_prefix, ri->ri_idx, ri->ri_count );
1254 
1255 			++ri->ri_count;
1256 			if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER
1257 				&& ri->ri_count == ri->ri_num[ ri->ri_idx ] )
1258 			{
1259 				ri->ri_count = 0;
1260 				++ri->ri_idx;
1261 			}
1262 			break;
1263 
1264 		default:
1265 			break;
1266 		}
1267 
1268 		li->li_isquarantined = LDAP_BACK_FQ_YES;
1269 		ri->ri_last = new_last;
1270 
1271 	} else if ( li->li_isquarantined != LDAP_BACK_FQ_NO ) {
1272 		if ( ri->ri_last == slap_get_time() ) {
1273 			goto done;
1274 		}
1275 
1276 		Debug( LDAP_DEBUG_ANY,
1277 			"%s: ldap_back_quarantine exit (%d) err=%d.\n",
1278 			op->o_log_prefix, li->li_isquarantined, rs->sr_err );
1279 
1280 		if ( li->li_quarantine_f ) {
1281 			(void)li->li_quarantine_f( li, li->li_quarantine_p );
1282 		}
1283 
1284 		ri->ri_count = 0;
1285 		ri->ri_idx = 0;
1286 		li->li_isquarantined = LDAP_BACK_FQ_NO;
1287 	}
1288 
1289 done:;
1290 	ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
1291 }
1292 
1293 static int
1294 ldap_back_dobind_cb(
1295 	Operation *op,
1296 	SlapReply *rs
1297 )
1298 {
1299 	ber_tag_t *tptr = op->o_callback->sc_private;
1300 	op->o_tag = *tptr;
1301 	rs->sr_tag = slap_req2res( op->o_tag );
1302 
1303 	return SLAP_CB_CONTINUE;
1304 }
1305 
1306 /*
1307  * ldap_back_dobind_int
1308  *
1309  * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
1310  */
1311 static int
1312 ldap_back_dobind_int(
1313 	ldapconn_t		**lcp,
1314 	Operation		*op,
1315 	SlapReply		*rs,
1316 	ldap_back_send_t	sendok,
1317 	int			retries,
1318 	int			dolock )
1319 {
1320 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
1321 
1322 	ldapconn_t	*lc;
1323 	struct berval	binddn = slap_empty_bv,
1324 			bindcred = slap_empty_bv;
1325 
1326 	int		rc = 0,
1327 			isbound,
1328 			binding = 0;
1329 	ber_int_t	msgid;
1330 	ber_tag_t	o_tag = op->o_tag;
1331 	slap_callback cb = {0};
1332 	char		*tmp_dn;
1333 
1334 	assert( lcp != NULL );
1335 	assert( retries >= 0 );
1336 
1337 	if ( sendok & LDAP_BACK_GETCONN ) {
1338 		assert( *lcp == NULL );
1339 
1340 		lc = ldap_back_getconn( op, rs, sendok, &binddn, &bindcred );
1341 		if ( lc == NULL ) {
1342 			return 0;
1343 		}
1344 		*lcp = lc;
1345 
1346 	} else {
1347 		lc = *lcp;
1348 	}
1349 
1350 	assert( lc != NULL );
1351 
1352 retry_lock:;
1353  	if ( dolock ) {
1354  		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1355  	}
1356 
1357  	if ( binding == 0 ) {
1358 		/* check if already bound */
1359 		rc = isbound = LDAP_BACK_CONN_ISBOUND( lc );
1360 		if ( isbound ) {
1361  			if ( dolock ) {
1362  				ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1363  			}
1364 			return rc;
1365 		}
1366 
1367 		if ( LDAP_BACK_CONN_BINDING( lc ) ) {
1368 			/* if someone else is about to bind it, give up and retry */
1369  			if ( dolock ) {
1370  				ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1371  			}
1372 			ldap_pvt_thread_yield();
1373 			goto retry_lock;
1374 
1375 		} else {
1376 			/* otherwise this thread will bind it */
1377  			LDAP_BACK_CONN_BINDING_SET( lc );
1378 			binding = 1;
1379 		}
1380 	}
1381 
1382  	if ( dolock ) {
1383  		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1384  	}
1385 
1386 	/*
1387 	 * FIXME: we need to let clients use proxyAuthz
1388 	 * otherwise we cannot do symmetric pools of servers;
1389 	 * we have to live with the fact that a user can
1390 	 * authorize itself as any ID that is allowed
1391 	 * by the authzTo directive of the "proxyauthzdn".
1392 	 */
1393 	/*
1394 	 * NOTE: current Proxy Authorization specification
1395 	 * and implementation do not allow proxy authorization
1396 	 * control to be provided with Bind requests
1397 	 */
1398 	/*
1399 	 * if no bind took place yet, but the connection is bound
1400 	 * and the "idassert-authcDN" (or other ID) is set,
1401 	 * then bind as the asserting identity and explicitly
1402 	 * add the proxyAuthz control to every operation with the
1403 	 * dn bound to the connection as control value.
1404 	 * This is done also if this is the authorizing backend,
1405 	 * but the "override" flag is given to idassert.
1406 	 * It allows to use SASL bind and yet proxyAuthz users
1407 	 */
1408 	op->o_tag = LDAP_REQ_BIND;
1409 	cb.sc_next = op->o_callback;
1410 	cb.sc_private = &o_tag;
1411 	cb.sc_response = ldap_back_dobind_cb;
1412 	op->o_callback = &cb;
1413 
1414 	if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) {
1415 		if ( BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &bindcred ) ) {
1416 			/* if we got here, it shouldn't return result */
1417 			rc = ldap_back_is_proxy_authz( op, rs,
1418 				LDAP_BACK_DONTSEND, &binddn, &bindcred );
1419 			if ( rc != 1 ) {
1420 				Debug( LDAP_DEBUG_ANY, "Error: ldap_back_is_proxy_authz "
1421 					"returned %d, misconfigured URI?\n", rc, 0, 0 );
1422 				rs->sr_err = LDAP_OTHER;
1423 				rs->sr_text = "misconfigured URI?";
1424 				LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
1425 				if ( sendok & LDAP_BACK_SENDERR ) {
1426 					send_ldap_result( op, rs );
1427 				}
1428 				goto done;
1429 			}
1430 		}
1431 		rc = ldap_back_proxy_authz_bind( lc, op, rs, sendok, &binddn, &bindcred );
1432 		goto done;
1433 	}
1434 
1435 #ifdef HAVE_CYRUS_SASL
1436 	if ( LDAP_BACK_CONN_ISPRIV( lc )) {
1437 	slap_bindconf *sb;
1438 	if ( li->li_acl_authmethod != LDAP_AUTH_NONE )
1439 		sb = &li->li_acl;
1440 	else
1441 		sb = &li->li_idassert.si_bc;
1442 
1443 	if ( sb->sb_method == LDAP_AUTH_SASL ) {
1444 		void		*defaults = NULL;
1445 
1446 		if ( sb->sb_secprops != NULL ) {
1447 			rc = ldap_set_option( lc->lc_ld,
1448 				LDAP_OPT_X_SASL_SECPROPS, sb->sb_secprops );
1449 
1450 			if ( rc != LDAP_OPT_SUCCESS ) {
1451 				Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
1452 					"(SECPROPS,\"%s\") failed!\n",
1453 					sb->sb_secprops, 0, 0 );
1454 				goto done;
1455 			}
1456 		}
1457 
1458 		defaults = lutil_sasl_defaults( lc->lc_ld,
1459 				sb->sb_saslmech.bv_val,
1460 				sb->sb_realm.bv_val,
1461 				sb->sb_authcId.bv_val,
1462 				sb->sb_cred.bv_val,
1463 				NULL );
1464 		if ( defaults == NULL ) {
1465 			rs->sr_err = LDAP_OTHER;
1466 			LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
1467 			if ( sendok & LDAP_BACK_SENDERR ) {
1468 				send_ldap_result( op, rs );
1469 			}
1470 			goto done;
1471 		}
1472 
1473 		rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld,
1474 				sb->sb_binddn.bv_val,
1475 				sb->sb_saslmech.bv_val, NULL, NULL,
1476 				LDAP_SASL_QUIET, lutil_sasl_interact,
1477 				defaults );
1478 
1479 		ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
1480 		ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
1481 		ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
1482 
1483 		lutil_sasl_freedefs( defaults );
1484 
1485 		switch ( rs->sr_err ) {
1486 		case LDAP_SUCCESS:
1487 			LDAP_BACK_CONN_ISBOUND_SET( lc );
1488 			break;
1489 
1490 		case LDAP_LOCAL_ERROR:
1491 			/* list client API error codes that require
1492 			 * to taint the connection */
1493 			/* FIXME: should actually retry? */
1494 			LDAP_BACK_CONN_TAINTED_SET( lc );
1495 
1496 			/* fallthru */
1497 
1498 		default:
1499 			LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
1500 			rs->sr_err = slap_map_api2result( rs );
1501 			if ( sendok & LDAP_BACK_SENDERR ) {
1502 				send_ldap_result( op, rs );
1503 			}
1504 			break;
1505 		}
1506 
1507 		if ( LDAP_BACK_QUARANTINE( li ) ) {
1508 			ldap_back_quarantine( op, rs );
1509 		}
1510 
1511 		goto done;
1512 	}
1513 	}
1514 #endif /* HAVE_CYRUS_SASL */
1515 
1516 retry:;
1517 	if ( BER_BVISNULL( &lc->lc_cred ) ) {
1518 		tmp_dn = "";
1519 		if ( !BER_BVISNULL( &lc->lc_bound_ndn ) && !BER_BVISEMPTY( &lc->lc_bound_ndn ) ) {
1520 			Debug( LDAP_DEBUG_ANY, "%s ldap_back_dobind_int: DN=\"%s\" without creds, binding anonymously",
1521 				op->o_log_prefix, lc->lc_bound_ndn.bv_val, 0 );
1522 		}
1523 
1524 	} else {
1525 		tmp_dn = lc->lc_bound_ndn.bv_val;
1526 	}
1527 	rs->sr_err = ldap_sasl_bind( lc->lc_ld,
1528 			tmp_dn,
1529 			LDAP_SASL_SIMPLE, &lc->lc_cred,
1530 			NULL, NULL, &msgid );
1531 
1532 	ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
1533 	ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
1534 	ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
1535 
1536 	if ( rs->sr_err == LDAP_SERVER_DOWN ) {
1537 		if ( retries != LDAP_BACK_RETRY_NEVER ) {
1538 			if ( dolock ) {
1539 				ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1540 			}
1541 
1542 			assert( lc->lc_refcnt > 0 );
1543 			if ( lc->lc_refcnt == 1 ) {
1544 				ldap_unbind_ext( lc->lc_ld, NULL, NULL );
1545 				lc->lc_ld = NULL;
1546 
1547 				/* lc here must be the regular lc, reset and ready for init */
1548 				rs->sr_err = ldap_back_prepare_conn( lc, op, rs, sendok );
1549 				if ( rs->sr_err != LDAP_SUCCESS ) {
1550 					sendok &= ~LDAP_BACK_SENDERR;
1551 					lc->lc_refcnt = 0;
1552 				}
1553 			}
1554 
1555 			if ( dolock ) {
1556 				ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1557 			}
1558 
1559 			if ( rs->sr_err == LDAP_SUCCESS ) {
1560 				if ( retries > 0 ) {
1561 					retries--;
1562 				}
1563 				goto retry;
1564 			}
1565 		}
1566 
1567 		assert( lc->lc_refcnt == 1 );
1568 		lc->lc_refcnt = 0;
1569 		ldap_back_freeconn( li, lc, dolock );
1570 		*lcp = NULL;
1571 		rs->sr_err = slap_map_api2result( rs );
1572 
1573 		if ( LDAP_BACK_QUARANTINE( li ) ) {
1574 			ldap_back_quarantine( op, rs );
1575 		}
1576 
1577 		if ( rs->sr_err != LDAP_SUCCESS &&
1578 			( sendok & LDAP_BACK_SENDERR ) )
1579 		{
1580 			if ( op->o_callback == &cb )
1581 				op->o_callback = cb.sc_next;
1582 			op->o_tag = o_tag;
1583 			rs->sr_text = "Proxy can't contact remote server";
1584 			send_ldap_result( op, rs );
1585 			/* if we originally bound and wanted rebind-as-user, must drop
1586 			 * the connection now because we just discarded the credentials.
1587 			 * ITS#7464, #8142
1588 			 */
1589 			if ( LDAP_BACK_SAVECRED( li ) && SLAP_IS_AUTHZ_BACKEND( op ) )
1590 				rs->sr_err = SLAPD_DISCONNECT;
1591 		}
1592 
1593 		rc = 0;
1594 		goto func_leave;
1595 	}
1596 
1597 	rc = ldap_back_op_result( lc, op, rs, msgid,
1598 		-1, ( sendok | LDAP_BACK_BINDING ) );
1599 	if ( rc == LDAP_SUCCESS ) {
1600 		LDAP_BACK_CONN_ISBOUND_SET( lc );
1601 	}
1602 
1603 done:;
1604 	LDAP_BACK_CONN_BINDING_CLEAR( lc );
1605 	rc = LDAP_BACK_CONN_ISBOUND( lc );
1606 	if ( !rc ) {
1607 		ldap_back_release_conn_lock( li, lcp, dolock );
1608 
1609 	} else if ( LDAP_BACK_SAVECRED( li ) ) {
1610 		ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
1611 	}
1612 
1613 func_leave:;
1614 	if ( op->o_callback == &cb )
1615 		op->o_callback = cb.sc_next;
1616 	op->o_tag = o_tag;
1617 
1618 	return rc;
1619 }
1620 
1621 /*
1622  * ldap_back_dobind
1623  *
1624  * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
1625  */
1626 int
1627 ldap_back_dobind( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
1628 {
1629 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
1630 
1631 	return ldap_back_dobind_int( lcp, op, rs,
1632 		( sendok | LDAP_BACK_GETCONN ), li->li_nretries, 1 );
1633 }
1634 
1635 /*
1636  * ldap_back_default_rebind
1637  *
1638  * This is a callback used for chasing referrals using the same
1639  * credentials as the original user on this session.
1640  */
1641 int
1642 ldap_back_default_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
1643 	ber_int_t msgid, void *params )
1644 {
1645 	ldapconn_t	*lc = (ldapconn_t *)params;
1646 
1647 #ifdef HAVE_TLS
1648 	/* ... otherwise we couldn't get here */
1649 	assert( lc != NULL );
1650 
1651 	if ( !ldap_tls_inplace( ld ) ) {
1652 		int		is_tls = LDAP_BACK_CONN_ISTLS( lc ),
1653 				rc;
1654 		const char	*text = NULL;
1655 
1656 		rc = ldap_back_start_tls( ld, 0, &is_tls, url, lc->lc_flags,
1657 			LDAP_BACK_RETRY_DEFAULT, &text );
1658 		if ( rc != LDAP_SUCCESS ) {
1659 			return rc;
1660 		}
1661 	}
1662 #endif /* HAVE_TLS */
1663 
1664 	/* FIXME: add checks on the URL/identity? */
1665 	/* TODO: would like to count this bind operation for monitoring
1666 	 * too, but where do we get the ldapinfo_t? */
1667 
1668 	return ldap_sasl_bind_s( ld,
1669 			BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val,
1670 			LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, NULL );
1671 }
1672 
1673 /*
1674  * ldap_back_default_urllist
1675  */
1676 int
1677 ldap_back_default_urllist(
1678 	LDAP		*ld,
1679 	LDAPURLDesc	**urllist,
1680 	LDAPURLDesc	**url,
1681 	void		*params )
1682 {
1683 	ldapinfo_t	*li = (ldapinfo_t *)params;
1684 	LDAPURLDesc	**urltail;
1685 
1686 	if ( urllist == url ) {
1687 		return LDAP_SUCCESS;
1688 	}
1689 
1690 	for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
1691 		/* count */ ;
1692 
1693 	*urltail = *urllist;
1694 	*urllist = *url;
1695 	*url = NULL;
1696 
1697 	if ( !li->li_uri_mutex_do_not_lock ) {
1698 		ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
1699 	}
1700 
1701 	if ( li->li_uri ) {
1702 		ch_free( li->li_uri );
1703 	}
1704 
1705 	ldap_get_option( ld, LDAP_OPT_URI, (void *)&li->li_uri );
1706 
1707 	if ( !li->li_uri_mutex_do_not_lock ) {
1708 		ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
1709 	}
1710 
1711 	return LDAP_SUCCESS;
1712 }
1713 
1714 int
1715 ldap_back_cancel(
1716 		ldapconn_t		*lc,
1717 		Operation		*op,
1718 		SlapReply		*rs,
1719 		ber_int_t		msgid,
1720 		ldap_back_send_t	sendok )
1721 {
1722 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
1723 
1724 	/* default behavior */
1725 	if ( LDAP_BACK_ABANDON( li ) ) {
1726 		return ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
1727 	}
1728 
1729 	if ( LDAP_BACK_IGNORE( li ) ) {
1730 		return ldap_pvt_discard( lc->lc_ld, msgid );
1731 	}
1732 
1733 	if ( LDAP_BACK_CANCEL( li ) ) {
1734 		/* FIXME: asynchronous? */
1735 		return ldap_cancel_s( lc->lc_ld, msgid, NULL, NULL );
1736 	}
1737 
1738 	assert( 0 );
1739 
1740 	return LDAP_OTHER;
1741 }
1742 
1743 int
1744 ldap_back_op_result(
1745 		ldapconn_t		*lc,
1746 		Operation		*op,
1747 		SlapReply		*rs,
1748 		ber_int_t		msgid,
1749 		time_t			timeout,
1750 		ldap_back_send_t	sendok )
1751 {
1752 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
1753 
1754 	char		*match = NULL;
1755 	char		*text = NULL;
1756 	char		**refs = NULL;
1757 	LDAPControl	**ctrls = NULL;
1758 
1759 	rs->sr_text = NULL;
1760 	rs->sr_matched = NULL;
1761 	rs->sr_ref = NULL;
1762 	rs->sr_ctrls = NULL;
1763 
1764 	/* if the error recorded in the reply corresponds
1765 	 * to a successful state, get the error from the
1766 	 * remote server response */
1767 	if ( LDAP_ERR_OK( rs->sr_err ) ) {
1768 		int		rc;
1769 		struct timeval	tv;
1770 		LDAPMessage	*res = NULL;
1771 		time_t		stoptime = (time_t)(-1);
1772 		int		timeout_err = op->o_protocol >= LDAP_VERSION3 ?
1773 					LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
1774 		const char	*timeout_text = "Operation timed out";
1775 
1776 		/* if timeout is not specified, compute and use
1777 		 * the one specific to the ongoing operation */
1778 		if ( timeout == (time_t)(-1) ) {
1779 			slap_op_t	opidx = slap_req2op( op->o_tag );
1780 
1781 			if ( opidx == SLAP_OP_SEARCH ) {
1782 				if ( op->ors_tlimit <= 0 ) {
1783 					timeout = 0;
1784 
1785 				} else {
1786 					timeout = op->ors_tlimit;
1787 					timeout_err = LDAP_TIMELIMIT_EXCEEDED;
1788 					timeout_text = NULL;
1789 				}
1790 
1791 			} else {
1792 				timeout = li->li_timeout[ opidx ];
1793 			}
1794 		}
1795 
1796 		/* better than nothing :) */
1797 		if ( timeout == 0 ) {
1798 			if ( li->li_idle_timeout ) {
1799 				timeout = li->li_idle_timeout;
1800 
1801 			} else if ( li->li_conn_ttl ) {
1802 				timeout = li->li_conn_ttl;
1803 			}
1804 		}
1805 
1806 		if ( timeout ) {
1807 			stoptime = op->o_time + timeout;
1808 		}
1809 
1810 		LDAP_BACK_TV_SET( &tv );
1811 
1812 retry:;
1813 		/* if result parsing fails, note the failure reason */
1814 		rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
1815 		switch ( rc ) {
1816 		case 0:
1817 			if ( timeout && slap_get_time() > stoptime ) {
1818 				if ( sendok & LDAP_BACK_BINDING ) {
1819 					ldap_unbind_ext( lc->lc_ld, NULL, NULL );
1820 					lc->lc_ld = NULL;
1821 
1822 					/* let it be used, but taint/delete it so that
1823 					 * no-one else can look it up any further */
1824 					ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1825 
1826 #if LDAP_BACK_PRINT_CONNTREE > 0
1827 					ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
1828 #endif /* LDAP_BACK_PRINT_CONNTREE */
1829 
1830 					(void)ldap_back_conn_delete( li, lc );
1831 					LDAP_BACK_CONN_TAINTED_SET( lc );
1832 
1833 #if LDAP_BACK_PRINT_CONNTREE > 0
1834 					ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
1835 #endif /* LDAP_BACK_PRINT_CONNTREE */
1836 					ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1837 
1838 				} else {
1839 					(void)ldap_back_cancel( lc, op, rs, msgid, sendok );
1840 				}
1841 				rs->sr_err = timeout_err;
1842 				rs->sr_text = timeout_text;
1843 				break;
1844 			}
1845 
1846 			/* timeout == 0 */
1847 			LDAP_BACK_TV_SET( &tv );
1848 			ldap_pvt_thread_yield();
1849 			goto retry;
1850 
1851 		case -1:
1852 			ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER,
1853 					&rs->sr_err );
1854 			break;
1855 
1856 
1857 		/* otherwise get the result; if it is not
1858 		 * LDAP_SUCCESS, record it in the reply
1859 		 * structure (this includes
1860 		 * LDAP_COMPARE_{TRUE|FALSE}) */
1861 		default:
1862 			/* only touch when activity actually took place... */
1863 			if ( li->li_idle_timeout ) {
1864 				lc->lc_time = op->o_time;
1865 			}
1866 
1867 			rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
1868 					&match, &text, &refs, &ctrls, 1 );
1869 			if ( rc == LDAP_SUCCESS ) {
1870 				rs->sr_text = text;
1871 			} else {
1872 				rs->sr_err = rc;
1873 			}
1874 			rs->sr_err = slap_map_api2result( rs );
1875 
1876 			/* RFC 4511: referrals can only appear
1877 			 * if result code is LDAP_REFERRAL */
1878 			if ( refs != NULL
1879 				&& refs[ 0 ] != NULL
1880 				&& refs[ 0 ][ 0 ] != '\0' )
1881 			{
1882 				if ( rs->sr_err != LDAP_REFERRAL ) {
1883 					Debug( LDAP_DEBUG_ANY,
1884 						"%s ldap_back_op_result: "
1885 						"got referrals with err=%d\n",
1886 						op->o_log_prefix,
1887 						rs->sr_err, 0 );
1888 
1889 				} else {
1890 					int	i;
1891 
1892 					for ( i = 0; refs[ i ] != NULL; i++ )
1893 						/* count */ ;
1894 					rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
1895 						op->o_tmpmemctx );
1896 					for ( i = 0; refs[ i ] != NULL; i++ ) {
1897 						ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
1898 					}
1899 					BER_BVZERO( &rs->sr_ref[ i ] );
1900 				}
1901 
1902 			} else if ( rs->sr_err == LDAP_REFERRAL ) {
1903 				Debug( LDAP_DEBUG_ANY,
1904 					"%s ldap_back_op_result: "
1905 					"got err=%d with null "
1906 					"or empty referrals\n",
1907 					op->o_log_prefix,
1908 					rs->sr_err, 0 );
1909 
1910 				rs->sr_err = LDAP_NO_SUCH_OBJECT;
1911 			}
1912 
1913 			if ( ctrls != NULL ) {
1914 				rs->sr_ctrls = ctrls;
1915 			}
1916 		}
1917 	}
1918 
1919 	/* if the error in the reply structure is not
1920 	 * LDAP_SUCCESS, try to map it from client
1921 	 * to server error */
1922 	if ( !LDAP_ERR_OK( rs->sr_err ) ) {
1923 		rs->sr_err = slap_map_api2result( rs );
1924 
1925 		/* internal ops ( op->o_conn == NULL )
1926 		 * must not reply to client */
1927 		if ( op->o_conn && !op->o_do_not_cache && match ) {
1928 
1929 			/* record the (massaged) matched
1930 			 * DN into the reply structure */
1931 			rs->sr_matched = match;
1932 		}
1933 	}
1934 
1935 	if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1936 		if ( !( sendok & LDAP_BACK_RETRYING ) ) {
1937 			if ( LDAP_BACK_QUARANTINE( li ) ) {
1938 				ldap_back_quarantine( op, rs );
1939 			}
1940 			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
1941 				if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
1942 				send_ldap_result( op, rs );
1943 			}
1944 		}
1945 
1946 	} else if ( op->o_conn &&
1947 		( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
1948 			|| ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
1949 	{
1950 		send_ldap_result( op, rs );
1951 	}
1952 
1953 	if ( text ) {
1954 		ldap_memfree( text );
1955 	}
1956 	rs->sr_text = NULL;
1957 
1958 	/* there can't be refs with a (successful) bind */
1959 	if ( rs->sr_ref ) {
1960 		op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
1961 		rs->sr_ref = NULL;
1962 	}
1963 
1964 	if ( refs ) {
1965 		ber_memvfree( (void **)refs );
1966 	}
1967 
1968 	/* match should not be possible with a successful bind */
1969 	if ( match ) {
1970 		if ( rs->sr_matched != match ) {
1971 			free( (char *)rs->sr_matched );
1972 		}
1973 		rs->sr_matched = NULL;
1974 		ldap_memfree( match );
1975 	}
1976 
1977 	if ( ctrls != NULL ) {
1978 		if ( op->o_tag == LDAP_REQ_BIND && rs->sr_err == LDAP_SUCCESS ) {
1979 			int i;
1980 
1981 			for ( i = 0; ctrls[i] != NULL; i++ );
1982 
1983 			rs->sr_ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( i + 1 ),
1984 				op->o_tmpmemctx );
1985 			for ( i = 0; ctrls[ i ] != NULL; i++ ) {
1986 				char *ptr;
1987 				ber_len_t oidlen = strlen( ctrls[i]->ldctl_oid );
1988 				ber_len_t size = sizeof( LDAPControl )
1989 					+ oidlen + 1
1990 					+ ctrls[i]->ldctl_value.bv_len + 1;
1991 
1992 				rs->sr_ctrls[ i ] = op->o_tmpalloc( size, op->o_tmpmemctx );
1993 				rs->sr_ctrls[ i ]->ldctl_oid = (char *)&rs->sr_ctrls[ i ][ 1 ];
1994 				lutil_strcopy( rs->sr_ctrls[ i ]->ldctl_oid, ctrls[i]->ldctl_oid );
1995 				rs->sr_ctrls[ i ]->ldctl_value.bv_val
1996 						= (char *)&rs->sr_ctrls[ i ]->ldctl_oid[oidlen + 1];
1997 				rs->sr_ctrls[ i ]->ldctl_value.bv_len
1998 					= ctrls[i]->ldctl_value.bv_len;
1999 				ptr = lutil_memcopy( rs->sr_ctrls[ i ]->ldctl_value.bv_val,
2000 					ctrls[i]->ldctl_value.bv_val, ctrls[i]->ldctl_value.bv_len );
2001 				*ptr = '\0';
2002 			}
2003 			rs->sr_ctrls[ i ] = NULL;
2004 			rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
2005 
2006 		} else {
2007 			assert( rs->sr_ctrls != NULL );
2008 			rs->sr_ctrls = NULL;
2009 		}
2010 
2011 		ldap_controls_free( ctrls );
2012 	}
2013 
2014 	return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
2015 }
2016 
2017 /* return true if bound, false if failed */
2018 int
2019 ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
2020 {
2021 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
2022 	int		rc = 0;
2023 
2024 	assert( lcp != NULL );
2025 	assert( *lcp != NULL );
2026 
2027 	ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
2028 
2029 	if ( (*lcp)->lc_refcnt == 1 ) {
2030 		int binding = LDAP_BACK_CONN_BINDING( *lcp );
2031 
2032 		ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
2033 		Debug( LDAP_DEBUG_ANY,
2034 			"%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
2035 			op->o_log_prefix, li->li_uri,
2036 			BER_BVISNULL( &(*lcp)->lc_bound_ndn ) ?
2037 				"" : (*lcp)->lc_bound_ndn.bv_val );
2038 		ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
2039 
2040 		ldap_unbind_ext( (*lcp)->lc_ld, NULL, NULL );
2041 		(*lcp)->lc_ld = NULL;
2042 		LDAP_BACK_CONN_ISBOUND_CLEAR( (*lcp) );
2043 
2044 		/* lc here must be the regular lc, reset and ready for init */
2045 		rc = ldap_back_prepare_conn( *lcp, op, rs, sendok );
2046 		if ( rc != LDAP_SUCCESS ) {
2047 			/* freeit, because lc_refcnt == 1 */
2048 			(*lcp)->lc_refcnt = 0;
2049 			(void)ldap_back_freeconn( li, *lcp, 0 );
2050 			*lcp = NULL;
2051 			rc = 0;
2052 
2053 		} else if ( ( sendok & LDAP_BACK_BINDING ) ) {
2054 			if ( binding ) {
2055 				LDAP_BACK_CONN_BINDING_SET( *lcp );
2056 			}
2057 			rc = 1;
2058 
2059 		} else {
2060 			rc = ldap_back_dobind_int( lcp, op, rs, sendok, 0, 0 );
2061 			if ( rc == 0 && *lcp != NULL ) {
2062 				/* freeit, because lc_refcnt == 1 */
2063 				(*lcp)->lc_refcnt = 0;
2064 				LDAP_BACK_CONN_TAINTED_SET( *lcp );
2065 				(void)ldap_back_freeconn( li, *lcp, 0 );
2066 				*lcp = NULL;
2067 			}
2068 		}
2069 
2070 	} else {
2071 		Debug( LDAP_DEBUG_TRACE,
2072 			"ldap_back_retry: conn %p refcnt=%u unable to retry.\n",
2073 			(void *)(*lcp), (*lcp)->lc_refcnt, 0 );
2074 
2075 		LDAP_BACK_CONN_TAINTED_SET( *lcp );
2076 		ldap_back_release_conn_lock( li, lcp, 0 );
2077 		assert( *lcp == NULL );
2078 
2079 		if ( sendok & LDAP_BACK_SENDERR ) {
2080 			rs->sr_err = LDAP_UNAVAILABLE;
2081 			rs->sr_text = "Unable to retry";
2082 			send_ldap_result( op, rs );
2083 		}
2084 	}
2085 
2086 	ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
2087 
2088 	return rc;
2089 }
2090 
2091 static int
2092 ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
2093 	struct berval *binddn, struct berval *bindcred )
2094 {
2095 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
2096 	struct berval	ndn;
2097 	int		dobind = 0;
2098 
2099 	if ( op->o_conn == NULL || op->o_do_not_cache ) {
2100 		goto done;
2101 	}
2102 
2103 	/* don't proxyAuthz if protocol is not LDAPv3 */
2104 	switch ( li->li_version ) {
2105 	case LDAP_VERSION3:
2106 		break;
2107 
2108 	case 0:
2109 		if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
2110 			break;
2111 		}
2112 		/* fall thru */
2113 
2114 	default:
2115 		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
2116 		if ( sendok & LDAP_BACK_SENDERR ) {
2117 			send_ldap_result( op, rs );
2118 			dobind = -1;
2119 		}
2120 		goto done;
2121 	}
2122 
2123 	/* safe default */
2124 	*binddn = slap_empty_bv;
2125 	*bindcred = slap_empty_bv;
2126 
2127 	if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
2128 		ndn = op->o_conn->c_ndn;
2129 
2130 	} else {
2131 		ndn = op->o_ndn;
2132 	}
2133 
2134 	if ( !( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE )) {
2135 		if ( op->o_tag == LDAP_REQ_BIND ) {
2136 			if ( !BER_BVISEMPTY( &ndn )) {
2137 				dobind = 0;
2138 				goto done;
2139 			}
2140 		} else if ( SLAP_IS_AUTHZ_BACKEND( op )) {
2141 			dobind = 0;
2142 			goto done;
2143 		}
2144 	}
2145 
2146 	switch ( li->li_idassert_mode ) {
2147 	case LDAP_BACK_IDASSERT_LEGACY:
2148 		if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
2149 			if ( !BER_BVISNULL( &li->li_idassert_authcDN ) && !BER_BVISEMPTY( &li->li_idassert_authcDN ) )
2150 			{
2151 				*binddn = li->li_idassert_authcDN;
2152 				*bindcred = li->li_idassert_passwd;
2153 				dobind = 1;
2154 			}
2155 		}
2156 		break;
2157 
2158 	default:
2159 		/* NOTE: rootdn can always idassert */
2160 		if ( BER_BVISNULL( &ndn )
2161 			&& li->li_idassert_authz == NULL
2162 			&& !( li->li_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
2163 		{
2164 			if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
2165 				rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
2166 				if ( sendok & LDAP_BACK_SENDERR ) {
2167 					send_ldap_result( op, rs );
2168 					dobind = -1;
2169 				}
2170 
2171 			} else {
2172 				rs->sr_err = LDAP_SUCCESS;
2173 				*binddn = slap_empty_bv;
2174 				*bindcred = slap_empty_bv;
2175 				break;
2176 			}
2177 
2178 			goto done;
2179 
2180 		} else if ( !be_isroot( op ) ) {
2181 			if ( li->li_idassert_passthru ) {
2182 				struct berval authcDN;
2183 
2184 				if ( BER_BVISNULL( &ndn ) ) {
2185 					authcDN = slap_empty_bv;
2186 
2187 				} else {
2188 					authcDN = ndn;
2189 				}
2190 				rs->sr_err = slap_sasl_matches( op, li->li_idassert_passthru,
2191 						&authcDN, &authcDN );
2192 				if ( rs->sr_err == LDAP_SUCCESS ) {
2193 					dobind = 0;
2194 					break;
2195 				}
2196 			}
2197 
2198 			if ( li->li_idassert_authz ) {
2199 				struct berval authcDN;
2200 
2201 				if ( BER_BVISNULL( &ndn ) ) {
2202 					authcDN = slap_empty_bv;
2203 
2204 				} else {
2205 					authcDN = ndn;
2206 				}
2207 				rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz,
2208 						&authcDN, &authcDN );
2209 				if ( rs->sr_err != LDAP_SUCCESS ) {
2210 					if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
2211 						if ( sendok & LDAP_BACK_SENDERR ) {
2212 							send_ldap_result( op, rs );
2213 							dobind = -1;
2214 						}
2215 
2216 					} else {
2217 						rs->sr_err = LDAP_SUCCESS;
2218 						*binddn = slap_empty_bv;
2219 						*bindcred = slap_empty_bv;
2220 						break;
2221 					}
2222 
2223 					goto done;
2224 				}
2225 			}
2226 		}
2227 
2228 		*binddn = li->li_idassert_authcDN;
2229 		*bindcred = li->li_idassert_passwd;
2230 		dobind = 1;
2231 		break;
2232 	}
2233 
2234 done:;
2235 	return dobind;
2236 }
2237 
2238 static int
2239 ldap_back_proxy_authz_bind(
2240 	ldapconn_t		*lc,
2241 	Operation		*op,
2242 	SlapReply		*rs,
2243 	ldap_back_send_t	sendok,
2244 	struct berval		*binddn,
2245 	struct berval		*bindcred )
2246 {
2247 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
2248 	struct berval	ndn;
2249 	int		msgid;
2250 	int		rc;
2251 
2252 	if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
2253 		ndn = op->o_conn->c_ndn;
2254 
2255 	} else {
2256 		ndn = op->o_ndn;
2257 	}
2258 
2259 	if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
2260 #ifdef HAVE_CYRUS_SASL
2261 		void		*defaults = NULL;
2262 		struct berval	authzID = BER_BVNULL;
2263 		int		freeauthz = 0;
2264 		LDAPControl **ctrlsp = NULL;
2265 		LDAPMessage *result = NULL;
2266 		const char *rmech = NULL;
2267 		const char *save_text = rs->sr_text;
2268 
2269 #ifdef SLAP_AUTH_DN
2270 		LDAPControl ctrl, *ctrls[2];
2271 		int msgid;
2272 #endif /* SLAP_AUTH_DN */
2273 
2274 		/* if SASL supports native authz, prepare for it */
2275 		if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
2276 				( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
2277 		{
2278 			switch ( li->li_idassert_mode ) {
2279 			case LDAP_BACK_IDASSERT_OTHERID:
2280 			case LDAP_BACK_IDASSERT_OTHERDN:
2281 				authzID = li->li_idassert_authzID;
2282 				break;
2283 
2284 			case LDAP_BACK_IDASSERT_ANONYMOUS:
2285 				BER_BVSTR( &authzID, "dn:" );
2286 				break;
2287 
2288 			case LDAP_BACK_IDASSERT_SELF:
2289 				if ( BER_BVISNULL( &ndn ) ) {
2290 					/* connection is not authc'd, so don't idassert */
2291 					BER_BVSTR( &authzID, "dn:" );
2292 					break;
2293 				}
2294 				authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
2295 				authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
2296 				AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
2297 				AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
2298 						ndn.bv_val, ndn.bv_len + 1 );
2299 				freeauthz = 1;
2300 				break;
2301 
2302 			default:
2303 				break;
2304 			}
2305 		}
2306 
2307 		if ( li->li_idassert_secprops != NULL ) {
2308 			rs->sr_err = ldap_set_option( lc->lc_ld,
2309 				LDAP_OPT_X_SASL_SECPROPS,
2310 				(void *)li->li_idassert_secprops );
2311 
2312 			if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
2313 				rs->sr_err = LDAP_OTHER;
2314 				if ( sendok & LDAP_BACK_SENDERR ) {
2315 					send_ldap_result( op, rs );
2316 				}
2317 				LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2318 				goto done;
2319 			}
2320 		}
2321 
2322 		defaults = lutil_sasl_defaults( lc->lc_ld,
2323 				li->li_idassert_sasl_mech.bv_val,
2324 				li->li_idassert_sasl_realm.bv_val,
2325 				li->li_idassert_authcID.bv_val,
2326 				li->li_idassert_passwd.bv_val,
2327 				authzID.bv_val );
2328 		if ( defaults == NULL ) {
2329 			rs->sr_err = LDAP_OTHER;
2330 			LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2331 			if ( sendok & LDAP_BACK_SENDERR ) {
2332 				send_ldap_result( op, rs );
2333 			}
2334 			goto done;
2335 		}
2336 
2337 #ifdef SLAP_AUTH_DN
2338 		if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) {
2339 			assert( BER_BVISNULL( binddn ) );
2340 
2341 			ctrl.ldctl_oid = LDAP_CONTROL_AUTHZID_REQUEST;
2342 			ctrl.ldctl_iscritical = 0;
2343 			BER_BVZERO( &ctrl.ldctl_value );
2344 			ctrls[0] = &ctrl;
2345 			ctrls[1] = NULL;
2346 			ctrlsp = ctrls;
2347 		}
2348 #endif /* SLAP_AUTH_DN */
2349 
2350 		do {
2351 			rs->sr_err = ldap_sasl_interactive_bind( lc->lc_ld, binddn->bv_val,
2352 				li->li_idassert_sasl_mech.bv_val,
2353 				ctrlsp, NULL, LDAP_SASL_QUIET, lutil_sasl_interact, defaults,
2354 				result, &rmech, &msgid );
2355 
2356 			if ( rs->sr_err != LDAP_SASL_BIND_IN_PROGRESS )
2357 				break;
2358 
2359 			ldap_msgfree( result );
2360 
2361 			if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
2362 				ldap_get_option( lc->lc_ld, LDAP_OPT_RESULT_CODE, (void*)&rs->sr_err );
2363 				ldap_get_option( lc->lc_ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&rs->sr_text );
2364 				break;
2365 			}
2366 		} while ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS );
2367 
2368 		ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
2369 		ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
2370 		ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
2371 
2372 		switch ( rs->sr_err ) {
2373 		case LDAP_SUCCESS:
2374 #ifdef SLAP_AUTH_DN
2375 			/* FIXME: right now, the only reason to check
2376 			 * response controls is RFC 3829 authzid */
2377 			if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) {
2378 				ctrlsp = NULL;
2379 				rc = ldap_parse_result( lc->lc_ld, result, NULL, NULL, NULL, NULL,
2380 					&ctrlsp, 0 );
2381 				if ( rc == LDAP_SUCCESS && ctrlsp ) {
2382 					LDAPControl *ctrl;
2383 
2384 					ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE,
2385 						ctrlsp, NULL );
2386 					if ( ctrl ) {
2387 						Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (authzid)\n",
2388 							op->o_log_prefix, ctrl->ldctl_value.bv_val, 0 );
2389 						if ( ctrl->ldctl_value.bv_len > STRLENOF("dn:") &&
2390 							strncasecmp( ctrl->ldctl_value.bv_val, "dn:", STRLENOF("dn:") ) == 0 )
2391 						{
2392 							struct berval bv;
2393 							bv.bv_val = &ctrl->ldctl_value.bv_val[STRLENOF("dn:")];
2394 							bv.bv_len = ctrl->ldctl_value.bv_len - STRLENOF("dn:");
2395 							ber_bvreplace( &lc->lc_bound_ndn, &bv );
2396 						}
2397 					}
2398 				}
2399 
2400 				ldap_controls_free( ctrlsp );
2401 
2402 			} else if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_WHOAMI ) {
2403 				struct berval *val = NULL;
2404 				rc = ldap_whoami_s( lc->lc_ld, &val, NULL, NULL );
2405 				if ( rc == LDAP_SUCCESS && val != NULL ) {
2406 					Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (whoami)\n",
2407 						op->o_log_prefix, val->bv_val, 0 );
2408 					if ( val->bv_len > STRLENOF("dn:") &&
2409 						strncasecmp( val->bv_val, "dn:", STRLENOF("dn:") ) == 0 )
2410 					{
2411 						struct berval bv;
2412 						bv.bv_val = &val->bv_val[STRLENOF("dn:")];
2413 						bv.bv_len = val->bv_len - STRLENOF("dn:");
2414 						ber_bvreplace( &lc->lc_bound_ndn, &bv );
2415 					}
2416 					ber_bvfree( val );
2417 				}
2418 			}
2419 
2420 			if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_MASK ) &&
2421 				BER_BVISNULL( &lc->lc_bound_ndn ) )
2422 			{
2423 				/* all in all, we only need it to be non-null */
2424 				/* FIXME: should this be configurable? */
2425 				static struct berval bv = BER_BVC("cn=authzdn");
2426 				ber_bvreplace( &lc->lc_bound_ndn, &bv );
2427 			}
2428 #endif /* SLAP_AUTH_DN */
2429 			LDAP_BACK_CONN_ISBOUND_SET( lc );
2430 			break;
2431 
2432 		case LDAP_LOCAL_ERROR:
2433 			/* list client API error codes that require
2434 			 * to taint the connection */
2435 			/* FIXME: should actually retry? */
2436 			LDAP_BACK_CONN_TAINTED_SET( lc );
2437 
2438 			/* fallthru */
2439 
2440 		default:
2441 			LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2442 			rs->sr_err = slap_map_api2result( rs );
2443 			if ( sendok & LDAP_BACK_SENDERR ) {
2444 				send_ldap_result( op, rs );
2445 			}
2446 			break;
2447 		}
2448 
2449 		if ( save_text != rs->sr_text ) {
2450 			ldap_memfree( (char *)rs->sr_text );
2451 			rs->sr_text = save_text;
2452 		}
2453 
2454 		ldap_msgfree( result );
2455 
2456 		lutil_sasl_freedefs( defaults );
2457 		if ( freeauthz ) {
2458 			slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
2459 		}
2460 
2461 		goto done;
2462 #endif /* HAVE_CYRUS_SASL */
2463 	}
2464 
2465 	switch ( li->li_idassert_authmethod ) {
2466 	case LDAP_AUTH_NONE:
2467 		/* FIXME: do we really need this? */
2468 		BER_BVSTR( binddn, "" );
2469 		BER_BVSTR( bindcred, "" );
2470 		/* fallthru */
2471 
2472 	case LDAP_AUTH_SIMPLE:
2473 		rs->sr_err = ldap_sasl_bind( lc->lc_ld,
2474 				binddn->bv_val, LDAP_SASL_SIMPLE,
2475 				bindcred, NULL, NULL, &msgid );
2476 		rc = ldap_back_op_result( lc, op, rs, msgid,
2477 			-1, ( sendok | LDAP_BACK_BINDING ) );
2478 
2479 		ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
2480 		ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
2481 		ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
2482 		break;
2483 
2484 	default:
2485 		/* unsupported! */
2486 		LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2487 		rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
2488 		if ( sendok & LDAP_BACK_SENDERR ) {
2489 			send_ldap_result( op, rs );
2490 		}
2491 		goto done;
2492 	}
2493 
2494 	if ( rc == LDAP_SUCCESS ) {
2495 		/* set rebind stuff in case of successful proxyAuthz bind,
2496 		 * so that referral chasing is attempted using the right
2497 		 * identity */
2498 		LDAP_BACK_CONN_ISBOUND_SET( lc );
2499 		if ( !BER_BVISNULL( binddn ) ) {
2500 			ber_bvreplace( &lc->lc_bound_ndn, binddn );
2501 		}
2502 
2503 		if ( !BER_BVISNULL( &lc->lc_cred ) ) {
2504 			memset( lc->lc_cred.bv_val, 0,
2505 					lc->lc_cred.bv_len );
2506 		}
2507 
2508 		if ( LDAP_BACK_SAVECRED( li ) ) {
2509 			if ( !BER_BVISNULL( bindcred ) ) {
2510 				ber_bvreplace( &lc->lc_cred, bindcred );
2511 				ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
2512 			}
2513 
2514 		} else {
2515 			lc->lc_cred.bv_len = 0;
2516 		}
2517 	}
2518 
2519 done:;
2520 	return LDAP_BACK_CONN_ISBOUND( lc );
2521 }
2522 
2523 /*
2524  * ldap_back_proxy_authz_ctrl() prepends a proxyAuthz control
2525  * to existing server-side controls if required; if not,
2526  * the existing server-side controls are placed in *pctrls.
2527  * The caller, after using the controls in client API
2528  * operations, if ( *pctrls != op->o_ctrls ), should
2529  * free( (*pctrls)[ 0 ] ) and free( *pctrls ).
2530  * The function returns success if the control could
2531  * be added if required, or if it did nothing; in the future,
2532  * it might return some error if it failed.
2533  *
2534  * if no bind took place yet, but the connection is bound
2535  * and the "proxyauthzdn" is set, then bind as "proxyauthzdn"
2536  * and explicitly add proxyAuthz the control to every operation
2537  * with the dn bound to the connection as control value.
2538  *
2539  * If no server-side controls are defined for the operation,
2540  * simply add the proxyAuthz control; otherwise, if the
2541  * proxyAuthz control is not already set, add it as
2542  * the first one
2543  *
2544  * FIXME: is controls order significant for security?
2545  * ANSWER: controls ordering and interoperability
2546  * must be indicated by the specs of each control; if none
2547  * is specified, the order is irrelevant.
2548  */
2549 int
2550 ldap_back_proxy_authz_ctrl(
2551 		Operation	*op,
2552 		SlapReply	*rs,
2553 		struct berval	*bound_ndn,
2554 		int		version,
2555 		slap_idassert_t	*si,
2556 		LDAPControl	*ctrl )
2557 {
2558 	slap_idassert_mode_t	mode;
2559 	struct berval		assertedID,
2560 				ndn;
2561 	int			isroot = 0;
2562 
2563 	rs->sr_err = SLAP_CB_CONTINUE;
2564 
2565 	/* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID,
2566 	 * but if it is not set this test fails.  We need a different
2567 	 * means to detect if idassert is enabled */
2568 	if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) )
2569 		&& ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) )
2570 		&& BER_BVISNULL( &si->si_bc.sb_saslmech ) )
2571 	{
2572 		goto done;
2573 	}
2574 
2575 	if ( !op->o_conn || op->o_do_not_cache || ( isroot = be_isroot( op ) ) ) {
2576 		goto done;
2577 	}
2578 
2579 	if ( op->o_tag == LDAP_REQ_BIND ) {
2580 		ndn = op->o_req_ndn;
2581 
2582 	} else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
2583 		ndn = op->o_conn->c_ndn;
2584 
2585 	} else {
2586 		ndn = op->o_ndn;
2587 	}
2588 
2589 	if ( si->si_mode == LDAP_BACK_IDASSERT_LEGACY ) {
2590 		if ( op->o_proxy_authz ) {
2591 			/*
2592 			 * FIXME: we do not want to perform proxyAuthz
2593 			 * on behalf of the client, because this would
2594 			 * be performed with "proxyauthzdn" privileges.
2595 			 *
2596 			 * This might actually be too strict, since
2597 			 * the "proxyauthzdn" authzTo, and each entry's
2598 			 * authzFrom attributes may be crafted
2599 			 * to avoid unwanted proxyAuthz to take place.
2600 			 */
2601 #if 0
2602 			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
2603 			rs->sr_text = "proxyAuthz not allowed within namingContext";
2604 #endif
2605 			goto done;
2606 		}
2607 
2608 		if ( !BER_BVISNULL( bound_ndn ) ) {
2609 			goto done;
2610 		}
2611 
2612 		if ( BER_BVISNULL( &ndn ) ) {
2613 			goto done;
2614 		}
2615 
2616 		if ( BER_BVISNULL( &si->si_bc.sb_binddn ) ) {
2617 			goto done;
2618 		}
2619 
2620 	} else if ( si->si_bc.sb_method == LDAP_AUTH_SASL ) {
2621 		if ( ( si->si_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
2622 		{
2623 			/* already asserted in SASL via native authz */
2624 			goto done;
2625 		}
2626 
2627 	} else if ( si->si_authz && !isroot ) {
2628 		int		rc;
2629 		struct berval authcDN;
2630 
2631 		if ( BER_BVISNULL( &ndn ) ) {
2632 			authcDN = slap_empty_bv;
2633 		} else {
2634 			authcDN = ndn;
2635 		}
2636 		rc = slap_sasl_matches( op, si->si_authz,
2637 				&authcDN, &authcDN );
2638 		if ( rc != LDAP_SUCCESS ) {
2639 			if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
2640 				/* ndn is not authorized
2641 				 * to use idassert */
2642 				rs->sr_err = rc;
2643 			}
2644 			goto done;
2645 		}
2646 	}
2647 
2648 	if ( op->o_proxy_authz ) {
2649 		/*
2650 		 * FIXME: we can:
2651 		 * 1) ignore the already set proxyAuthz control
2652 		 * 2) leave it in place, and don't set ours
2653 		 * 3) add both
2654 		 * 4) reject the operation
2655 		 *
2656 		 * option (4) is very drastic
2657 		 * option (3) will make the remote server reject
2658 		 * the operation, thus being equivalent to (4)
2659 		 * option (2) will likely break the idassert
2660 		 * assumptions, so we cannot accept it;
2661 		 * option (1) means that we are contradicting
2662 		 * the client's reques.
2663 		 *
2664 		 * I think (4) is the only correct choice.
2665 		 */
2666 		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
2667 		rs->sr_text = "proxyAuthz not allowed within namingContext";
2668 	}
2669 
2670 	if ( op->o_is_auth_check ) {
2671 		mode = LDAP_BACK_IDASSERT_NOASSERT;
2672 
2673 	} else {
2674 		mode = si->si_mode;
2675 	}
2676 
2677 	switch ( mode ) {
2678 	case LDAP_BACK_IDASSERT_LEGACY:
2679 		/* original behavior:
2680 		 * assert the client's identity */
2681 	case LDAP_BACK_IDASSERT_SELF:
2682 		assertedID = ndn;
2683 		break;
2684 
2685 	case LDAP_BACK_IDASSERT_ANONYMOUS:
2686 		/* assert "anonymous" */
2687 		assertedID = slap_empty_bv;
2688 		break;
2689 
2690 	case LDAP_BACK_IDASSERT_NOASSERT:
2691 		/* don't assert; bind as proxyauthzdn */
2692 		goto done;
2693 
2694 	case LDAP_BACK_IDASSERT_OTHERID:
2695 	case LDAP_BACK_IDASSERT_OTHERDN:
2696 		/* assert idassert DN */
2697 		assertedID = si->si_bc.sb_authzId;
2698 		break;
2699 
2700 	default:
2701 		assert( 0 );
2702 	}
2703 
2704 	/* if we got here, "" is allowed to proxyAuthz */
2705 	if ( BER_BVISNULL( &assertedID ) ) {
2706 		assertedID = slap_empty_bv;
2707 	}
2708 
2709 	/* don't idassert the bound DN (ITS#4497) */
2710 	if ( dn_match( &assertedID, bound_ndn ) ) {
2711 		goto done;
2712 	}
2713 
2714 	ctrl->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
2715 	ctrl->ldctl_iscritical = ( ( si->si_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) == LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL );
2716 
2717 	switch ( si->si_mode ) {
2718 	/* already in u:ID or dn:DN form */
2719 	case LDAP_BACK_IDASSERT_OTHERID:
2720 	case LDAP_BACK_IDASSERT_OTHERDN:
2721 		ber_dupbv_x( &ctrl->ldctl_value, &assertedID, op->o_tmpmemctx );
2722 		rs->sr_err = LDAP_SUCCESS;
2723 		break;
2724 
2725 	/* needs the dn: prefix */
2726 	default:
2727 		ctrl->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" );
2728 		ctrl->ldctl_value.bv_val = op->o_tmpalloc( ctrl->ldctl_value.bv_len + 1,
2729 				op->o_tmpmemctx );
2730 		AC_MEMCPY( ctrl->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) );
2731 		AC_MEMCPY( &ctrl->ldctl_value.bv_val[ STRLENOF( "dn:" ) ],
2732 				assertedID.bv_val, assertedID.bv_len + 1 );
2733 		rs->sr_err = LDAP_SUCCESS;
2734 		break;
2735 	}
2736 
2737 	/* Older versions of <draft-weltman-ldapv3-proxy> required
2738 	 * to encode the value of the authzID (and called it proxyDN);
2739 	 * this hack provides compatibility with those DSAs that
2740 	 * implement it this way */
2741 	if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
2742 		struct berval		authzID = ctrl->ldctl_value;
2743 		BerElementBuffer	berbuf;
2744 		BerElement		*ber = (BerElement *)&berbuf;
2745 		ber_tag_t		tag;
2746 
2747 		ber_init2( ber, 0, LBER_USE_DER );
2748 		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
2749 
2750 		tag = ber_printf( ber, "O", &authzID );
2751 		if ( tag == LBER_ERROR ) {
2752 			rs->sr_err = LDAP_OTHER;
2753 			goto free_ber;
2754 		}
2755 
2756 		if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
2757 			rs->sr_err = LDAP_OTHER;
2758 			goto free_ber;
2759 		}
2760 
2761 		rs->sr_err = LDAP_SUCCESS;
2762 
2763 free_ber:;
2764 		op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
2765 		ber_free_buf( ber );
2766 
2767 		if ( rs->sr_err != LDAP_SUCCESS ) {
2768 			goto done;
2769 		}
2770 
2771 	} else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
2772 		struct berval		authzID = ctrl->ldctl_value,
2773 					tmp;
2774 		BerElementBuffer	berbuf;
2775 		BerElement		*ber = (BerElement *)&berbuf;
2776 		ber_tag_t		tag;
2777 
2778 		if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) {
2779 			rs->sr_err = LDAP_PROTOCOL_ERROR;
2780 			goto done;
2781 		}
2782 
2783 		tmp = authzID;
2784 		tmp.bv_val += STRLENOF( "dn:" );
2785 		tmp.bv_len -= STRLENOF( "dn:" );
2786 
2787 		ber_init2( ber, 0, LBER_USE_DER );
2788 		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
2789 
2790 		/* apparently, Mozilla API encodes this
2791 		 * as "SEQUENCE { LDAPDN }" */
2792 		tag = ber_printf( ber, "{O}", &tmp );
2793 		if ( tag == LBER_ERROR ) {
2794 			rs->sr_err = LDAP_OTHER;
2795 			goto free_ber2;
2796 		}
2797 
2798 		if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
2799 			rs->sr_err = LDAP_OTHER;
2800 			goto free_ber2;
2801 		}
2802 
2803 		ctrl->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
2804 		rs->sr_err = LDAP_SUCCESS;
2805 
2806 free_ber2:;
2807 		op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
2808 		ber_free_buf( ber );
2809 
2810 		if ( rs->sr_err != LDAP_SUCCESS ) {
2811 			goto done;
2812 		}
2813 	}
2814 
2815 done:;
2816 
2817 	return rs->sr_err;
2818 }
2819 
2820 /*
2821  * Add controls;
2822  *
2823  * if any needs to be added, it is prepended to existing ones,
2824  * in a newly allocated array.  The companion function
2825  * ldap_back_controls_free() must be used to restore the original
2826  * status of op->o_ctrls.
2827  */
2828 int
2829 ldap_back_controls_add(
2830 		Operation	*op,
2831 		SlapReply	*rs,
2832 		ldapconn_t	*lc,
2833 		LDAPControl	***pctrls )
2834 {
2835 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
2836 
2837 	LDAPControl	**ctrls = NULL;
2838 	/* set to the maximum number of controls this backend can add */
2839 	LDAPControl	c[ 2 ] = { { 0 } };
2840 	int		n = 0, i, j1 = 0, j2 = 0;
2841 
2842 	*pctrls = NULL;
2843 
2844 	rs->sr_err = LDAP_SUCCESS;
2845 
2846 	/* don't add controls if protocol is not LDAPv3 */
2847 	switch ( li->li_version ) {
2848 	case LDAP_VERSION3:
2849 		break;
2850 
2851 	case 0:
2852 		if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
2853 			break;
2854 		}
2855 		/* fall thru */
2856 
2857 	default:
2858 		goto done;
2859 	}
2860 
2861 	/* put controls that go __before__ existing ones here */
2862 
2863 	/* proxyAuthz for identity assertion */
2864 	switch ( ldap_back_proxy_authz_ctrl( op, rs, &lc->lc_bound_ndn,
2865 		li->li_version, &li->li_idassert, &c[ j1 ] ) )
2866 	{
2867 	case SLAP_CB_CONTINUE:
2868 		break;
2869 
2870 	case LDAP_SUCCESS:
2871 		j1++;
2872 		break;
2873 
2874 	default:
2875 		goto done;
2876 	}
2877 
2878 	/* put controls that go __after__ existing ones here */
2879 
2880 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
2881 	/* FIXME: according to <draft-wahl-ldap-session>,
2882 	 * the server should check if the control can be added
2883 	 * based on the identity of the client and so */
2884 
2885 	/* session tracking */
2886 	if ( LDAP_BACK_ST_REQUEST( li ) ) {
2887 		switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) {
2888 		case SLAP_CB_CONTINUE:
2889 			break;
2890 
2891 		case LDAP_SUCCESS:
2892 			j2++;
2893 			break;
2894 
2895 		default:
2896 			goto done;
2897 		}
2898 	}
2899 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
2900 
2901 	if ( rs->sr_err == SLAP_CB_CONTINUE ) {
2902 		rs->sr_err = LDAP_SUCCESS;
2903 	}
2904 
2905 	/* if nothing to do, just bail out */
2906 	if ( j1 == 0 && j2 == 0 ) {
2907 		goto done;
2908 	}
2909 
2910 	assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) );
2911 
2912 	if ( op->o_ctrls ) {
2913 		for ( n = 0; op->o_ctrls[ n ]; n++ )
2914 			/* just count ctrls */ ;
2915 	}
2916 
2917 	ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ),
2918 			op->o_tmpmemctx );
2919 	if ( j1 ) {
2920 		ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
2921 		*ctrls[ 0 ] = c[ 0 ];
2922 		for ( i = 1; i < j1; i++ ) {
2923 			ctrls[ i ] = &ctrls[ 0 ][ i ];
2924 			*ctrls[ i ] = c[ i ];
2925 		}
2926 	}
2927 
2928 	i = 0;
2929 	if ( op->o_ctrls ) {
2930 		for ( i = 0; op->o_ctrls[ i ]; i++ ) {
2931 			ctrls[ i + j1 ] = op->o_ctrls[ i ];
2932 		}
2933 	}
2934 
2935 	n += j1;
2936 	if ( j2 ) {
2937 		ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1;
2938 		*ctrls[ n ] = c[ j1 ];
2939 		for ( i = 1; i < j2; i++ ) {
2940 			ctrls[ n + i ] = &ctrls[ n ][ i ];
2941 			*ctrls[ n + i ] = c[ i ];
2942 		}
2943 	}
2944 
2945 	ctrls[ n + j2 ] = NULL;
2946 
2947 done:;
2948 	if ( ctrls == NULL ) {
2949 		ctrls = op->o_ctrls;
2950 	}
2951 
2952 	*pctrls = ctrls;
2953 
2954 	return rs->sr_err;
2955 }
2956 
2957 int
2958 ldap_back_controls_free( Operation *op, SlapReply *rs, LDAPControl ***pctrls )
2959 {
2960 	LDAPControl	**ctrls = *pctrls;
2961 
2962 	/* we assume that the controls added by the proxy come first,
2963 	 * so as soon as we find op->o_ctrls[ 0 ] we can stop */
2964 	if ( ctrls && ctrls != op->o_ctrls ) {
2965 		int		i = 0, n = 0, n_added;
2966 		LDAPControl	*lower, *upper;
2967 
2968 		assert( ctrls[ 0 ] != NULL );
2969 
2970 		for ( n = 0; ctrls[ n ] != NULL; n++ )
2971 			/* count 'em */ ;
2972 
2973 		if ( op->o_ctrls ) {
2974 			for ( i = 0; op->o_ctrls[ i ] != NULL; i++ )
2975 				/* count 'em */ ;
2976 		}
2977 
2978 		n_added = n - i;
2979 		lower = (LDAPControl *)&ctrls[ n ];
2980 		upper = &lower[ n_added ];
2981 
2982 		for ( i = 0; ctrls[ i ] != NULL; i++ ) {
2983 			if ( ctrls[ i ] < lower || ctrls[ i ] >= upper ) {
2984 				/* original; don't touch */
2985 				continue;
2986 			}
2987 
2988 			if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) {
2989 				op->o_tmpfree( ctrls[ i ]->ldctl_value.bv_val, op->o_tmpmemctx );
2990 			}
2991 		}
2992 
2993 		op->o_tmpfree( ctrls, op->o_tmpmemctx );
2994 	}
2995 
2996 	*pctrls = NULL;
2997 
2998 	return 0;
2999 }
3000 
3001 int
3002 ldap_back_conn2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen )
3003 {
3004 	char tbuf[ SLAP_TEXT_BUFLEN ];
3005 	char *ptr = buf, *end = buf + buflen;
3006 	int len;
3007 
3008 	if ( ptr + sizeof("conn=") > end ) return -1;
3009 	ptr = lutil_strcopy( ptr, "conn=" );
3010 
3011 	len = ldap_back_connid2str( lc, ptr, (ber_len_t)(end - ptr) );
3012 	ptr += len;
3013 	if ( ptr >= end ) return -1;
3014 
3015 	if ( !BER_BVISNULL( &lc->lcb_local_ndn ) ) {
3016 		if ( ptr + sizeof(" DN=\"\"") + lc->lcb_local_ndn.bv_len > end ) return -1;
3017 		ptr = lutil_strcopy( ptr, " DN=\"" );
3018 		ptr = lutil_strncopy( ptr, lc->lcb_local_ndn.bv_val, lc->lcb_local_ndn.bv_len );
3019 		*ptr++ = '"';
3020 	}
3021 
3022 	if ( lc->lcb_create_time != 0 ) {
3023 		len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_create_time );
3024 		if ( ptr + sizeof(" created=") + len >= end ) return -1;
3025 		ptr = lutil_strcopy( ptr, " created=" );
3026 		ptr = lutil_strcopy( ptr, tbuf );
3027 	}
3028 
3029 	if ( lc->lcb_time != 0 ) {
3030 		len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_time );
3031 		if ( ptr + sizeof(" modified=") + len >= end ) return -1;
3032 		ptr = lutil_strcopy( ptr, " modified=" );
3033 		ptr = lutil_strcopy( ptr, tbuf );
3034 	}
3035 
3036 	len = snprintf( tbuf, sizeof(tbuf), "%u", lc->lcb_refcnt );
3037 	if ( ptr + sizeof(" refcnt=") + len >= end ) return -1;
3038 	ptr = lutil_strcopy( ptr, " refcnt=" );
3039 	ptr = lutil_strcopy( ptr, tbuf );
3040 
3041 	return ptr - buf;
3042 }
3043 
3044 int
3045 ldap_back_connid2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen )
3046 {
3047 	static struct berval conns[] = {
3048 		BER_BVC("ROOTDN"),
3049 		BER_BVC("ROOTDN-TLS"),
3050 		BER_BVC("ANON"),
3051 		BER_BVC("ANON-TLS"),
3052 		BER_BVC("BIND"),
3053 		BER_BVC("BIND-TLS"),
3054 		BER_BVNULL
3055 	};
3056 
3057 	int len = 0;
3058 
3059 	if ( LDAP_BACK_PCONN_ISPRIV( (const ldapconn_t *)lc ) ) {
3060 		long cid;
3061 		struct berval *bv;
3062 
3063 		cid = (long)lc->lcb_conn;
3064 		assert( cid >= LDAP_BACK_PCONN_FIRST && cid < LDAP_BACK_PCONN_LAST );
3065 
3066 		bv = &conns[ cid ];
3067 
3068 		if ( bv->bv_len >= buflen ) {
3069 			return bv->bv_len + 1;
3070 		}
3071 
3072 		len = bv->bv_len;
3073 		lutil_strncopy( buf, bv->bv_val, bv->bv_len + 1 );
3074 
3075 	} else {
3076 		len = snprintf( buf, buflen, "%lu", lc->lcb_conn->c_connid );
3077 	}
3078 
3079 	return len;
3080 }
3081