request.c 40.8 KB
Newer Older
1
/* $OpenLDAP$ */
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1998-2012 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
	Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 );
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 );
131

Howard Chu's avatar
Howard Chu committed
132
	}
133
134
	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
135
136
	if( rc < 0 ) {
		ber_free( ber, 1 );
137
		LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
Howard Chu's avatar
Howard Chu committed
138
139
		return( -1 );
	} else if ( rc == 0 ) {
140
		Debug( LDAP_DEBUG_TRACE,
141
142
			"ldap_open_defconn: successful\n",
			0, 0, 0 );
143
144
	}

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


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

182
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
183
	if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) {
184
		if ( sock_errno() == EAGAIN ) {
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
			/* 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 );
205
		ldap_clear_select_write( ld, lc->lconn_sb );
206
207
208
	}
	return 0;
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
209

210
211
212
213
214
215
216
/*
 * 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
217
int
218
219
220
221
222
ldap_send_server_request(
	LDAP *ld,
	BerElement *ber,
	ber_int_t msgid,
	LDAPRequest *parentreq,
223
	LDAPURLDesc **srvlist,
224
	LDAPConn *lc,
225
226
227
	LDAPreqinfo *bind,
	int m_noconn,
	int m_res )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
228
229
{
	LDAPRequest	*lr;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
230
	int		incparent, rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
231

232
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
233
	Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
234

235
	incparent = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
236
237
	ld->ld_errno = LDAP_SUCCESS;	/* optimistic */

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

256
257
258
259
260
261
262
263
	/* 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 ... */
264
		switch ( ldap_int_poll( ld, sd, &tv, 1 ) ) {
265
266
267
268
269
		case 0:
			/* go on! */
			lc->lconn_status = LDAP_CONNST_CONNECTED;
			break;

Howard Chu's avatar
Howard Chu committed
270
		case -2:
271
			/* async only occurs if a network timeout is set */
Howard Chu's avatar
Howard Chu committed
272
273

			/* honor network timeout */
274
			LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
Howard Chu's avatar
Howard Chu committed
275
276
277
278
279
			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;
			}
280
			LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
Howard Chu's avatar
Howard Chu committed
281
			/* fallthru */
282
283
284
285
286
287
288

		default:
			/* error */
			break;
		}
	}

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

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

	use_connection( ld, lc );
304

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

321
322
323
324
325
	/* 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.
	 */
326
	rc = 0;
327
328
	if ( ld->ld_requests &&
		ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
Pierangelo Masarati's avatar
Pierangelo Masarati committed
329
330
		ldap_int_flush_request( ld, ld->ld_requests ) < 0 )
	{
331
		rc = -1;
332
	}
333
334
335
336
	if ( rc ) {
		LDAP_CONN_UNLOCK_IF(m_noconn);
		return rc;
	}
337

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
338
	lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
