xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/request.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: request.c,v 1.2 2020/08/11 13:15:37 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2020 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
18  * All rights reserved.
19  */
20 /* This notice applies to changes, created by or for Novell, Inc.,
21  * to preexisting works for which notices appear elsewhere in this file.
22  *
23  * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
24  *
25  * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
26  * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
27  * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
28  * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
29  * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
30  * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
31  * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
32  * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
33  *---
34  * Modification to OpenLDAP source by Novell, Inc.
35  * April 2000 sfs  Added code to chase V3 referrals
36  *  request.c - sending of ldap requests; handling of referrals
37  *---
38  * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
39  * can be found in the file "build/LICENSE-2.0.1" in this distribution
40  * of OpenLDAP Software.
41  */
42 
43 #include <sys/cdefs.h>
44 __RCSID("$NetBSD: request.c,v 1.2 2020/08/11 13:15:37 christos Exp $");
45 
46 #include "portable.h"
47 
48 #include <stdio.h>
49 
50 #include <ac/stdlib.h>
51 
52 #include <ac/errno.h>
53 #include <ac/socket.h>
54 #include <ac/string.h>
55 #include <ac/time.h>
56 #include <ac/unistd.h>
57 
58 #include "ldap-int.h"
59 #include "lber.h"
60 
61 /* used by ldap_send_server_request and ldap_new_connection */
62 #ifdef LDAP_R_COMPILE
63 #define LDAP_CONN_LOCK_IF(nolock) \
64 	{ if (nolock) LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); }
65 #define LDAP_CONN_UNLOCK_IF(nolock) \
66 	{ if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); }
67 #define LDAP_REQ_LOCK_IF(nolock) \
68 	{ if (nolock) LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); }
69 #define LDAP_REQ_UNLOCK_IF(nolock) \
70 	{ if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); }
71 #define LDAP_RES_LOCK_IF(nolock) \
72 	{ if (nolock) LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); }
73 #define LDAP_RES_UNLOCK_IF(nolock) \
74 	{ if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); }
75 #else
76 #define LDAP_CONN_LOCK_IF(nolock)
77 #define LDAP_CONN_UNLOCK_IF(nolock)
78 #define LDAP_REQ_LOCK_IF(nolock)
79 #define LDAP_REQ_UNLOCK_IF(nolock)
80 #define LDAP_RES_LOCK_IF(nolock)
81 #define LDAP_RES_UNLOCK_IF(nolock)
82 #endif
83 
84 static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPURLDesc *srv, int any ));
85 static void use_connection LDAP_P(( LDAP *ld, LDAPConn *lc ));
86 static void ldap_free_request_int LDAP_P(( LDAP *ld, LDAPRequest *lr ));
87 
88 static BerElement *
89 re_encode_request( LDAP *ld,
90 	BerElement *origber,
91 	ber_int_t msgid,
92 	int sref,
93 	LDAPURLDesc *srv,
94 	int *type );
95 
96 BerElement *
97 ldap_alloc_ber_with_options( LDAP *ld )
98 {
99 	BerElement	*ber;
100 
101 	ber = ber_alloc_t( ld->ld_lberoptions );
102 	if ( ber == NULL ) {
103 		ld->ld_errno = LDAP_NO_MEMORY;
104 	}
105 
106 	return( ber );
107 }
108 
109 
110 void
111 ldap_set_ber_options( LDAP *ld, BerElement *ber )
112 {
113 	/* ld_lberoptions is constant, hence no lock */
114 	ber->ber_options = ld->ld_lberoptions;
115 }
116 
117 
118 /* sets needed mutexes - no mutexes set to this point */
119 ber_int_t
120 ldap_send_initial_request(
121 	LDAP *ld,
122 	ber_tag_t msgtype,
123 	const char *dn,
124 	BerElement *ber,
125 	ber_int_t msgid)
126 {
127 	int rc = 1;
128 	ber_socket_t sd = AC_SOCKET_INVALID;
129 
130 	Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 );
131 
132 	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
133 	if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ) == -1 ) {
134 		/* not connected yet */
135 		rc = ldap_open_defconn( ld );
136 		if ( rc == 0 ) {
137 			ber_sockbuf_ctrl( ld->ld_defconn->lconn_sb,
138 				LBER_SB_OPT_GET_FD, &sd );
139 		}
140 	}
141 	if ( ld->ld_defconn && ld->ld_defconn->lconn_status == LDAP_CONNST_CONNECTING )
142 		rc = ldap_int_check_async_open( ld, sd );
143 	if( rc < 0 ) {
144 		ber_free( ber, 1 );
145 		LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
146 		return( -1 );
147 	} else if ( rc == 0 ) {
148 		Debug( LDAP_DEBUG_TRACE,
149 			"ldap_open_defconn: successful\n",
150 			0, 0, 0 );
151 	}
152 
153 #ifdef LDAP_CONNECTIONLESS
154 	if (LDAP_IS_UDP(ld)) {
155 		if (msgtype == LDAP_REQ_BIND) {
156 			LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
157 			if (ld->ld_options.ldo_cldapdn)
158 				ldap_memfree(ld->ld_options.ldo_cldapdn);
159 			ld->ld_options.ldo_cldapdn = ldap_strdup(dn);
160 			ber_free( ber, 1 );
161 			LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
162 			LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
163 			return 0;
164 		}
165 		if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH)
166 		{
167 			ber_free( ber, 1 );
168 			LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
169 			return LDAP_PARAM_ERROR;
170 		}
171 	}
172 #endif
173 	LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
174 	rc = ldap_send_server_request( ld, ber, msgid, NULL,
175 		NULL, NULL, NULL, 0, 0 );
176 	LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
177 	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
178 	return(rc);
179 }
180 
181 
182 /* protected by conn_mutex */
183 int
184 ldap_int_flush_request(
185 	LDAP *ld,
186 	LDAPRequest *lr )
187 {
188 	LDAPConn *lc = lr->lr_conn;
189 
190 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
191 	if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) {
192 		if (( sock_errno() == EAGAIN ) || ( sock_errno() == ENOTCONN )) {
193 			/* ENOTCONN is returned in Solaris 10 */
194 			/* need to continue write later */
195 			lr->lr_status = LDAP_REQST_WRITING;
196 			ldap_mark_select_write( ld, lc->lconn_sb );
197 			ld->ld_errno = LDAP_BUSY;
198 			return -2;
199 		} else {
200 			ld->ld_errno = LDAP_SERVER_DOWN;
201 			ldap_free_request( ld, lr );
202 			ldap_free_connection( ld, lc, 0, 0 );
203 			return( -1 );
204 		}
205 	} else {
206 		if ( lr->lr_parent == NULL ) {
207 			lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
208 			lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
209 		}
210 		lr->lr_status = LDAP_REQST_INPROGRESS;
211 
212 		/* sent -- waiting for a response */
213 		ldap_mark_select_read( ld, lc->lconn_sb );
214 		ldap_clear_select_write( ld, lc->lconn_sb );
215 	}
216 	return 0;
217 }
218 
219 /*
220  * protected by req_mutex
221  * if m_noconn then protect using conn_lock
222  * else already protected with conn_lock
223  * if m_res then also protected by res_mutex
224  */
225 
226 int
227 ldap_send_server_request(
228 	LDAP *ld,
229 	BerElement *ber,
230 	ber_int_t msgid,
231 	LDAPRequest *parentreq,
232 	LDAPURLDesc **srvlist,
233 	LDAPConn *lc,
234 	LDAPreqinfo *bind,
235 	int m_noconn,
236 	int m_res )
237 {
238 	LDAPRequest	*lr;
239 	int		incparent, rc;
240 
241 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
242 	Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 );
243 
244 	incparent = 0;
245 	ld->ld_errno = LDAP_SUCCESS;	/* optimistic */
246 
247 	LDAP_CONN_LOCK_IF(m_noconn);
248 	if ( lc == NULL ) {
249 		if ( srvlist == NULL ) {
250 			lc = ld->ld_defconn;
251 		} else {
252 			lc = find_connection( ld, *srvlist, 1 );
253 			if ( lc == NULL ) {
254 				if ( (bind != NULL) && (parentreq != NULL) ) {
255 					/* Remember the bind in the parent */
256 					incparent = 1;
257 					++parentreq->lr_outrefcnt;
258 				}
259 				lc = ldap_new_connection( ld, srvlist, 0,
260 					1, bind, 1, m_res );
261 			}
262 		}
263 	}
264 
265 	/* async connect... */
266 	if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) {
267 		ber_socket_t	sd = AC_SOCKET_ERROR;
268 		struct timeval	tv = { 0 };
269 
270 		ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd );
271 
272 		/* poll ... */
273 		switch ( ldap_int_poll( ld, sd, &tv, 1 ) ) {
274 		case 0:
275 			/* go on! */
276 			lc->lconn_status = LDAP_CONNST_CONNECTED;
277 			break;
278 
279 		case -2:
280 			/* async only occurs if a network timeout is set */
281 
282 			/* honor network timeout */
283 			LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
284 			if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec )
285 			{
286 				/* caller will have to call again */
287 				ld->ld_errno = LDAP_X_CONNECTING;
288 			}
289 			LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
290 			/* fallthru */
291 
292 		default:
293 			/* error */
294 			break;
295 		}
296 	}
297 
298 	if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
299 		if ( ld->ld_errno == LDAP_SUCCESS ) {
300 			ld->ld_errno = LDAP_SERVER_DOWN;
301 		}
302 
303 		ber_free( ber, 1 );
304 		if ( incparent ) {
305 			/* Forget about the bind */
306 			--parentreq->lr_outrefcnt;
307 		}
308 		LDAP_CONN_UNLOCK_IF(m_noconn);
309 		return( -1 );
310 	}
311 
312 	use_connection( ld, lc );
313 
314 #ifdef LDAP_CONNECTIONLESS
315 	if ( LDAP_IS_UDP( ld )) {
316 		BerElement tmpber = *ber;
317 		ber_rewind( &tmpber );
318 		LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
319 		rc = ber_write( &tmpber, ld->ld_options.ldo_peer,
320 			sizeof( struct sockaddr_storage ), 0 );
321 		LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
322 		if ( rc == -1 ) {
323 			ld->ld_errno = LDAP_ENCODING_ERROR;
324 			ber_free( ber, 1 );
325 			LDAP_CONN_UNLOCK_IF(m_noconn);
326 			return rc;
327 		}
328 	}
329 #endif
330 
331 	/* If we still have an incomplete write, try to finish it before
332 	 * dealing with the new request. If we don't finish here, return
333 	 * LDAP_BUSY and let the caller retry later. We only allow a single
334 	 * request to be in WRITING state.
335 	 */
336 	rc = 0;
337 	if ( ld->ld_requests &&
338 		ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
339 		ldap_int_flush_request( ld, ld->ld_requests ) < 0 )
340 	{
341 		rc = -1;
342 	}
343 	if ( rc ) {
344 		ber_free( ber, 1 );
345 		LDAP_CONN_UNLOCK_IF(m_noconn);
346 		return rc;
347 	}
348 
349 	lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) );
350 	if ( lr == NULL ) {
351 		ld->ld_errno = LDAP_NO_MEMORY;
352 		ldap_free_connection( ld, lc, 0, 0 );
353 		ber_free( ber, 1 );
354 		if ( incparent ) {
355 			/* Forget about the bind */
356 			--parentreq->lr_outrefcnt;
357 		}
358 		LDAP_CONN_UNLOCK_IF(m_noconn);
359 		return( -1 );
360 	}
361 	lr->lr_msgid = msgid;
362 	lr->lr_status = LDAP_REQST_INPROGRESS;
363 	lr->lr_res_errno = LDAP_SUCCESS;	/* optimistic */
364 	lr->lr_ber = ber;
365 	lr->lr_conn = lc;
366 	if ( parentreq != NULL ) {	/* sub-request */
367 		if ( !incparent ) {
368 			/* Increment if we didn't do it before the bind */
369 			++parentreq->lr_outrefcnt;
370 		}
371 		lr->lr_origid = parentreq->lr_origid;
372 		lr->lr_parentcnt = ++parentreq->lr_parentcnt;
373 		lr->lr_parent = parentreq;
374 		lr->lr_refnext = parentreq->lr_child;
375 		parentreq->lr_child = lr;
376 	} else {			/* original request */
377 		lr->lr_origid = lr->lr_msgid;
378 	}
379 
380 	/* Extract requestDN for future reference */
381 #ifdef LDAP_CONNECTIONLESS
382 	if ( !LDAP_IS_UDP(ld) )
383 #endif
384 	{
385 		BerElement tmpber = *ber;
386 		ber_int_t	bint;
387 		ber_tag_t	tag, rtag;
388 
389 		ber_reset( &tmpber, 1 );
390 		rtag = ber_scanf( &tmpber, "{it", /*}*/ &bint, &tag );
391 		switch ( tag ) {
392 		case LDAP_REQ_BIND:
393 			rtag = ber_scanf( &tmpber, "{i" /*}*/, &bint );
394 			break;
395 		case LDAP_REQ_DELETE:
396 			break;
397 		default:
398 			rtag = ber_scanf( &tmpber, "{" /*}*/ );
399 		case LDAP_REQ_ABANDON:
400 			break;
401 		}
402 		if ( tag != LDAP_REQ_ABANDON ) {
403 			ber_skip_tag( &tmpber, &lr->lr_dn.bv_len );
404 			lr->lr_dn.bv_val = tmpber.ber_ptr;
405 		}
406 	}
407 
408 	lr->lr_prev = NULL;
409 	lr->lr_next = ld->ld_requests;
410 	if ( lr->lr_next != NULL ) {
411 		lr->lr_next->lr_prev = lr;
412 	}
413 	ld->ld_requests = lr;
414 
415 	ld->ld_errno = LDAP_SUCCESS;
416 	if ( ldap_int_flush_request( ld, lr ) == -1 ) {
417 		msgid = -1;
418 	}
419 
420 	LDAP_CONN_UNLOCK_IF(m_noconn);
421 	return( msgid );
422 }
423 
424 /* return 0 if no StartTLS ext, 1 if present, 2 if critical */
425 static int
426 find_tls_ext( LDAPURLDesc *srv )
427 {
428 	int i, crit;
429 	char *ext;
430 
431 	if ( !srv->lud_exts )
432 		return 0;
433 
434 	for (i=0; srv->lud_exts[i]; i++) {
435 		crit = 0;
436 		ext = srv->lud_exts[i];
437 		if ( ext[0] == '!') {
438 			ext++;
439 			crit = 1;
440 		}
441 		if ( !strcasecmp( ext, "StartTLS" ) ||
442 			!strcasecmp( ext, "X-StartTLS" ) ||
443 			!strcmp( ext, LDAP_EXOP_START_TLS )) {
444 			return crit + 1;
445 		}
446 	}
447 	return 0;
448 }
449 
450 /*
451  * always protected by conn_mutex
452  * optionally protected by req_mutex and res_mutex
453  */
454 LDAPConn *
455 ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
456 	int connect, LDAPreqinfo *bind, int m_req, int m_res )
457 {
458 	LDAPConn	*lc;
459 	int		async = 0;
460 
461 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
462 	Debug( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n",
463 		use_ldsb, connect, (bind != NULL) );
464 	/*
465 	 * make a new LDAP server connection
466 	 * XXX open connection synchronously for now
467 	 */
468 	lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ) );
469 	if ( lc == NULL ) {
470 		ld->ld_errno = LDAP_NO_MEMORY;
471 		return( NULL );
472 	}
473 
474 	if ( use_ldsb ) {
475 		assert( ld->ld_sb != NULL );
476 		lc->lconn_sb = ld->ld_sb;
477 
478 	} else {
479 		lc->lconn_sb = ber_sockbuf_alloc();
480 		if ( lc->lconn_sb == NULL ) {
481 			LDAP_FREE( (char *)lc );
482 			ld->ld_errno = LDAP_NO_MEMORY;
483 			return( NULL );
484 		}
485 	}
486 
487 	if ( connect ) {
488 		LDAPURLDesc	**srvp, *srv = NULL;
489 
490 		async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );
491 
492 		for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) {
493 			int		rc;
494 
495 			rc = ldap_int_open_connection( ld, lc, *srvp, async );
496 			if ( rc != -1 ) {
497 				srv = *srvp;
498 
499 				/* If we fully connected, async is moot */
500 				if ( rc == 0 )
501 					async = 0;
502 
503 				if ( ld->ld_urllist_proc && ( !async || rc != -2 ) ) {
504 					ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params );
505 				}
506 
507 				break;
508 			}
509 		}
510 
511 		if ( srv == NULL ) {
512 			if ( !use_ldsb ) {
513 				ber_sockbuf_free( lc->lconn_sb );
514 			}
515 			LDAP_FREE( (char *)lc );
516 			ld->ld_errno = LDAP_SERVER_DOWN;
517 			return( NULL );
518 		}
519 
520 		lc->lconn_server = ldap_url_dup( srv );
521 		if ( !lc->lconn_server ) {
522 			if ( !use_ldsb )
523 				ber_sockbuf_free( lc->lconn_sb );
524 			LDAP_FREE( (char *)lc );
525 			ld->ld_errno = LDAP_NO_MEMORY;
526 			return( NULL );
527 		}
528 	}
529 
530 	lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED;
531 	lc->lconn_next = ld->ld_conns;
532 	ld->ld_conns = lc;
533 
534 	if ( connect ) {
535 #ifdef HAVE_TLS
536 		if ( lc->lconn_server->lud_exts ) {
537 			int rc, ext = find_tls_ext( lc->lconn_server );
538 			if ( ext ) {
539 				LDAPConn	*savedefconn;
540 
541 				savedefconn = ld->ld_defconn;
542 				++lc->lconn_refcnt;	/* avoid premature free */
543 				ld->ld_defconn = lc;
544 
545 				LDAP_REQ_UNLOCK_IF(m_req);
546 				LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
547 				LDAP_RES_UNLOCK_IF(m_res);
548 				rc = ldap_start_tls_s( ld, NULL, NULL );
549 				LDAP_RES_LOCK_IF(m_res);
550 				LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
551 				LDAP_REQ_LOCK_IF(m_req);
552 				ld->ld_defconn = savedefconn;
553 				--lc->lconn_refcnt;
554 
555 				if ( rc != LDAP_SUCCESS && ext == 2 ) {
556 					ldap_free_connection( ld, lc, 1, 0 );
557 					return NULL;
558 				}
559 			}
560 		}
561 #endif
562 	}
563 
564 	if ( bind != NULL ) {
565 		int		err = 0;
566 		LDAPConn	*savedefconn;
567 
568 		/* Set flag to prevent additional referrals
569 		 * from being processed on this
570 		 * connection until the bind has completed
571 		 */
572 		lc->lconn_rebind_inprogress = 1;
573 		/* V3 rebind function */
574 		if ( ld->ld_rebind_proc != NULL) {
575 			LDAPURLDesc	*srvfunc;
576 
577 			srvfunc = ldap_url_dup( *srvlist );
578 			if ( srvfunc == NULL ) {
579 				ld->ld_errno = LDAP_NO_MEMORY;
580 				err = -1;
581 			} else {
582 				savedefconn = ld->ld_defconn;
583 				++lc->lconn_refcnt;	/* avoid premature free */
584 				ld->ld_defconn = lc;
585 
586 				Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0);
587 				LDAP_REQ_UNLOCK_IF(m_req);
588 				LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
589 				LDAP_RES_UNLOCK_IF(m_res);
590 				err = (*ld->ld_rebind_proc)( ld,
591 					bind->ri_url, bind->ri_request, bind->ri_msgid,
592 					ld->ld_rebind_params );
593 				LDAP_RES_LOCK_IF(m_res);
594 				LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
595 				LDAP_REQ_LOCK_IF(m_req);
596 
597 				ld->ld_defconn = savedefconn;
598 				--lc->lconn_refcnt;
599 
600 				if ( err != 0 ) {
601 					err = -1;
602 					ldap_free_connection( ld, lc, 1, 0 );
603 					lc = NULL;
604 				}
605 				ldap_free_urldesc( srvfunc );
606 			}
607 
608 		} else {
609 			int		msgid, rc;
610 			struct berval	passwd = BER_BVNULL;
611 
612 			savedefconn = ld->ld_defconn;
613 			++lc->lconn_refcnt;	/* avoid premature free */
614 			ld->ld_defconn = lc;
615 
616 			Debug( LDAP_DEBUG_TRACE,
617 				"anonymous rebind via ldap_sasl_bind(\"\")\n",
618 				0, 0, 0);
619 
620 			LDAP_REQ_UNLOCK_IF(m_req);
621 			LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
622 			LDAP_RES_UNLOCK_IF(m_res);
623 			rc = ldap_sasl_bind( ld, "", LDAP_SASL_SIMPLE, &passwd,
624 				NULL, NULL, &msgid );
625 			if ( rc != LDAP_SUCCESS ) {
626 				err = -1;
627 
628 			} else {
629 				for ( err = 1; err > 0; ) {
630 					struct timeval	tv = { 0, 100000 };
631 					LDAPMessage	*res = NULL;
632 
633 					switch ( ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) {
634 					case -1:
635 						err = -1;
636 						break;
637 
638 					case 0:
639 #ifdef LDAP_R_COMPILE
640 						ldap_pvt_thread_yield();
641 #endif
642 						break;
643 
644 					case LDAP_RES_BIND:
645 						rc = ldap_parse_result( ld, res, &err, NULL, NULL, NULL, NULL, 1 );
646 						if ( rc != LDAP_SUCCESS ) {
647 							err = -1;
648 
649 						} else if ( err != LDAP_SUCCESS ) {
650 							err = -1;
651 						}
652 						/* else err == LDAP_SUCCESS == 0 */
653 						break;
654 
655 					default:
656 						Debug( LDAP_DEBUG_TRACE,
657 							"ldap_new_connection %p: "
658 							"unexpected response %d "
659 							"from BIND request id=%d\n",
660 							(void *) ld, ldap_msgtype( res ), msgid );
661 						err = -1;
662 						break;
663 					}
664 				}
665 			}
666 			LDAP_RES_LOCK_IF(m_res);
667 			LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
668 			LDAP_REQ_LOCK_IF(m_req);
669 			ld->ld_defconn = savedefconn;
670 			--lc->lconn_refcnt;
671 
672 			if ( err != 0 ) {
673 				ldap_free_connection( ld, lc, 1, 0 );
674 				lc = NULL;
675 			}
676 		}
677 		if ( lc != NULL )
678 			lc->lconn_rebind_inprogress = 0;
679 	}
680 	return( lc );
681 }
682 
683 
684 /* protected by ld_conn_mutex */
685 static LDAPConn *
686 find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
687 /*
688  * return an existing connection (if any) to the server srv
689  * if "any" is non-zero, check for any server in the "srv" chain
690  */
691 {
692 	LDAPConn	*lc;
693 	LDAPURLDesc	*lcu, *lsu;
694 	int lcu_port, lsu_port;
695 	int found = 0;
696 
697 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
698 	for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
699 		lcu = lc->lconn_server;
700 		lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme,
701 			lcu->lud_port );
702 
703 		for ( lsu = srv; lsu != NULL; lsu = lsu->lud_next ) {
704 			lsu_port = ldap_pvt_url_scheme_port( lsu->lud_scheme,
705 				lsu->lud_port );
706 
707 			if ( lsu_port == lcu_port
708 				&& strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0
709 				&& lcu->lud_host != NULL && lsu->lud_host != NULL
710 				&& strcasecmp( lsu->lud_host, lcu->lud_host ) == 0 )
711 			{
712 				found = 1;
713 				break;
714 			}
715 
716 			if ( !any ) break;
717 		}
718 		if ( found )
719 			break;
720 	}
721 	return lc;
722 }
723 
724 
725 
726 /* protected by ld_conn_mutex */
727 static void
728 use_connection( LDAP *ld, LDAPConn *lc )
729 {
730 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
731 	++lc->lconn_refcnt;
732 	lc->lconn_lastused = time( NULL );
733 }
734 
735 
736 /* protected by ld_conn_mutex */
737 void
738 ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
739 {
740 	LDAPConn	*tmplc, *prevlc;
741 
742 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
743 	Debug( LDAP_DEBUG_TRACE,
744 		"ldap_free_connection %d %d\n",
745 		force, unbind, 0 );
746 
747 	if ( force || --lc->lconn_refcnt <= 0 ) {
748 		/* remove from connections list first */
749 
750 		for ( prevlc = NULL, tmplc = ld->ld_conns;
751 			tmplc != NULL;
752 			tmplc = tmplc->lconn_next )
753 		{
754 			if ( tmplc == lc ) {
755 				if ( prevlc == NULL ) {
756 				    ld->ld_conns = tmplc->lconn_next;
757 				} else {
758 				    prevlc->lconn_next = tmplc->lconn_next;
759 				}
760 				if ( ld->ld_defconn == lc ) {
761 					ld->ld_defconn = NULL;
762 				}
763 				break;
764 			}
765 			prevlc = tmplc;
766 		}
767 
768 		/* process connection callbacks */
769 		{
770 			struct ldapoptions *lo;
771 			ldaplist *ll;
772 			ldap_conncb *cb;
773 
774 			lo = &ld->ld_options;
775 			LDAP_MUTEX_LOCK( &lo->ldo_mutex );
776 			if ( lo->ldo_conn_cbs ) {
777 				for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
778 					cb = ll->ll_data;
779 					cb->lc_del( ld, lc->lconn_sb, cb );
780 				}
781 			}
782 			LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
783 			lo = LDAP_INT_GLOBAL_OPT();
784 			LDAP_MUTEX_LOCK( &lo->ldo_mutex );
785 			if ( lo->ldo_conn_cbs ) {
786 				for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
787 					cb = ll->ll_data;
788 					cb->lc_del( ld, lc->lconn_sb, cb );
789 				}
790 			}
791 			LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
792 		}
793 
794 		if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
795 			ldap_mark_select_clear( ld, lc->lconn_sb );
796 			if ( unbind ) {
797 				ldap_send_unbind( ld, lc->lconn_sb,
798 						NULL, NULL );
799 			}
800 		}
801 
802 		if ( lc->lconn_ber != NULL ) {
803 			ber_free( lc->lconn_ber, 1 );
804 		}
805 
806 		ldap_int_sasl_close( ld, lc );
807 #ifdef HAVE_GSSAPI
808 		ldap_int_gssapi_close( ld, lc );
809 #endif
810 
811 		ldap_free_urllist( lc->lconn_server );
812 
813 		/* FIXME: is this at all possible?
814 		 * ldap_ld_free() in unbind.c calls ldap_free_connection()
815 		 * with force == 1 __after__ explicitly calling
816 		 * ldap_free_request() on all requests */
817 		if ( force ) {
818 			LDAPRequest	*lr;
819 
820 			for ( lr = ld->ld_requests; lr; ) {
821 				LDAPRequest	*lr_next = lr->lr_next;
822 
823 				if ( lr->lr_conn == lc ) {
824 					ldap_free_request_int( ld, lr );
825 				}
826 
827 				lr = lr_next;
828 			}
829 		}
830 
831 		if ( lc->lconn_sb != ld->ld_sb ) {
832 			ber_sockbuf_free( lc->lconn_sb );
833 		} else {
834 			ber_int_sb_close( lc->lconn_sb );
835 		}
836 
837 		if ( lc->lconn_rebind_queue != NULL) {
838 			int i;
839 			for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) {
840 				LDAP_VFREE( lc->lconn_rebind_queue[i] );
841 			}
842 			LDAP_FREE( lc->lconn_rebind_queue );
843 		}
844 
845 		LDAP_FREE( lc );
846 
847 		Debug( LDAP_DEBUG_TRACE,
848 			"ldap_free_connection: actually freed\n",
849 			0, 0, 0 );
850 
851 	} else {
852 		lc->lconn_lastused = time( NULL );
853 		Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n",
854 				lc->lconn_refcnt, 0, 0 );
855 	}
856 }
857 
858 
859 /* Protects self with ld_conn_mutex */
860 #ifdef LDAP_DEBUG
861 void
862 ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
863 {
864 	LDAPConn	*lc;
865    	char		timebuf[32];
866 
867 	Debug( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "", 0 );
868 	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
869 	for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
870 		if ( lc->lconn_server != NULL ) {
871 			Debug( LDAP_DEBUG_TRACE, "* host: %s  port: %d%s\n",
872 				( lc->lconn_server->lud_host == NULL ) ? "(null)"
873 				: lc->lconn_server->lud_host,
874 				lc->lconn_server->lud_port, ( lc->lconn_sb ==
875 				ld->ld_sb ) ? "  (default)" : "" );
876 		}
877 		Debug( LDAP_DEBUG_TRACE, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
878 			( lc->lconn_status == LDAP_CONNST_NEEDSOCKET )
879 				? "NeedSocket" :
880 				( lc->lconn_status == LDAP_CONNST_CONNECTING )
881 					? "Connecting" : "Connected", 0 );
882 		Debug( LDAP_DEBUG_TRACE, "  last used: %s%s\n",
883 			ldap_pvt_ctime( &lc->lconn_lastused, timebuf ),
884 			lc->lconn_rebind_inprogress ? "  rebind in progress" : "", 0 );
885 		if ( lc->lconn_rebind_inprogress ) {
886 			if ( lc->lconn_rebind_queue != NULL) {
887 				int	i;
888 
889 				for ( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) {
890 					int	j;
891 					for( j = 0; lc->lconn_rebind_queue[i][j] != 0; j++ ) {
892 						Debug( LDAP_DEBUG_TRACE, "    queue %d entry %d - %s\n",
893 							i, j, lc->lconn_rebind_queue[i][j] );
894 					}
895 				}
896 			} else {
897 				Debug( LDAP_DEBUG_TRACE, "    queue is empty\n", 0, 0, 0 );
898 			}
899 		}
900 		Debug( LDAP_DEBUG_TRACE, "\n", 0, 0, 0 );
901 		if ( !all ) {
902 			break;
903 		}
904 	}
905 	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
906 }
907 
908 
909 /* protected by req_mutex and res_mutex */
910 void
911 ldap_dump_requests_and_responses( LDAP *ld )
912 {
913 	LDAPRequest	*lr;
914 	LDAPMessage	*lm, *l;
915 	int		i;
916 
917 	Debug( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n",
918 		(void *)ld, 0, 0 );
919 	lr = ld->ld_requests;
920 	if ( lr == NULL ) {
921 		Debug( LDAP_DEBUG_TRACE, "   Empty\n", 0, 0, 0 );
922 	}
923 	for ( i = 0; lr != NULL; lr = lr->lr_next, i++ ) {
924 		Debug( LDAP_DEBUG_TRACE, " * msgid %d,  origid %d, status %s\n",
925 			lr->lr_msgid, lr->lr_origid,
926 			( lr->lr_status == LDAP_REQST_INPROGRESS ) ? "InProgress" :
927 			( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" :
928 			( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" :
929 			( lr->lr_status == LDAP_REQST_WRITING ) ? "Writing" :
930 			( lr->lr_status == LDAP_REQST_COMPLETED ) ? "RequestCompleted"
931 				: "InvalidStatus" );
932 		Debug( LDAP_DEBUG_TRACE, "   outstanding referrals %d, parent count %d\n",
933 			lr->lr_outrefcnt, lr->lr_parentcnt, 0 );
934 	}
935 	Debug( LDAP_DEBUG_TRACE, "  ld %p request count %d (abandoned %lu)\n",
936 		(void *)ld, i, ld->ld_nabandoned );
937 	Debug( LDAP_DEBUG_TRACE, "** ld %p Response Queue:\n", (void *)ld, 0, 0 );
938 	if ( ( lm = ld->ld_responses ) == NULL ) {
939 		Debug( LDAP_DEBUG_TRACE, "   Empty\n", 0, 0, 0 );
940 	}
941 	for ( i = 0; lm != NULL; lm = lm->lm_next, i++ ) {
942 		Debug( LDAP_DEBUG_TRACE, " * msgid %d,  type %lu\n",
943 		    lm->lm_msgid, (unsigned long)lm->lm_msgtype, 0 );
944 		if ( lm->lm_chain != NULL ) {
945 			Debug( LDAP_DEBUG_TRACE, "   chained responses:\n", 0, 0, 0 );
946 			for ( l = lm->lm_chain; l != NULL; l = l->lm_chain ) {
947 				Debug( LDAP_DEBUG_TRACE,
948 					"  * msgid %d,  type %lu\n",
949 					l->lm_msgid,
950 					(unsigned long)l->lm_msgtype, 0 );
951 			}
952 		}
953 	}
954 	Debug( LDAP_DEBUG_TRACE, "  ld %p response count %d\n", (void *)ld, i, 0 );
955 }
956 #endif /* LDAP_DEBUG */
957 
958 /* protected by req_mutex */
959 static void
960 ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
961 {
962 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
963 	/* if lr_refcnt > 0, the request has been looked up
964 	 * by ldap_find_request_by_msgid(); if in the meanwhile
965 	 * the request is free()'d by someone else, just decrease
966 	 * the reference count and extract it from the request
967 	 * list; later on, it will be freed. */
968 	if ( lr->lr_prev == NULL ) {
969 		if ( lr->lr_refcnt == 0 ) {
970 			/* free'ing the first request? */
971 			assert( ld->ld_requests == lr );
972 		}
973 
974 		if ( ld->ld_requests == lr ) {
975 			ld->ld_requests = lr->lr_next;
976 		}
977 
978 	} else {
979 		lr->lr_prev->lr_next = lr->lr_next;
980 	}
981 
982 	if ( lr->lr_next != NULL ) {
983 		lr->lr_next->lr_prev = lr->lr_prev;
984 	}
985 
986 	if ( lr->lr_refcnt > 0 ) {
987 		lr->lr_refcnt = -lr->lr_refcnt;
988 
989 		lr->lr_prev = NULL;
990 		lr->lr_next = NULL;
991 
992 		return;
993 	}
994 
995 	if ( lr->lr_ber != NULL ) {
996 		ber_free( lr->lr_ber, 1 );
997 		lr->lr_ber = NULL;
998 	}
999 
1000 	if ( lr->lr_res_error != NULL ) {
1001 		LDAP_FREE( lr->lr_res_error );
1002 		lr->lr_res_error = NULL;
1003 	}
1004 
1005 	if ( lr->lr_res_matched != NULL ) {
1006 		LDAP_FREE( lr->lr_res_matched );
1007 		lr->lr_res_matched = NULL;
1008 	}
1009 
1010 	LDAP_FREE( lr );
1011 }
1012 
1013 /* protected by req_mutex */
1014 void
1015 ldap_free_request( LDAP *ld, LDAPRequest *lr )
1016 {
1017 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
1018 	Debug( LDAP_DEBUG_TRACE, "ldap_free_request (origid %d, msgid %d)\n",
1019 		lr->lr_origid, lr->lr_msgid, 0 );
1020 
1021 	/* free all referrals (child requests) */
1022 	while ( lr->lr_child ) {
1023 		ldap_free_request( ld, lr->lr_child );
1024 	}
1025 
1026 	if ( lr->lr_parent != NULL ) {
1027 		LDAPRequest     **lrp;
1028 
1029 		--lr->lr_parent->lr_outrefcnt;
1030 		for ( lrp = &lr->lr_parent->lr_child;
1031 			*lrp && *lrp != lr;
1032 			lrp = &(*lrp)->lr_refnext );
1033 
1034 		if ( *lrp == lr ) {
1035 			*lrp = lr->lr_refnext;
1036 		}
1037 	}
1038 	ldap_free_request_int( ld, lr );
1039 }
1040 
1041 /*
1042  * call first time with *cntp = -1
1043  * when returns *cntp == -1, no referrals are left
1044  *
1045  * NOTE: may replace *refsp, or shuffle the contents
1046  * of the original array.
1047  */
1048 static int ldap_int_nextref(
1049 	LDAP			*ld,
1050 	char			***refsp,
1051 	int			*cntp,
1052 	void			*params )
1053 {
1054 	assert( refsp != NULL );
1055 	assert( *refsp != NULL );
1056 	assert( cntp != NULL );
1057 
1058 	if ( *cntp < -1 ) {
1059 		*cntp = -1;
1060 		return -1;
1061 	}
1062 
1063 	(*cntp)++;
1064 
1065 	if ( (*refsp)[ *cntp ] == NULL ) {
1066 		*cntp = -1;
1067 	}
1068 
1069 	return 0;
1070 }
1071 
1072 /*
1073  * Chase v3 referrals
1074  *
1075  * Parameters:
1076  *  (IN) ld = LDAP connection handle
1077  *  (IN) lr = LDAP Request structure
1078  *  (IN) refs = array of pointers to referral strings that we will chase
1079  *              The array will be free'd by this function when no longer needed
1080  *  (IN) sref != 0 if following search reference
1081  *  (OUT) errstrp = Place to return a string of referrals which could not be followed
1082  *  (OUT) hadrefp = 1 if sucessfully followed referral
1083  *
1084  * Return value - number of referrals followed
1085  *
1086  * Protected by res_mutex, conn_mutex and req_mutex	(try_read1msg)
1087  */
1088 int
1089 ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp )
1090 {
1091 	char		*unfollowed;
1092 	int		 unfollowedcnt = 0;
1093 	LDAPRequest	*origreq;
1094 	LDAPURLDesc	*srv = NULL;
1095 	BerElement	*ber;
1096 	char		**refarray = NULL;
1097 	LDAPConn	*lc;
1098 	int			 rc, count, i, j, id;
1099 	LDAPreqinfo  rinfo;
1100 	LDAP_NEXTREF_PROC	*nextref_proc = ld->ld_nextref_proc ? ld->ld_nextref_proc : ldap_int_nextref;
1101 
1102 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
1103 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
1104 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
1105 	Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n", 0, 0, 0 );
1106 
1107 	ld->ld_errno = LDAP_SUCCESS;	/* optimistic */
1108 	*hadrefp = 0;
1109 
1110 	unfollowed = NULL;
1111 	rc = count = 0;
1112 
1113 	/* If no referrals in array, return */
1114 	if ( (refs == NULL) || ( (refs)[0] == NULL) ) {
1115 		rc = 0;
1116 		goto done;
1117 	}
1118 
1119 	/* Check for hop limit exceeded */
1120 	if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
1121 		Debug( LDAP_DEBUG_ANY,
1122 		    "more than %d referral hops (dropping)\n", ld->ld_refhoplimit, 0, 0 );
1123 		ld->ld_errno = LDAP_REFERRAL_LIMIT_EXCEEDED;
1124 		rc = -1;
1125 		goto done;
1126 	}
1127 
1128 	/* find original request */
1129 	for ( origreq = lr;
1130 		origreq->lr_parent != NULL;
1131 		origreq = origreq->lr_parent )
1132 	{
1133 		/* empty */ ;
1134 	}
1135 
1136 	refarray = refs;
1137 	refs = NULL;
1138 
1139 	/* parse out & follow referrals */
1140 	/* NOTE: if nextref_proc == ldap_int_nextref, params is ignored */
1141 	i = -1;
1142 	for ( nextref_proc( ld, &refarray, &i, ld->ld_nextref_params );
1143 			i != -1;
1144 			nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ) )
1145 	{
1146 
1147 		/* Parse the referral URL */
1148 		rc = ldap_url_parse_ext( refarray[i], &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN );
1149 		if ( rc != LDAP_URL_SUCCESS ) {
1150 			/* ldap_url_parse_ext() returns LDAP_URL_* errors
1151 			 * which do not map on API errors */
1152 			ld->ld_errno = LDAP_PARAM_ERROR;
1153 			rc = -1;
1154 			goto done;
1155 		}
1156 
1157 		if( srv->lud_crit_exts ) {
1158 			int ok = 0;
1159 #ifdef HAVE_TLS
1160 			/* If StartTLS is the only critical ext, OK. */
1161 			if ( find_tls_ext( srv ) == 2 && srv->lud_crit_exts == 1 )
1162 				ok = 1;
1163 #endif
1164 			if ( !ok ) {
1165 				/* we do not support any other extensions */
1166 				ld->ld_errno = LDAP_NOT_SUPPORTED;
1167 				rc = -1;
1168 				goto done;
1169 			}
1170 		}
1171 
1172 		/* check connection for re-bind in progress */
1173 		if (( lc = find_connection( ld, srv, 1 )) != NULL ) {
1174 			/* See if we've already requested this DN with this conn */
1175 			LDAPRequest *lp;
1176 			int looped = 0;
1177 			ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0;
1178 			for ( lp = origreq; lp; ) {
1179 				if ( lp->lr_conn == lc
1180 					&& len == lp->lr_dn.bv_len
1181 					&& len
1182 					&& strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) == 0 )
1183 				{
1184 					looped = 1;
1185 					break;
1186 				}
1187 				if ( lp == origreq ) {
1188 					lp = lp->lr_child;
1189 				} else {
1190 					lp = lp->lr_refnext;
1191 				}
1192 			}
1193 			if ( looped ) {
1194 				ldap_free_urllist( srv );
1195 				srv = NULL;
1196 				ld->ld_errno = LDAP_CLIENT_LOOP;
1197 				rc = -1;
1198 				continue;
1199 			}
1200 
1201 			if ( lc->lconn_rebind_inprogress ) {
1202 				/* We are already chasing a referral or search reference and a
1203 				 * bind on that connection is in progress.  We must queue
1204 				 * referrals on that connection, so we don't get a request
1205 				 * going out before the bind operation completes. This happens
1206 				 * if two search references come in one behind the other
1207 				 * for the same server with different contexts.
1208 				 */
1209 				Debug( LDAP_DEBUG_TRACE,
1210 					"ldap_chase_v3referrals: queue referral \"%s\"\n",
1211 					refarray[i], 0, 0);
1212 				if( lc->lconn_rebind_queue == NULL ) {
1213 					/* Create a referral list */
1214 					lc->lconn_rebind_queue =
1215 						(char ***) LDAP_MALLOC( sizeof(void *) * 2);
1216 
1217 					if( lc->lconn_rebind_queue == NULL) {
1218 						ld->ld_errno = LDAP_NO_MEMORY;
1219 						rc = -1;
1220 						goto done;
1221 					}
1222 
1223 					lc->lconn_rebind_queue[0] = refarray;
1224 					lc->lconn_rebind_queue[1] = NULL;
1225 					refarray = NULL;
1226 
1227 				} else {
1228 					/* Count how many referral arrays we already have */
1229 					for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) {
1230 						/* empty */;
1231 					}
1232 
1233 					/* Add the new referral to the list */
1234 					lc->lconn_rebind_queue = (char ***) LDAP_REALLOC(
1235 						lc->lconn_rebind_queue, sizeof(void *) * (j + 2));
1236 
1237 					if( lc->lconn_rebind_queue == NULL ) {
1238 						ld->ld_errno = LDAP_NO_MEMORY;
1239 						rc = -1;
1240 						goto done;
1241 					}
1242 					lc->lconn_rebind_queue[j] = refarray;
1243 					lc->lconn_rebind_queue[j+1] = NULL;
1244 					refarray = NULL;
1245 				}
1246 
1247 				/* We have queued the referral/reference, now just return */
1248 				rc = 0;
1249 				*hadrefp = 1;
1250 				count = 1; /* Pretend we already followed referral */
1251 				goto done;
1252 			}
1253 		}
1254 		/* Re-encode the request with the new starting point of the search.
1255 		 * Note: In the future we also need to replace the filter if one
1256 		 * was provided with the search reference
1257 		 */
1258 
1259 		/* For references we don't want old dn if new dn empty */
1260 		if ( sref && srv->lud_dn == NULL ) {
1261 			srv->lud_dn = LDAP_STRDUP( "" );
1262 		}
1263 
1264 		LDAP_NEXT_MSGID( ld, id );
1265 		ber = re_encode_request( ld, origreq->lr_ber, id,
1266 			sref, srv, &rinfo.ri_request );
1267 
1268 		if( ber == NULL ) {
1269 			ld->ld_errno = LDAP_ENCODING_ERROR;
1270 			rc = -1;
1271 			goto done;
1272 		}
1273 
1274 		Debug( LDAP_DEBUG_TRACE,
1275 			"ldap_chase_v3referral: msgid %d, url \"%s\"\n",
1276 			lr->lr_msgid, refarray[i], 0);
1277 
1278 		/* Send the new request to the server - may require a bind */
1279 		rinfo.ri_msgid = origreq->lr_origid;
1280 		rinfo.ri_url = refarray[i];
1281 		rc = ldap_send_server_request( ld, ber, id,
1282 			origreq, &srv, NULL, &rinfo, 0, 1 );
1283 		if ( rc < 0 ) {
1284 			/* Failure, try next referral in the list */
1285 			Debug( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%d: %s)\n",
1286 				refarray[i], ld->ld_errno, ldap_err2string( ld->ld_errno ) );
1287 			unfollowedcnt += ldap_append_referral( ld, &unfollowed, refarray[i] );
1288 			ldap_free_urllist( srv );
1289 			srv = NULL;
1290 			ld->ld_errno = LDAP_REFERRAL;
1291 		} else {
1292 			/* Success, no need to try this referral list further */
1293 			rc = 0;
1294 			++count;
1295 			*hadrefp = 1;
1296 
1297 			/* check if there is a queue of referrals that came in during bind */
1298 			if ( lc == NULL) {
1299 				lc = find_connection( ld, srv, 1 );
1300 				if ( lc == NULL ) {
1301 					ld->ld_errno = LDAP_OPERATIONS_ERROR;
1302 					rc = -1;
1303 					LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
1304 					goto done;
1305 				}
1306 			}
1307 
1308 			if ( lc->lconn_rebind_queue != NULL ) {
1309 				/* Release resources of previous list */
1310 				LDAP_VFREE( refarray );
1311 				refarray = NULL;
1312 				ldap_free_urllist( srv );
1313 				srv = NULL;
1314 
1315 				/* Pull entries off end of queue so list always null terminated */
1316 				for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++ )
1317 					;
1318 				refarray = lc->lconn_rebind_queue[j - 1];
1319 				lc->lconn_rebind_queue[j-1] = NULL;
1320 				/* we pulled off last entry from queue, free queue */
1321 				if ( j == 1 ) {
1322 					LDAP_FREE( lc->lconn_rebind_queue );
1323 					lc->lconn_rebind_queue = NULL;
1324 				}
1325 				/* restart the loop the with new referral list */
1326 				i = -1;
1327 				continue;
1328 			}
1329 			break; /* referral followed, break out of for loop */
1330 		}
1331 	} /* end for loop */
1332 done:
1333 	LDAP_VFREE( refarray );
1334 	ldap_free_urllist( srv );
1335 	LDAP_FREE( *errstrp );
1336 
1337 	if( rc == 0 ) {
1338 		*errstrp = NULL;
1339 		LDAP_FREE( unfollowed );
1340 		return count;
1341 	} else {
1342 		*errstrp = unfollowed;
1343 		return rc;
1344 	}
1345 }
1346 
1347 /*
1348  * XXX merging of errors in this routine needs to be improved
1349  * Protected by res_mutex, conn_mutex and req_mutex	(try_read1msg)
1350  */
1351 int
1352 ldap_chase_referrals( LDAP *ld,
1353 	LDAPRequest *lr,
1354 	char **errstrp,
1355 	int sref,
1356 	int *hadrefp )
1357 {
1358 	int		rc, count, id;
1359 	unsigned	len;
1360 	char		*p, *ref, *unfollowed;
1361 	LDAPRequest	*origreq;
1362 	LDAPURLDesc	*srv;
1363 	BerElement	*ber;
1364 	LDAPreqinfo  rinfo;
1365 	LDAPConn	*lc;
1366 
1367 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
1368 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
1369 	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
1370 	Debug( LDAP_DEBUG_TRACE, "ldap_chase_referrals\n", 0, 0, 0 );
1371 
1372 	ld->ld_errno = LDAP_SUCCESS;	/* optimistic */
1373 	*hadrefp = 0;
1374 
1375 	if ( *errstrp == NULL ) {
1376 		return( 0 );
1377 	}
1378 
1379 	len = strlen( *errstrp );
1380 	for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) {
1381 		if ( strncasecmp( p, LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) {
1382 			*p = '\0';
1383 			p += LDAP_REF_STR_LEN;
1384 			break;
1385 		}
1386 	}
1387 
1388 	if ( len < LDAP_REF_STR_LEN ) {
1389 		return( 0 );
1390 	}
1391 
1392 	if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
1393 		Debug( LDAP_DEBUG_ANY,
1394 		    "more than %d referral hops (dropping)\n",
1395 		    ld->ld_refhoplimit, 0, 0 );
1396 		    /* XXX report as error in ld->ld_errno? */
1397 		    return( 0 );
1398 	}
1399 
1400 	/* find original request */
1401 	for ( origreq = lr; origreq->lr_parent != NULL;
1402 	     origreq = origreq->lr_parent ) {
1403 		/* empty */;
1404 	}
1405 
1406 	unfollowed = NULL;
1407 	rc = count = 0;
1408 
1409 	/* parse out & follow referrals */
1410 	for ( ref = p; rc == 0 && ref != NULL; ref = p ) {
1411 		p = strchr( ref, '\n' );
1412 		if ( p != NULL ) {
1413 			*p++ = '\0';
1414 		}
1415 
1416 		rc = ldap_url_parse_ext( ref, &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN );
1417 		if ( rc != LDAP_URL_SUCCESS ) {
1418 			Debug( LDAP_DEBUG_TRACE,
1419 				"ignoring %s referral <%s>\n",
1420 				ref, rc == LDAP_URL_ERR_BADSCHEME ? "unknown" : "incorrect", 0 );
1421 			rc = ldap_append_referral( ld, &unfollowed, ref );
1422 			*hadrefp = 1;
1423 			continue;
1424 		}
1425 
1426 		Debug( LDAP_DEBUG_TRACE,
1427 		    "chasing LDAP referral: <%s>\n", ref, 0, 0 );
1428 
1429 		*hadrefp = 1;
1430 
1431 		/* See if we've already been here */
1432 		if (( lc = find_connection( ld, srv, 1 )) != NULL ) {
1433 			LDAPRequest *lp;
1434 			int looped = 0;
1435 			ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0;
1436 			for ( lp = lr; lp; lp = lp->lr_parent ) {
1437 				if ( lp->lr_conn == lc
1438 					&& len == lp->lr_dn.bv_len )
1439 				{
1440 					if ( len && strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) )
1441 							continue;
1442 					looped = 1;
1443 					break;
1444 				}
1445 			}
1446 			if ( looped ) {
1447 				ldap_free_urllist( srv );
1448 				ld->ld_errno = LDAP_CLIENT_LOOP;
1449 				rc = -1;
1450 				continue;
1451 			}
1452 		}
1453 
1454 		LDAP_NEXT_MSGID( ld, id );
1455 		ber = re_encode_request( ld, origreq->lr_ber,
1456 		    id, sref, srv, &rinfo.ri_request );
1457 
1458 		if ( ber == NULL ) {
1459 			ldap_free_urllist( srv );
1460 			return -1 ;
1461 		}
1462 
1463 		/* copy the complete referral for rebind process */
1464 		rinfo.ri_url = LDAP_STRDUP( ref );
1465 
1466 		rinfo.ri_msgid = origreq->lr_origid;
1467 
1468 		rc = ldap_send_server_request( ld, ber, id,
1469 			lr, &srv, NULL, &rinfo, 0, 1 );
1470 		LDAP_FREE( rinfo.ri_url );
1471 
1472 		if( rc >= 0 ) {
1473 			++count;
1474 		} else {
1475 			Debug( LDAP_DEBUG_ANY,
1476 				"Unable to chase referral \"%s\" (%d: %s)\n",
1477 				ref, ld->ld_errno, ldap_err2string( ld->ld_errno ) );
1478 			rc = ldap_append_referral( ld, &unfollowed, ref );
1479 		}
1480 
1481 		ldap_free_urllist(srv);
1482 	}
1483 
1484 	LDAP_FREE( *errstrp );
1485 	*errstrp = unfollowed;
1486 
1487 	return(( rc == 0 ) ? count : rc );
1488 }
1489 
1490 
1491 int
1492 ldap_append_referral( LDAP *ld, char **referralsp, char *s )
1493 {
1494 	int	first;
1495 
1496 	if ( *referralsp == NULL ) {
1497 		first = 1;
1498 		*referralsp = (char *)LDAP_MALLOC( strlen( s ) + LDAP_REF_STR_LEN
1499 		    + 1 );
1500 	} else {
1501 		first = 0;
1502 		*referralsp = (char *)LDAP_REALLOC( *referralsp,
1503 		    strlen( *referralsp ) + strlen( s ) + 2 );
1504 	}
1505 
1506 	if ( *referralsp == NULL ) {
1507 		ld->ld_errno = LDAP_NO_MEMORY;
1508 		return( -1 );
1509 	}
1510 
1511 	if ( first ) {
1512 		strcpy( *referralsp, LDAP_REF_STR );
1513 	} else {
1514 		strcat( *referralsp, "\n" );
1515 	}
1516 	strcat( *referralsp, s );
1517 
1518 	return( 0 );
1519 }
1520 
1521 
1522 
1523 static BerElement *
1524 re_encode_request( LDAP *ld,
1525 	BerElement *origber,
1526 	ber_int_t msgid,
1527 	int sref,
1528 	LDAPURLDesc *srv,
1529 	int *type )
1530 {
1531 	/*
1532 	 * XXX this routine knows way too much about how the lber library works!
1533 	 */
1534 	ber_int_t	along;
1535 	ber_tag_t	tag;
1536 	ber_tag_t	rtag;
1537 	ber_int_t	ver;
1538 	ber_int_t	scope;
1539 	int		rc;
1540 	BerElement	tmpber, *ber;
1541 	struct berval		dn;
1542 
1543 	Debug( LDAP_DEBUG_TRACE,
1544 	    "re_encode_request: new msgid %ld, new dn <%s>\n",
1545 	    (long) msgid,
1546 		( srv == NULL || srv->lud_dn == NULL) ? "NONE" : srv->lud_dn, 0 );
1547 
1548 	tmpber = *origber;
1549 
1550 	/*
1551 	 * all LDAP requests are sequences that start with a message id.
1552 	 * For all except delete, this is followed by a sequence that is
1553 	 * tagged with the operation code.  For delete, the provided DN
1554 	 * is not wrapped by a sequence.
1555 	 */
1556 	rtag = ber_scanf( &tmpber, "{it", /*}*/ &along, &tag );
1557 
1558 	if ( rtag == LBER_ERROR ) {
1559 		ld->ld_errno = LDAP_DECODING_ERROR;
1560 		return( NULL );
1561 	}
1562 
1563 	assert( tag != 0);
1564 	if ( tag == LDAP_REQ_BIND ) {
1565 		/* bind requests have a version number before the DN & other stuff */
1566 		rtag = ber_scanf( &tmpber, "{im" /*}*/, &ver, &dn );
1567 
1568 	} else if ( tag == LDAP_REQ_DELETE ) {
1569 		/* delete requests don't have a DN wrapping sequence */
1570 		rtag = ber_scanf( &tmpber, "m", &dn );
1571 
1572 	} else if ( tag == LDAP_REQ_SEARCH ) {
1573 		/* search requests need to be re-scope-ed */
1574 		rtag = ber_scanf( &tmpber, "{me" /*"}"*/, &dn, &scope );
1575 
1576 		if( srv->lud_scope != LDAP_SCOPE_DEFAULT ) {
1577 			/* use the scope provided in reference */
1578 			scope = srv->lud_scope;
1579 
1580 		} else if ( sref ) {
1581 			/* use scope implied by previous operation
1582 			 *   base -> base
1583 			 *   one -> base
1584 			 *   subtree -> subtree
1585 			 *   subordinate -> subtree
1586 			 */
1587 			switch( scope ) {
1588 			default:
1589 			case LDAP_SCOPE_BASE:
1590 			case LDAP_SCOPE_ONELEVEL:
1591 				scope = LDAP_SCOPE_BASE;
1592 				break;
1593 			case LDAP_SCOPE_SUBTREE:
1594 			case LDAP_SCOPE_SUBORDINATE:
1595 				scope = LDAP_SCOPE_SUBTREE;
1596 				break;
1597 			}
1598 		}
1599 
1600 	} else {
1601 		rtag = ber_scanf( &tmpber, "{m" /*}*/, &dn );
1602 	}
1603 
1604 	if( rtag == LBER_ERROR ) {
1605 		ld->ld_errno = LDAP_DECODING_ERROR;
1606 		return NULL;
1607 	}
1608 
1609 	/* restore character zero'd out by ber_scanf*/
1610 	dn.bv_val[dn.bv_len] = tmpber.ber_tag;
1611 
1612 	if (( ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
1613 		return NULL;
1614 	}
1615 
1616 	if ( srv->lud_dn ) {
1617 		ber_str2bv( srv->lud_dn, 0, 0, &dn );
1618 	}
1619 
1620 	if ( tag == LDAP_REQ_BIND ) {
1621 		rc = ber_printf( ber, "{it{iO" /*}}*/, msgid, tag, ver, &dn );
1622 	} else if ( tag == LDAP_REQ_DELETE ) {
1623 		rc = ber_printf( ber, "{itON}", msgid, tag, &dn );
1624 	} else if ( tag == LDAP_REQ_SEARCH ) {
1625 		rc = ber_printf( ber, "{it{Oe" /*}}*/, msgid, tag, &dn, scope );
1626 	} else {
1627 		rc = ber_printf( ber, "{it{O" /*}}*/, msgid, tag, &dn );
1628 	}
1629 
1630 	if ( rc == -1 ) {
1631 		ld->ld_errno = LDAP_ENCODING_ERROR;
1632 		ber_free( ber, 1 );
1633 		return NULL;
1634 	}
1635 
1636 	if ( tag != LDAP_REQ_DELETE && (
1637 		ber_write(ber, tmpber.ber_ptr, ( tmpber.ber_end - tmpber.ber_ptr ), 0)
1638 		!= ( tmpber.ber_end - tmpber.ber_ptr ) ||
1639 	    ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) )
1640 	{
1641 		ld->ld_errno = LDAP_ENCODING_ERROR;
1642 		ber_free( ber, 1 );
1643 		return NULL;
1644 	}
1645 
1646 #ifdef LDAP_DEBUG
1647 	if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
1648 		Debug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n",
1649 		    0, 0, 0 );
1650 		ber_log_dump( LDAP_DEBUG_BER, ldap_debug, ber, 0 );
1651 	}
1652 #endif /* LDAP_DEBUG */
1653 
1654 	*type = tag;	/* return request type */
1655 	return ber;
1656 }
1657 
1658 
1659 /* protected by req_mutex */
1660 LDAPRequest *
1661 ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid )
1662 {
1663 	LDAPRequest	*lr;
1664 
1665 	for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
1666 		if ( lr->lr_status == LDAP_REQST_COMPLETED ) {
1667 			continue;	/* Skip completed requests */
1668 		}
1669 		if ( msgid == lr->lr_msgid ) {
1670 			lr->lr_refcnt++;
1671 			break;
1672 		}
1673 	}
1674 
1675 	return( lr );
1676 }
1677 
1678 /* protected by req_mutex */
1679 void
1680 ldap_return_request( LDAP *ld, LDAPRequest *lrx, int freeit )
1681 {
1682 	LDAPRequest	*lr;
1683 
1684 	for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
1685 		if ( lr == lrx ) {
1686 			if ( lr->lr_refcnt > 0 ) {
1687 				lr->lr_refcnt--;
1688 
1689 			} else if ( lr->lr_refcnt < 0 ) {
1690 				lr->lr_refcnt++;
1691 				if ( lr->lr_refcnt == 0 ) {
1692 					lr = NULL;
1693 				}
1694 			}
1695 			break;
1696 		}
1697 	}
1698 	if ( lr == NULL ) {
1699 		ldap_free_request_int( ld, lrx );
1700 
1701 	} else if ( freeit ) {
1702 		ldap_free_request( ld, lrx );
1703 	}
1704 }
1705