request.c 42.6 KB
Newer Older
1
/* $OpenLDAP$ */
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
4
 * Copyright 1998-2021 The OpenLDAP Foundation.
5
6
7
8
9
10
11
12
13
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
14
 */
15
16
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
 * All rights reserved.
17
 */
18
/* This notice applies to changes, created by or for Novell, Inc.,
19
20
21
22
23
24
25
26
27
28
29
30
 * to preexisting works for which notices appear elsewhere in this file.
 *
 * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
 *
 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
 * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
 * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
 * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
 * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
 * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
 * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
 * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 
31
 *---
32
33
 * Modification to OpenLDAP source by Novell, Inc.
 * April 2000 sfs  Added code to chase V3 referrals
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
 *  request.c - sending of ldap requests; handling of referrals
35
36
 *---
 * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License 
37
38
39
 * can be found in the file "build/LICENSE-2.0.1" in this distribution
 * of OpenLDAP Software.
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
40

41
#include "portable.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
42
43

#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
44
45

#include <ac/stdlib.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
46

47
48
49
50
51
52
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
53
#include "ldap-int.h"
54
#include "lber.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/* used by ldap_send_server_request and ldap_new_connection */
#ifdef LDAP_R_COMPILE
#define LDAP_CONN_LOCK_IF(nolock) \
	{ if (nolock) LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); }
#define LDAP_CONN_UNLOCK_IF(nolock) \
	{ if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); }
#define LDAP_REQ_LOCK_IF(nolock) \
	{ if (nolock) LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); }
#define LDAP_REQ_UNLOCK_IF(nolock) \
	{ if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); }
#define LDAP_RES_LOCK_IF(nolock) \
	{ if (nolock) LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); }
#define LDAP_RES_UNLOCK_IF(nolock) \
	{ if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); }
#else
#define LDAP_CONN_LOCK_IF(nolock)
#define LDAP_CONN_UNLOCK_IF(nolock)
#define LDAP_REQ_LOCK_IF(nolock)
#define LDAP_REQ_UNLOCK_IF(nolock)
#define LDAP_RES_LOCK_IF(nolock)
#define LDAP_RES_UNLOCK_IF(nolock)
#endif

79
static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPURLDesc *srv, int any ));
80
static void use_connection LDAP_P(( LDAP *ld, LDAPConn *lc ));
Pierangelo Masarati's avatar
Pierangelo Masarati committed
81
static void ldap_free_request_int LDAP_P(( LDAP *ld, LDAPRequest *lr ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
82

83
84
static BerElement *
re_encode_request( LDAP *ld,
85
	BerElement *origber,
86
	ber_int_t msgid,
87
	int sref,
88
89
	LDAPURLDesc *srv,
	int *type );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
90
91

BerElement *
92
ldap_alloc_ber_with_options( LDAP *ld )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
93
94
95
{
	BerElement	*ber;

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
96
97
	ber = ber_alloc_t( ld->ld_lberoptions );
	if ( ber == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
98
99
100
101
102
103
104
105
		ld->ld_errno = LDAP_NO_MEMORY;
	}

	return( ber );
}


void
106
ldap_set_ber_options( LDAP *ld, BerElement *ber )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
107
{
108
	/* ld_lberoptions is constant, hence no lock */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
109
110
111
112
	ber->ber_options = ld->ld_lberoptions;
}


113
/* sets needed mutexes - no mutexes set to this point */
114
ber_int_t
Kurt Zeilenga's avatar
Kurt Zeilenga committed
115
116
ldap_send_initial_request(
	LDAP *ld,
117
	ber_tag_t msgtype,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
118
	const char *dn,
119
120
	BerElement *ber,
	ber_int_t msgid)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
121
{
Howard Chu's avatar
Howard Chu committed
122
	int rc = 1;
123
	ber_socket_t sd = AC_SOCKET_INVALID;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
124

125
	Debug0( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
126

127
	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
128
	if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ) == -1 ) {
129
		/* not connected yet */
Howard Chu's avatar
Howard Chu committed
130
		rc = ldap_open_defconn( ld );
Howard Chu's avatar
Howard Chu committed
131
132
133
134
		if ( rc == 0 ) {
			ber_sockbuf_ctrl( ld->ld_defconn->lconn_sb,
				LBER_SB_OPT_GET_FD, &sd );
		}
Howard Chu's avatar
Howard Chu committed
135
	}
136
137
	if ( ld->ld_defconn && ld->ld_defconn->lconn_status == LDAP_CONNST_CONNECTING )
		rc = ldap_int_check_async_open( ld, sd );
Howard Chu's avatar
Howard Chu committed
138
139
	if( rc < 0 ) {
		ber_free( ber, 1 );
140
		LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
Howard Chu's avatar
Howard Chu committed
141
142
		return( -1 );
	} else if ( rc == 0 ) {
143
144
		Debug0( LDAP_DEBUG_TRACE,
			"ldap_open_defconn: successful\n" );
145
146
	}

147
148
149
#ifdef LDAP_CONNECTIONLESS
	if (LDAP_IS_UDP(ld)) {
		if (msgtype == LDAP_REQ_BIND) {
150
			LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
151
152
153
			if (ld->ld_options.ldo_cldapdn)
				ldap_memfree(ld->ld_options.ldo_cldapdn);
			ld->ld_options.ldo_cldapdn = ldap_strdup(dn);
Howard Chu's avatar
Howard Chu committed
154
			ber_free( ber, 1 );
155
156
			LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
			LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
157
158
159
			return 0;
		}
		if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH)
Howard Chu's avatar
Howard Chu committed
160
161
		{
			ber_free( ber, 1 );
162
			LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
163
			return LDAP_PARAM_ERROR;
Howard Chu's avatar
Howard Chu committed
164
		}
165
166
	}
#endif
Howard Chu's avatar
Howard Chu committed
167
	LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
168
	rc = ldap_send_server_request( ld, ber, msgid, NULL,
169
		NULL, NULL, NULL, 0, 0 );
Howard Chu's avatar
Howard Chu committed
170
	LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
171
	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
172
	return(rc);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
173
174
175
}