339
	if ( lr == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
340
		ld->ld_errno = LDAP_NO_MEMORY;
341
		ldap_free_connection( ld, lc, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
342
		ber_free( ber, 1 );
343
344
345
346
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
347
		LDAP_CONN_UNLOCK_IF(m_noconn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
348
349
350
351
352
353
354
355
		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 */
356
357
358
359
		if ( !incparent ) { 
			/* Increment if we didn't do it before the bind */
			++parentreq->lr_outrefcnt;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
360
		lr->lr_origid = parentreq->lr_origid;
361
		lr->lr_parentcnt = ++parentreq->lr_parentcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
362
		lr->lr_parent = parentreq;
363
364
		lr->lr_refnext = parentreq->lr_child;
		parentreq->lr_child = lr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
365
366
367
368
	} else {			/* original request */
		lr->lr_origid = lr->lr_msgid;
	}

369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
	/* Extract requestDN for future reference */
	{
		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;
		}
	}

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
394
	lr->lr_prev = NULL;
395
396
	lr->lr_next = ld->ld_requests;
	if ( lr->lr_next != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
397
398
399
400
		lr->lr_next->lr_prev = lr;
	}
	ld->ld_requests = lr;

401
	ld->ld_errno = LDAP_SUCCESS;
402
	if ( ldap_int_flush_request( ld, lr ) == -1 ) {
403
		msgid = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
404
405
	}

406
	LDAP_CONN_UNLOCK_IF(m_noconn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
407
408
409
	return( msgid );
}

Howard Chu's avatar
Howard Chu committed
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/* 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
428
			!strcasecmp( ext, "X-StartTLS" ) ||
Howard Chu's avatar
Howard Chu committed
429
430
431
432
433
434
435
			!strcmp( ext, LDAP_EXOP_START_TLS )) {
			return crit + 1;
		}
	}
	return 0;
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
436
/*
437
438
 * always protected by conn_mutex
 * optionally protected by req_mutex and res_mutex
Pierangelo Masarati's avatar
Pierangelo Masarati committed
439
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
440
LDAPConn *
441
ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
442
	int connect, LDAPreqinfo *bind, int m_req, int m_res )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
443
444
{
	LDAPConn	*lc;
445
	int		async = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
446

447
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
448
449
	Debug( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n",
		use_ldsb, connect, (bind != NULL) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
450
451
452
453
	/*
	 * make a new LDAP server connection
	 * XXX open connection synchronously for now
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
454
455
	lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ) );
	if ( lc == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
456
457
458
		ld->ld_errno = LDAP_NO_MEMORY;
		return( NULL );
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
459
460
	
	if ( use_ldsb ) {
461
		assert( ld->ld_sb != NULL );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
462
		lc->lconn_sb = ld->ld_sb;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
463

Pierangelo Masarati's avatar
Pierangelo Masarati committed
464
465
466
467
468
469
470
471
	} 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
472
473

	if ( connect ) {
474
475
		LDAPURLDesc	**srvp, *srv = NULL;

476
477
		async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );

478
		for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) {
479
480
481
482
			int		rc;

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

485
				if ( ld->ld_urllist_proc && ( !async || rc != -2 ) ) {
486
487
488
					ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params );
				}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
489
490
491
492
493
				break;
			}
		}

		if ( srv == NULL ) {
494
495
496
			if ( !use_ldsb ) {
				ber_sockbuf_free( lc->lconn_sb );
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
497
498
499
			LDAP_FREE( (char *)lc );
			ld->ld_errno = LDAP_SERVER_DOWN;
			return( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
500
501
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
502
		lc->lconn_server = ldap_url_dup( srv );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
503
504
	}

505
	lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
506
507
508
	lc->lconn_next = ld->ld_conns;
	ld->ld_conns = lc;

Howard Chu's avatar
Howard Chu committed
509
	if ( connect ) {
Howard Chu's avatar
Howard Chu committed
510
#ifdef HAVE_TLS
Howard Chu's avatar
Howard Chu committed
511
		if ( lc->lconn_server->lud_exts ) {
Howard Chu's avatar
Howard Chu committed
512
513
514
515
516
517
518
519
			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;

520
521
522
				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
523
				rc = ldap_start_tls_s( ld, NULL, NULL );
524
525
526
				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
527
528
529
530
531
532
533
534
535
536
537
538
				ld->ld_defconn = savedefconn;
				--lc->lconn_refcnt;

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

539
	if ( bind != NULL ) {
540
		int		err = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
541
542
		LDAPConn	*savedefconn;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
543
544
		/* Set flag to prevent additional referrals
		 * from being processed on this
545
546
547
548
		 * connection until the bind has completed
		 */
		lc->lconn_rebind_inprogress = 1;
		/* V3 rebind function */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
549
		if ( ld->ld_rebind_proc != NULL) {
550
			LDAPURLDesc	*srvfunc;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
551

552
			srvfunc = ldap_url_dup( *srvlist );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
553
			if ( srvfunc == NULL ) {
554
555
				ld->ld_errno = LDAP_NO_MEMORY;
				err = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
			} else {
557
558
559
560
				savedefconn = ld->ld_defconn;
				++lc->lconn_refcnt;	/* avoid premature free */
				ld->ld_defconn = lc;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
561
				Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0);
562
563
564
				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
565
566
				err = (*ld->ld_rebind_proc)( ld,
					bind->ri_url, bind->ri_request, bind->ri_msgid,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
567
					ld->ld_rebind_params );
568
569
570
				LDAP_RES_LOCK_IF(m_res);
				LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
				LDAP_REQ_LOCK_IF(m_req);
571
572
573
574

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
575
576
				if ( err != 0 ) {
					err = -1;
577
578
					ldap_free_connection( ld, lc, 1, 0 );
					lc = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
579
580
				}
				ldap_free_urldesc( srvfunc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
581
			}
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
582

583
		} else {
584
585
586
			int		msgid, rc;
			struct berval	passwd = BER_BVNULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
587
588
			savedefconn = ld->ld_defconn;
			++lc->lconn_refcnt;	/* avoid premature free */
589
			ld->ld_defconn = lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
590

591
592
593
594
			Debug( LDAP_DEBUG_TRACE,
				"anonymous rebind via ldap_sasl_bind(\"\")\n",
				0, 0, 0);

595
596
597
			LDAP_REQ_UNLOCK_IF(m_req);
			LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
			LDAP_RES_UNLOCK_IF(m_res);
598
599
600
			rc = ldap_sasl_bind( ld, "", LDAP_SASL_SIMPLE, &passwd,
				NULL, NULL, &msgid );
			if ( rc != LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
601
				err = -1;
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630

			} 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:
631
632
633
634
						Debug( LDAP_DEBUG_TRACE,
							"ldap_new_connection %p: "
							"unexpected response %d "
							"from BIND request id=%d\n",
635
							(void *) ld, ldap_msgtype( res ), msgid );
636
637
						err = -1;
						break;
638
639
					}
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
640
			}
641
642
643
			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
644
			ld->ld_defconn = savedefconn;
645
			--lc->lconn_refcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
646

Pierangelo Masarati's avatar
Pierangelo Masarati committed
647
648
649
650
			if ( err != 0 ) {
				ldap_free_connection( ld, lc, 1, 0 );
				lc = NULL;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
651
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
652
		if ( lc != NULL )
653
654
			lc->lconn_rebind_inprogress = 0;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
655
656
657
658
	return( lc );
}


659
/* protected by ld_conn_mutex */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
660
static LDAPConn *
661
find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
662
663
664
665
666
667
/*
 * 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;
668
669
	LDAPURLDesc	*lcu, *lsu;
	int lcu_port, lsu_port;
670
	int found = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
671

672
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
673
	for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
674
		lcu = lc->lconn_server;
675
676
677
		lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme,
			lcu->lud_port );

678
		for ( lsu = srv; lsu != NULL; lsu = lsu->lud_next ) {
679
680
681
			lsu_port = ldap_pvt_url_scheme_port( lsu->lud_scheme,
				lsu->lud_port );

682
683
			if ( lsu_port == lcu_port
				&& strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0
684
				&& lcu->lud_host != NULL && lsu->lud_host != NULL
685
				&& strcasecmp( lsu->lud_host, lcu->lud_host ) == 0 )
686
			{
687
688
				found = 1;
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
689
			}
690
691

			if ( !any ) break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
692
		}
693
694
		if ( found )
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
695
	}
696
	return lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
697
698
699
700
}



701
/* protected by ld_conn_mutex */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
702
703
704
static void
use_connection( LDAP *ld, LDAPConn *lc )
{
705
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
706
	++lc->lconn_refcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
707
	lc->lconn_lastused = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
708
709
710
}


711
/* protected by ld_conn_mutex */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
712
void
713
ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
714
715
716
{
	LDAPConn	*tmplc, *prevlc;

717
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
718
719
720
	Debug( LDAP_DEBUG_TRACE,
		"ldap_free_connection %d %d\n",
		force, unbind, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
721
722

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

		for ( prevlc = NULL, tmplc = ld->ld_conns;
726
727
728
			tmplc != NULL;
			tmplc = tmplc->lconn_next )
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
729
730
731
732
733
734
			if ( tmplc == lc ) {
				if ( prevlc == NULL ) {
				    ld->ld_conns = tmplc->lconn_next;
				} else {
				    prevlc->lconn_next = tmplc->lconn_next;
				}
735
736
737
				if ( ld->ld_defconn == lc ) {
					ld->ld_defconn = NULL;
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
738
739
				break;
			}
740
			prevlc = tmplc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
741
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
742

743
744
745
746
747
748
749
		/* process connection callbacks */
		{
			struct ldapoptions *lo;
			ldaplist *ll;
			ldap_conncb *cb;

			lo = &ld->ld_options;
750
			LDAP_MUTEX_LOCK( &lo->ldo_mutex );
751
752
753
754
755
756
			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 );
				}
			}
757
			LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
758
			lo = LDAP_INT_GLOBAL_OPT();
759
			LDAP_MUTEX_LOCK( &lo->ldo_mutex );
760
761
762
763
764
765
			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 );
				}
			}
