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