176
/* protected by conn_mutex */
177
178
179
int
ldap_int_flush_request(
	LDAP *ld,
180
	LDAPRequest *lr )
181
182
183
{
	LDAPConn *lc = lr->lr_conn;

184
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
185
	if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) {
186
187
		if (( sock_errno() == EAGAIN ) || ( sock_errno() == ENOTCONN )) {
			/* ENOTCONN is returned in Solaris 10 */
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
			/* need to continue write later */
			lr->lr_status = LDAP_REQST_WRITING;
			ldap_mark_select_write( ld, lc->lconn_sb );
			ld->ld_errno = LDAP_BUSY;
			return -2;
		} else {
			ld->ld_errno = LDAP_SERVER_DOWN;
			ldap_free_request( ld, lr );
			ldap_free_connection( ld, lc, 0, 0 );
			return( -1 );
		}
	} else {
		if ( lr->lr_parent == NULL ) {
			lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
			lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
		}
		lr->lr_status = LDAP_REQST_INPROGRESS;

		/* sent -- waiting for a response */
		ldap_mark_select_read( ld, lc->lconn_sb );
208
		ldap_clear_select_write( ld, lc->lconn_sb );
209
210
211
	}
	return 0;
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
212

213
214
215
216
217
218
219
/*
 * protected by req_mutex
 * if m_noconn then protect using conn_lock
 * else already protected with conn_lock
 * if m_res then also protected by res_mutex
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
220
int
221
222
223
224
225
ldap_send_server_request(
	LDAP *ld,
	BerElement *ber,
	ber_int_t msgid,
	LDAPRequest *parentreq,
226
	LDAPURLDesc **srvlist,
227
	LDAPConn *lc,
228
229
230
	LDAPreqinfo *bind,
	int m_noconn,
	int m_res )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
231
232
{
	LDAPRequest	*lr;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
233
	int		incparent, rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
234

235
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
236
	Debug0( LDAP_DEBUG_TRACE, "ldap_send_server_request\n" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
237

238
	incparent = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
239
240
	ld->ld_errno = LDAP_SUCCESS;	/* optimistic */

241
	LDAP_CONN_LOCK_IF(m_noconn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
242
243
244
245
	if ( lc == NULL ) {
		if ( srvlist == NULL ) {
			lc = ld->ld_defconn;
		} else {
246
			lc = find_connection( ld, *srvlist, 1 );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
247
			if ( lc == NULL ) {
248
				if ( (bind != NULL) && (parentreq != NULL) ) {
249
250
251
252
					/* Remember the bind in the parent */
					incparent = 1;
					++parentreq->lr_outrefcnt;
				}
253
254
				lc = ldap_new_connection( ld, srvlist, 0,
					1, bind, 1, m_res );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
255
256
257
258
			}
		}
	}

259
260
261
262
263
264
265
266
	/* async connect... */
	if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) {
		ber_socket_t	sd = AC_SOCKET_ERROR;
		struct timeval	tv = { 0 };

		ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd );

		/* poll ... */