766
			LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
767
768
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
769
770
771
772
773
774
775
776
777
778
779
780
781
		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 );
782
783
784
#ifdef HAVE_GSSAPI
		ldap_int_gssapi_close( ld, lc );
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
785

786
		ldap_free_urllist( lc->lconn_server );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
787

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
788
789
790
791
		/* FIXME: is this at all possible?
		 * ldap_ld_free() in unbind.c calls ldap_free_connection()
		 * with force == 1 __after__ explicitly calling
		 * ldap_free_request() on all requests */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
792
793
794
795
796
797
798
799
800
801
802
803
804
		if ( force ) {
			LDAPRequest	*lr;

			for ( lr = ld->ld_requests; lr; ) {
				LDAPRequest	*lr_next = lr->lr_next;

				if ( lr->lr_conn == lc ) {
					ldap_free_request_int( ld, lr );
				}

				lr = lr_next;
			}
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
805

806
		if ( lc->lconn_sb != ld->ld_sb ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
807
			ber_sockbuf_free( lc->lconn_sb );
808
809
		} else {
			ber_int_sb_close( lc->lconn_sb );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
810
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
811

Pierangelo Masarati's avatar
Pierangelo Masarati committed
812
		if ( lc->lconn_rebind_queue != NULL) {
813
			int i;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
814
815
			for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) {
				LDAP_VFREE( lc->lconn_rebind_queue[i] );
816
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
817
			LDAP_FREE( lc->lconn_rebind_queue );
818
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
819

820
		LDAP_FREE( lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
821

Pierangelo Masarati's avatar
Pierangelo Masarati committed
822
823
824
		Debug( LDAP_DEBUG_TRACE,
			"ldap_free_connection: actually freed\n",
			0, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
825

Kurt Zeilenga's avatar
Kurt Zeilenga committed
826
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
827
		lc->lconn_lastused = time( NULL );
828
		Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
829
				lc->lconn_refcnt, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
830
831
832
833
	}
}


834
/* Protects self with ld_conn_mutex */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
835
836
#ifdef LDAP_DEBUG
void
837
ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
838
839
{
	LDAPConn	*lc;
840
   	char		timebuf[32];
Kurt Zeilenga's avatar
Kurt Zeilenga committed
841

842
	Debug( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "", 0 );
843
	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
844
845
	for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
		if ( lc->lconn_server != NULL ) {
846
			Debug( LDAP_DEBUG_TRACE, "* host: %s  port: %d%s\n",
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
847
848
849
850
				( 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
851
		}
852
853
		Debug( LDAP_DEBUG_TRACE, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
			( lc->lconn_status == LDAP_CONNST_NEEDSOCKET )
854
855
856
				? "NeedSocket" :
				( lc->lconn_status == LDAP_CONNST_CONNECTING )
					? "Connecting" : "Connected", 0 );
857
858
859
860
861
862
863
864
865
866
867
868
		Debug( LDAP_DEBUG_TRACE, "  last used: %s%s\n",
			ldap_pvt_ctime( &lc->lconn_lastused, timebuf ),
			lc->lconn_rebind_inprogress ? "  rebind in progress" : "", 0 );
		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++ ) {
						Debug( LDAP_DEBUG_TRACE, "    queue %d entry %d - %s\n",
							i, j, lc->lconn_rebind_queue[i][j] );
869
870
871
					}
				}
			} else {
872
				Debug( LDAP_DEBUG_TRACE, "    queue is empty\n", 0, 0, 0 );
873
874
			}
		}
875
		Debug( LDAP_DEBUG_TRACE, "\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
876
877
878
879
		if ( !all ) {
			break;
		}
	}
880
	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
881
882
883
}


884
/* protected by req_mutex and res_mutex */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
885
void
886
ldap_dump_requests_and_responses( LDAP *ld )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
887
888
889
{
	LDAPRequest	*lr;
	LDAPMessage	*lm, *l;
890
	int		i;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
891

892
893
	Debug( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n",
		(void *)ld, 0, 0 );
894
895
	lr = ld->ld_requests;
	if ( lr == NULL ) {
896
		Debug( LDAP_DEBUG_TRACE, "   Empty\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
897
	}
898
	for ( i = 0; lr != NULL; lr = lr->lr_next, i++ ) {
899
		Debug( LDAP_DEBUG_TRACE, " * msgid %d,  origid %d, status %s\n",
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
900
901
902
903
904
905
			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"
906
907
908
				: "InvalidStatus" );
		Debug( LDAP_DEBUG_TRACE, "   outstanding referrals %d, parent count %d\n",
			lr->lr_outrefcnt, lr->lr_parentcnt, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
909
	}
910
	Debug( LDAP_DEBUG_TRACE, "  ld %p request count %d (abandoned %lu)\n",
911
		(void *)ld, i, ld->ld_nabandoned );
912
	Debug( LDAP_DEBUG_TRACE, "** ld %p Response Queue:\n", (void *)ld, 0, 0 );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
913
	if ( ( lm = ld->ld_responses ) == NULL ) {
914
		Debug( LDAP_DEBUG_TRACE, "   Empty\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
915
	}
916
	for ( i = 0; lm != NULL; lm = lm->lm_next, i++ ) {
917
918
		Debug( LDAP_DEBUG_TRACE, " * msgid %d,  type %lu\n",
		    lm->lm_msgid, (unsigned long)lm->lm_msgtype, 0 );
919
		if ( lm->lm_chain != NULL ) {
920
			Debug( LDAP_DEBUG_TRACE, "   chained responses:\n", 0, 0, 0 );
921
			for ( l = lm->lm_chain; l != NULL; l = l->lm_chain ) {
922
				Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
923
924
					"  * msgid %d,  type %lu\n",
					l->lm_msgid,
925
					(unsigned long)l->lm_msgtype, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
926
927
928
			}
		}
	}
929
	Debug( LDAP_DEBUG_TRACE, "  ld %p response count %d\n", (void *)ld, i, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
930
931
932
}
#endif /* LDAP_DEBUG */

933
/* protected by req_mutex */
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
934
static void
935
ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
936
{
937
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
938
939
940
941
942
	/* 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
	 * the reference count and extract it from the request
	 * list; later on, it will be freed. */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
943
	if ( lr->lr_prev == NULL ) {
944
945
946
947
948
949
950
951
		if ( lr->lr_refcnt == 0 ) {
			/* free'ing the first request? */
			assert( ld->ld_requests == lr );
		}

		if ( ld->ld_requests == lr ) {
			ld->ld_requests = lr->lr_next;
		}
952

Kurt Zeilenga's avatar
Kurt Zeilenga committed
953
954
955
956
957
958
959
960
	} else {
		lr->lr_prev->lr_next = lr->lr_next;
	}

	if ( lr->lr_next != NULL ) {
		lr->lr_next->lr_prev = lr->lr_prev;
	}

961
962
963
964
965
966
967
968
969
	if ( lr->lr_refcnt > 0 ) {
		lr->lr_refcnt = -lr->lr_refcnt;

		lr->lr_prev = NULL;
		lr->lr_next = NULL;

		return;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
970
971
	if ( lr->lr_ber != NULL ) {
		ber_free( lr->lr_ber, 1 );
972
		lr->lr_ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
973
974
975
	}

	if ( lr->lr_res_error != NULL ) {
976
		LDAP_FREE( lr->lr_res_error );
977
		lr->lr_res_error = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
978
979
980
	}

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

985
	LDAP_FREE( lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
986
987
}

988
/* protected by req_mutex */
989
990
991
void
ldap_free_request( LDAP *ld, LDAPRequest *lr )
{
Howard Chu's avatar
Howard Chu committed
992
	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
993
994
995
	Debug( LDAP_DEBUG_TRACE, "ldap_free_request (origid %d, msgid %d)\n",
		lr->lr_origid, lr->lr_msgid, 0 );

996
	/* free all referrals (child requests) */
997
	while ( lr->lr_child ) {
998
		ldap_free_request( ld, lr->lr_child );
999
	}
1000

1001
	if ( lr->lr_parent != NULL ) {
1002
1003
		LDAPRequest     **lrp;

1004
		--lr->lr_parent->lr_outrefcnt;
1005
1006
1007
1008
1009
1010
1011
		for ( lrp = &lr->lr_parent->lr_child;
			*lrp && *lrp != lr;
			lrp = &(*lrp)->lr_refnext );

		if ( *lrp == lr ) {
			*lrp = lr->lr_refnext;
		}
1012
1013
1014
1015
	}
	ldap_free_request_int( ld, lr );
}

1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
/*
 * call first time with *cntp = -1
 * when returns *cntp == -1, no referrals are left
 *
 * NOTE: may replace *refsp, or shuffle the contents
 * of the original array.
 */
static int ldap_int_nextref(
	LDAP			*ld,
	char			***refsp,
	int			*cntp,
	void			*params )
{
	assert( refsp != NULL );
	assert( *refsp != NULL );
	assert( cntp != NULL );

	if ( *cntp < -1 ) {
		*cntp = -1;
		return -1;
	}

	(*cntp)++;

	if ( (*refsp)[ *cntp ] == NULL ) {
		*cntp = -1;
	}

	return 0;
}