267
		switch ( ldap_int_poll( ld, sd, &tv, 1 ) ) {
268
269
270
271
272
		case 0:
			/* go on! */
			lc->lconn_status = LDAP_CONNST_CONNECTED;
			break;

Howard Chu's avatar
Howard Chu committed
273
		case -2:
274
			/* async only occurs if a network timeout is set */
Howard Chu's avatar
Howard Chu committed
275
276

			/* honor network timeout */
277
			LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
Howard Chu's avatar
Howard Chu committed
278
279
280
281
282
			if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec )
			{
				/* caller will have to call again */
				ld->ld_errno = LDAP_X_CONNECTING;
			}
283
			LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
Howard Chu's avatar
Howard Chu committed
284
			/* fallthru */
285
286
287
288
289
290
291

		default:
			/* error */
			break;
		}
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
292
293
294
295
	if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
		if ( ld->ld_errno == LDAP_SUCCESS ) {
			ld->ld_errno = LDAP_SERVER_DOWN;
		}
296
297

		ber_free( ber, 1 );
298
299
300
301
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
302
		LDAP_CONN_UNLOCK_IF(m_noconn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
303
304
305
306
		return( -1 );
	}

	use_connection( ld, lc );
307

Howard Chu's avatar
Howard Chu committed
308
309
310
311
#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP( ld )) {
		BerElement tmpber = *ber;
		ber_rewind( &tmpber );
312
		LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
Howard Chu's avatar
Howard Chu committed
313
		rc = ber_write( &tmpber, ld->ld_options.ldo_peer,
314
			sizeof( struct sockaddr_storage ), 0 );
315
		LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
Howard Chu's avatar
Howard Chu committed
316
317
		if ( rc == -1 ) {
			ld->ld_errno = LDAP_ENCODING_ERROR;
Howard Chu's avatar
Howard Chu committed
318
			ber_free( ber, 1 );
319
			LDAP_CONN_UNLOCK_IF(m_noconn);
Howard Chu's avatar
Howard Chu committed
320
321
322
323
324
			return rc;
		}
	}
#endif

325
326
327
328
329
	/* If we still have an incomplete write, try to finish it before
	 * dealing with the new request. If we don't finish here, return
	 * LDAP_BUSY and let the caller retry later. We only allow a single
	 * request to be in WRITING state.
	 */
330
	rc = 0;
331
332
333
334
335
336
337
338
339
340
	if ( ld->ld_requests != NULL ) {
		TAvlnode *node = ldap_tavl_end( ld->ld_requests, TAVL_DIR_RIGHT );
		LDAPRequest *lr;

		assert( node != NULL );
		lr = node->avl_data;
		if ( lr->lr_status == LDAP_REQST_WRITING &&
				ldap_int_flush_request( ld, lr ) < 0 ) {
			rc = -1;
		}
341
	}
342
	if ( rc ) {
Howard Chu's avatar
Howard Chu committed
343
		ber_free( ber, 1 );
344
345
346
		LDAP_CONN_UNLOCK_IF(m_noconn);
		return rc;
	}
347

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
348
	lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
349
	if ( lr == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
350
		ld->ld_errno = LDAP_NO_MEMORY;
351
		ldap_free_connection( ld, lc, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
352
		ber_free( ber, 1 );
353
354
355
356
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
357
		LDAP_CONN_UNLOCK_IF(m_noconn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
358
359
360
361
362
363
364
365
		return( -1 );
	} 
	lr->lr_msgid = msgid;
	lr->lr_status = LDAP_REQST_INPROGRESS;
	lr->lr_res_errno = LDAP_SUCCESS;	/* optimistic */
	lr->lr_ber = ber;
	lr->lr_conn = lc;
	if ( parentreq != NULL ) {	/* sub-request */
366
367
368
369
		if ( !incparent ) { 
			/* Increment if we didn't do it before the bind */
			++parentreq->lr_outrefcnt;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
370
		lr->lr_origid = parentreq->lr_origid;
371
		lr->lr_parentcnt = ++parentreq->lr_parentcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
372
		lr->lr_parent = parentreq;
373
374
		lr->lr_refnext = parentreq->lr_child;
		parentreq->lr_child = lr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
375
376
377
378
	} else {			/* original request */
		lr->lr_origid = lr->lr_msgid;
	}

379
	/* Extract requestDN for future reference */
380
381
382
#ifdef LDAP_CONNECTIONLESS
	if ( !LDAP_IS_UDP(ld) )
#endif
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
	{
		BerElement tmpber = *ber;
		ber_int_t	bint;
		ber_tag_t	tag, rtag;

		ber_reset( &tmpber, 1 );
		rtag = ber_scanf( &tmpber, "{it", /*}*/ &bint, &tag );
		switch ( tag ) {
		case LDAP_REQ_BIND:
			rtag = ber_scanf( &tmpber, "{i" /*}*/, &bint );
			break;
		case LDAP_REQ_DELETE:
			break;
		default:
			rtag = ber_scanf( &tmpber, "{" /*}*/ );
		case LDAP_REQ_ABANDON:
			break;
		}
		if ( tag != LDAP_REQ_ABANDON ) {
			ber_skip_tag( &tmpber, &lr->lr_dn.bv_len );
			lr->lr_dn.bv_val = tmpber.ber_ptr;
		}
	}

407
408
	rc = ldap_tavl_insert( &ld->ld_requests, lr, ldap_req_cmp, ldap_avl_dup_error );
	assert( rc == LDAP_SUCCESS );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
409

410
	ld->ld_errno = LDAP_SUCCESS;
411
	if ( ldap_int_flush_request( ld, lr ) == -1 ) {
412
		msgid = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
413
414
	}

415
	LDAP_CONN_UNLOCK_IF(m_noconn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
416
417
418
	return( msgid );
}

Howard Chu's avatar
Howard Chu committed
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
/* return 0 if no StartTLS ext, 1 if present, 2 if critical */
static int
find_tls_ext( LDAPURLDesc *srv )
{
	int i, crit;
	char *ext;

	if ( !srv->lud_exts )
		return 0;

	for (i=0; srv->lud_exts[i]; i++) {
		crit = 0;
		ext = srv->lud_exts[i];
		if ( ext[0] == '!') {
			ext++;
			crit = 1;
		}
		if ( !strcasecmp( ext, "StartTLS" ) ||
Howard Chu's avatar
Howard Chu committed
437
			!strcasecmp( ext, "X-StartTLS" ) ||
Howard Chu's avatar
Howard Chu committed
438
439
440
441
442
443
444
			!strcmp( ext, LDAP_EXOP_START_TLS )) {
			return crit + 1;
		}
	}
	return 0;
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
445
/*
446
447
 * always protected by conn_mutex
 * optionally protected by req_mutex and res_mutex
Pierangelo Masarati's avatar
Pierangelo Masarati committed
448
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
449
LDAPConn *
450
ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
451
	int connect, LDAPreqinfo *bind, int m_req, int m_res )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
452
453
{
	LDAPConn	*lc;
454
	int		async = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
455

456
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
457
	Debug3( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
458
		use_ldsb, connect, (bind != NULL) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
459
460
461
462
	/*
	 * make a new LDAP server connection
	 * XXX open connection synchronously for now
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
463
464
	lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ) );
	if ( lc == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
465
466
467
		ld->ld_errno = LDAP_NO_MEMORY;
		return( NULL );
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
468
469
	
	if ( use_ldsb ) {
470
		assert( ld->ld_sb != NULL );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
471
		lc->lconn_sb = ld->ld_sb;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
472

Pierangelo Masarati's avatar
Pierangelo Masarati committed
473
474
475
476
477
478
479
480
	} else {
		lc->lconn_sb = ber_sockbuf_alloc();
		if ( lc->lconn_sb == NULL ) {
			LDAP_FREE( (char *)lc );
			ld->ld_errno = LDAP_NO_MEMORY;
			return( NULL );
		}
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
481
482

	if ( connect ) {
483
484
		LDAPURLDesc	**srvp, *srv = NULL;

485
486
		async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );

487
		for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) {
488
489
490
491
			int		rc;

			rc = ldap_int_open_connection( ld, lc, *srvp, async );
			if ( rc != -1 ) {
492
493
				srv = *srvp;

494
495
496
497
				/* If we fully connected, async is moot */
				if ( rc == 0 )
					async = 0;

498
				if ( ld->ld_urllist_proc && ( !async || rc != -2 ) ) {
499
500
501
					ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params );
				}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
502
503
504
505
506
				break;
			}
		}

		if ( srv == NULL ) {
507
508
509
			if ( !use_ldsb ) {
				ber_sockbuf_free( lc->lconn_sb );
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
510
511
512
			LDAP_FREE( (char *)lc );
			ld->ld_errno = LDAP_SERVER_DOWN;
			return( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
513
514
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
515
		lc->lconn_server = ldap_url_dup( srv );
Howard Chu's avatar
Howard Chu committed
516
517
518
519
520
521
522
		if ( !lc->lconn_server ) {
			if ( !use_ldsb )
				ber_sockbuf_free( lc->lconn_sb );
			LDAP_FREE( (char *)lc );
			ld->ld_errno = LDAP_NO_MEMORY;
			return( NULL );
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
523
524
	}

525
	lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
526
527
528
	lc->lconn_next = ld->ld_conns;
	ld->ld_conns = lc;

Howard Chu's avatar
Howard Chu committed
529
	if ( connect ) {
Howard Chu's avatar
Howard Chu committed
530
#ifdef HAVE_TLS
Howard Chu's avatar
Howard Chu committed
531
		if ( lc->lconn_server->lud_exts ) {
Howard Chu's avatar
Howard Chu committed
532
533
534
535
536
537
538
539
			int rc, ext = find_tls_ext( lc->lconn_server );
			if ( ext ) {
				LDAPConn	*savedefconn;

				savedefconn = ld->ld_defconn;
				++lc->lconn_refcnt;	/* avoid premature free */
				ld->ld_defconn = lc;

540
541
542
				LDAP_REQ_UNLOCK_IF(m_req);
				LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
				LDAP_RES_UNLOCK_IF(m_res);
Howard Chu's avatar
Howard Chu committed
543
				rc = ldap_start_tls_s( ld, NULL, NULL );
544
545
546
				LDAP_RES_LOCK_IF(m_res);
				LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
				LDAP_REQ_LOCK_IF(m_req);
Howard Chu's avatar
Howard Chu committed
547
548
549
550
551
552
553
554
555
556
557
558
				ld->ld_defconn = savedefconn;
				--lc->lconn_refcnt;

				if ( rc != LDAP_SUCCESS && ext == 2 ) {
					ldap_free_connection( ld, lc, 1, 0 );
					return NULL;
				}
			}
		}
#endif
	}

559
	if ( bind != NULL ) {
560
		int		err = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
561
562
		LDAPConn	*savedefconn;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
563
564
		/* Set flag to prevent additional referrals
		 * from being processed on this
565
566
567
568
		 * connection until the bind has completed
		 */
		lc->lconn_rebind_inprogress = 1;
		/* V3 rebind function */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
569
		if ( ld->ld_rebind_proc != NULL) {
570
			LDAPURLDesc	*srvfunc;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
571

572
			srvfunc = ldap_url_dup( *srvlist );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
573
			if ( srvfunc == NULL ) {
574
575
				ld->ld_errno = LDAP_NO_MEMORY;
				err = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
576
			} else {
577
578
579
580
				savedefconn = ld->ld_defconn;
				++lc->lconn_refcnt;	/* avoid premature free */
				ld->ld_defconn = lc;

581
				Debug0( LDAP_DEBUG_TRACE, "Call application rebind_proc\n" );
582
583
584
				LDAP_REQ_UNLOCK_IF(m_req);
				LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
				LDAP_RES_UNLOCK_IF(m_res);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
585
586
				err = (*ld->ld_rebind_proc)( ld,
					bind->ri_url, bind->ri_request, bind->ri_msgid,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
587
					ld->ld_rebind_params );
588
589
590
				LDAP_RES_LOCK_IF(m_res);
				LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
				LDAP_REQ_LOCK_IF(m_req);
591
592
593
594

				ld->ld_defconn = savedefconn;
				--lc->lconn_refcnt;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
595
596
				if ( err != 0 ) {
					err = -1;
597
598
					ldap_free_connection( ld, lc, 1, 0 );
					lc = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
599
600
				}
				ldap_free_urldesc( srvfunc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
601
			}
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
602

603
		} else {
604
605
606
			int		msgid, rc;
			struct berval	passwd = BER_BVNULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
607
608
			savedefconn = ld->ld_defconn;
			++lc->lconn_refcnt;	/* avoid premature free */
609
			ld->ld_defconn = lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
610

611
612
			Debug0( LDAP_DEBUG_TRACE,
				"anonymous rebind via ldap_sasl_bind(\"\")\n" );
613

614
615
616
			LDAP_REQ_UNLOCK_IF(m_req);
			LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
			LDAP_RES_UNLOCK_IF(m_res);
617
618
619
			rc = ldap_sasl_bind( ld, "", LDAP_SASL_SIMPLE, &passwd,
				NULL, NULL, &msgid );
			if ( rc != LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
620
				err = -1;
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649

			} else {
				for ( err = 1; err > 0; ) {
					struct timeval	tv = { 0, 100000 };
					LDAPMessage	*res = NULL;

					switch ( ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) {
					case -1:
						err = -1;
						break;

					case 0:
#ifdef LDAP_R_COMPILE
						ldap_pvt_thread_yield();
#endif
						break;

					case LDAP_RES_BIND:
						rc = ldap_parse_result( ld, res, &err, NULL, NULL, NULL, NULL, 1 );
						if ( rc != LDAP_SUCCESS ) {
							err = -1;

						} else if ( err != LDAP_SUCCESS ) {
							err = -1;
						}
						/* else err == LDAP_SUCCESS == 0 */
						break;

					default:
650
						Debug3( LDAP_DEBUG_TRACE,
651
652
653
							"ldap_new_connection %p: "
							"unexpected response %d "
							"from BIND request id=%d\n",
654
							(void *) ld, ldap_msgtype( res ), msgid );
655
656
						err = -1;
						break;
657
658
					}
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
659
			}
660
661
662
			LDAP_RES_LOCK_IF(m_res);
			LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
			LDAP_REQ_LOCK_IF(m_req);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
663
			ld->ld_defconn = savedefconn;
664
			--lc->lconn_refcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
665

Pierangelo Masarati's avatar
Pierangelo Masarati committed
666
667
668
669
			if ( err != 0 ) {
				ldap_free_connection( ld, lc, 1, 0 );
				lc = NULL;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
670
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
671
		if ( lc != NULL )
672
673
			lc->lconn_rebind_inprogress = 0;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
674
675
676
677
	return( lc );
}


678
/* protected by ld_conn_mutex */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
679
static LDAPConn *
680
find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
681
682
683
684
685
686
/*
 * return an existing connection (if any) to the server srv
 * if "any" is non-zero, check for any server in the "srv" chain
 */
{
	LDAPConn	*lc;
687
688
	LDAPURLDesc	*lcu, *lsu;
	int lcu_port, lsu_port;
689
	int found = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
690

691
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
692
	for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
693
		lcu = lc->lconn_server;
694
695
696
		lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme,
			lcu->lud_port );

697
		for ( lsu = srv; lsu != NULL; lsu = lsu->lud_next ) {
698
699
700
			lsu_port = ldap_pvt_url_scheme_port( lsu->lud_scheme,
				lsu->lud_port );

701
702
			if ( lsu_port == lcu_port
				&& strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0
703
				&& lcu->lud_host != NULL && lsu->lud_host != NULL
704
				&& strcasecmp( lsu->lud_host, lcu->lud_host ) == 0 )
705
			{
706
707
				found = 1;
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
708
			}
709
710

			if ( !any ) break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
711
		}
712
713
		if ( found )
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
714
	}
715
	return lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
716
717
718
719
}



720
/* protected by ld_conn_mutex */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
721
722
723
static void
use_connection( LDAP *ld, LDAPConn *lc )
{
724
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
725
	++lc->lconn_refcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
726
	lc->lconn_lastused = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
727
728
729
}


730
/* protected by ld_conn_mutex */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
731
void
732
ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
733
734
735
{
	LDAPConn	*tmplc, *prevlc;

736
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
737
	Debug2( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
738
		"ldap_free_connection %d %d\n",
739
		force, unbind );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
740
741

	if ( force || --lc->lconn_refcnt <= 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
742
743
744
		/* remove from connections list first */

		for ( prevlc = NULL, tmplc = ld->ld_conns;
745
746
747
			tmplc != NULL;
			tmplc = tmplc->lconn_next )
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
748
749
750
751
752
753
			if ( tmplc == lc ) {
				if ( prevlc == NULL ) {
				    ld->ld_conns = tmplc->lconn_next;
				} else {
				    prevlc->lconn_next = tmplc->lconn_next;
				}
754
755
756
				if ( ld->ld_defconn == lc ) {
					ld->ld_defconn = NULL;
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
757
758
				break;
			}
759
			prevlc = tmplc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
760
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
761

762
763
764
765
766
767
768
		/* process connection callbacks */
		{
			struct ldapoptions *lo;
			ldaplist *ll;
			ldap_conncb *cb;

			lo = &ld->ld_options;
769
			LDAP_MUTEX_LOCK( &lo->ldo_mutex );
770
771
772
773
774
775
			if ( lo->ldo_conn_cbs ) {
				for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
					cb = ll->ll_data;
					cb->lc_del( ld, lc->lconn_sb, cb );
				}
			}
776
			LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
777
			lo = LDAP_INT_GLOBAL_OPT();
778
			LDAP_MUTEX_LOCK( &lo->ldo_mutex );
779
780
781
782
783
784
			if ( lo->ldo_conn_cbs ) {
				for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
					cb = ll->ll_data;
					cb->lc_del( ld, lc->lconn_sb, cb );
				}
			}
785
			LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
786
787
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
788
789
790
791
792
793
794
795
796
797
798
799
800
801
		if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
			ldap_mark_select_clear( ld, lc->lconn_sb );
			if ( unbind ) {
				ldap_send_unbind( ld, lc->lconn_sb,
						NULL, NULL );
			}
		}

		if ( lc->lconn_ber != NULL ) {
			ber_free( lc->lconn_ber, 1 );
		}

		ldap_int_sasl_close( ld, lc );

802
		ldap_free_urllist( lc->lconn_server );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
803

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
804
805
806
		/* FIXME: is this at all possible?
		 * ldap_ld_free() in unbind.c calls ldap_free_connection()
		 * with force == 1 __after__ explicitly calling
807
		 * ldap_tavl_free on ld->ld_requests */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
808
		if ( force ) {
809
810
			ldap_tavl_free( ld->ld_requests, ldap_do_free_request );
			ld->ld_requests = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
811
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
812

813
		if ( lc->lconn_sb != ld->ld_sb ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
814
			ber_sockbuf_free( lc->lconn_sb );
815
816
		} else {
			ber_int_sb_close( lc->lconn_sb );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
817
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
818

Pierangelo Masarati's avatar
Pierangelo Masarati committed
819
		if ( lc->lconn_rebind_queue != NULL) {
820
			int i;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
821
822
			for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) {
				LDAP_VFREE( lc->lconn_rebind_queue[i] );
823
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
824
			LDAP_FREE( lc->lconn_rebind_queue );
825
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
826

827
		LDAP_FREE( lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
828

829
830
		Debug0( LDAP_DEBUG_TRACE,
			"ldap_free_connection: actually freed\n" );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
831

Kurt Zeilenga's avatar
Kurt Zeilenga committed
832
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
833
		lc->lconn_lastused = time( NULL );
834
835
		Debug1( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n",
				lc->lconn_refcnt );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
836
837
838
839
	}
}


840
/* Protects self with ld_conn_mutex */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
841
842
#ifdef LDAP_DEBUG
void
843
ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
844
845
{
	LDAPConn	*lc;
846
   	char		timebuf[32];
Kurt Zeilenga's avatar
Kurt Zeilenga committed
847

848
	Debug2( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "" );
849
	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
850
851
	for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
		if ( lc->lconn_server != NULL ) {
852
			Debug3( LDAP_DEBUG_TRACE, "* host: %s  port: %d%s\n",
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
853
854
855
856
				( lc->lconn_server->lud_host == NULL ) ? "(null)"
				: lc->lconn_server->lud_host,
				lc->lconn_server->lud_port, ( lc->lconn_sb ==
				ld->ld_sb ) ? "  (default)" : "" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
857
		}
858
		if ( lc->lconn_sb != NULL ) {
859
			char 			from[LDAP_IPADDRLEN];
860
861
862
863
864
865
			struct berval 	frombv = BER_BVC(from);
			ber_socket_t 	sb;
			if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sb ) == 1 ) {
				struct sockaddr_in sin;
				socklen_t len = sizeof( sin );
				if ( getsockname( sb, (struct sockaddr *)&sin, &len ) == 0 ) {
866
					ldap_pvt_sockaddrstr( (Sockaddr *) &sin, &frombv );
867
868
869
870
871
					Debug1( LDAP_DEBUG_TRACE, "* from: %s\n",
						( from == NULL ) ? "(null)" : from );
				}
			}
		}
872
		Debug2( LDAP_DEBUG_TRACE, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
873
			( lc->lconn_status == LDAP_CONNST_NEEDSOCKET )
874
875
				? "NeedSocket" :
				( lc->lconn_status == LDAP_CONNST_CONNECTING )
876
877
					? "Connecting" : "Connected" );
		Debug2( LDAP_DEBUG_TRACE, "  last used: %s%s\n",
878
			ldap_pvt_ctime( &lc->lconn_lastused, timebuf ),
879
			lc->lconn_rebind_inprogress ? "  rebind in progress" : "" );
880
881
882
883
884
885
886
		if ( lc->lconn_rebind_inprogress ) {
			if ( lc->lconn_rebind_queue != NULL) {
				int	i;

				for ( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) {
					int	j;
					for( j = 0; lc->lconn_rebind_queue[i][j] != 0; j++ ) {
887
						Debug3( LDAP_DEBUG_TRACE, "    queue %d entry %d - %s\n",
888
							i, j, lc->lconn_rebind_queue[i][j] );
889
890
891
					}
				}
			} else {
892
				Debug0( LDAP_DEBUG_TRACE, "    queue is empty\n" );
893
894
			}
		}
895
		Debug0( LDAP_DEBUG_TRACE, "\n" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
896
897
898
899
		if ( !all ) {
			break;
		}
	}
900
	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
901
902
903
}


904
/* protected by req_mutex and res_mutex */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
905
void
906
ldap_dump_requests_and_responses( LDAP *ld )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
907
908
{
	LDAPMessage	*lm, *l;
909
	TAvlnode *node;
910
	int		i;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
911

912
913
	Debug1( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n",
		(void *)ld );
914
915
	node = ldap_tavl_end( ld->ld_requests, TAVL_DIR_LEFT );
	if ( node == NULL ) {
916
		Debug0( LDAP_DEBUG_TRACE, "   Empty\n" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
917
	}
918
919
920
	for ( i = 0 ; node != NULL; i++, node = ldap_tavl_next( node, TAVL_DIR_RIGHT ) ) {
		LDAPRequest	*lr = node->avl_data;

921
		Debug3( LDAP_DEBUG_TRACE, " * msgid %d,  origid %d, status %s\n",
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
922
923
924
925
926
927
			lr->lr_msgid, lr->lr_origid,
			( lr->lr_status == LDAP_REQST_INPROGRESS ) ? "InProgress" :
			( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" :
			( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" :
			( lr->lr_status == LDAP_REQST_WRITING ) ? "Writing" :
			( lr->lr_status == LDAP_REQST_COMPLETED ) ? "RequestCompleted"
928
				: "InvalidStatus" );
929
930
		Debug2( LDAP_DEBUG_TRACE, "   outstanding referrals %d, parent count %d\n",
			lr->lr_outrefcnt, lr->lr_parentcnt );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
931
	}
932
	Debug3( LDAP_DEBUG_TRACE, "  ld %p request count %d (abandoned %lu)\n",
933
		(void *)ld, i, ld->ld_nabandoned );
934
	Debug1( LDAP_DEBUG_TRACE, "** ld %p Response Queue:\n", (void *)ld );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
935
	if ( ( lm = ld->ld_responses ) == NULL ) {
936
		Debug0( LDAP_DEBUG_TRACE, "   Empty\n" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
937
	}
938
	for ( i = 0; lm != NULL; lm = lm->lm_next, i++ ) {
939
940
		Debug2( LDAP_DEBUG_TRACE, " * msgid %d,  type %lu\n",
		    lm->lm_msgid, (unsigned long)lm->lm_msgtype );
941
		if ( lm->lm_chain != NULL ) {
942
			Debug0( LDAP_DEBUG_TRACE, "   chained responses:\n" );
943
			for ( l = lm->lm_chain; l != NULL; l = l->lm_chain ) {
944
				Debug2( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
945
946
					"  * msgid %d,  type %lu\n",
					l->lm_msgid,
947
					(unsigned long)l->lm_msgtype );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
948
949
950
			}
		}
	}
951
	Debug2( LDAP_DEBUG_TRACE, "  ld %p response count %d\n", (void *)ld, i );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
952
953
954
}
#endif /* LDAP_DEBUG */

955
/* protected by req_mutex */
956
957
void
ldap_do_free_request( void *arg )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
958
{
959
960
961
962
963
	LDAPRequest *lr = arg;

	Debug3( LDAP_DEBUG_TRACE, "ldap_do_free_request: "
			"asked to free lr %p msgid %d refcnt %d\n",
			lr, lr->lr_msgid, lr->lr_refcnt );
964
965
966
	/* if lr_refcnt > 0, the request has been looked up 
	 * by ldap_find_request_by_msgid(); if in the meanwhile
	 * the request is free()'d by someone else, just decrease
967
	 * the reference count; later on, it will be freed. */
968
	if ( lr->lr_refcnt > 0 ) {
969
		assert( lr->lr_refcnt == 1 );
970
971
972
973
		lr->lr_refcnt = -lr->lr_refcnt;
		return;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
974
975
	if ( lr->lr_ber != NULL ) {
		ber_free( lr->lr_ber, 1 );
976
		lr->lr_ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
977
978
979
	}

	if ( lr->lr_res_error != NULL ) {
980
		LDAP_FREE( lr->lr_res_error );
981
		lr->lr_res_error = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
982
983
984
	}

	if ( lr->lr_res_matched != NULL ) {
985
		LDAP_FREE( lr->lr_res_matched );
986
		lr->lr_res_matched = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
987
988
	}

989
	LDAP_FREE( lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
990
991
}

992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
int
ldap_req_cmp( const void *l, const void *r )
{
	const LDAPRequest *left = l, *right = r;
	return left->lr_msgid - right->lr_msgid;
}

/* protected by req_mutex */
static void
ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
{
	LDAPRequest *removed;

	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );