request.c 38.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-2009 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
static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPURLDesc *srv, int any ));
57
static void use_connection LDAP_P(( LDAP *ld, LDAPConn *lc ));
Pierangelo Masarati's avatar
Pierangelo Masarati committed
58
static void ldap_free_request_int LDAP_P(( LDAP *ld, LDAPRequest *lr ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
59

60
61
static BerElement *
re_encode_request( LDAP *ld,
62
	BerElement *origber,
63
	ber_int_t msgid,
64
	int sref,
65
66
	LDAPURLDesc *srv,
	int *type );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
67
68

BerElement *
69
ldap_alloc_ber_with_options( LDAP *ld )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
70
71
72
{
	BerElement	*ber;

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
73
74
	ber = ber_alloc_t( ld->ld_lberoptions );
	if ( ber == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
75
76
77
78
79
80
81
82
		ld->ld_errno = LDAP_NO_MEMORY;
	}

	return( ber );
}


void
83
ldap_set_ber_options( LDAP *ld, BerElement *ber )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
84
85
86
87
88
{
	ber->ber_options = ld->ld_lberoptions;
}


89
ber_int_t
Kurt Zeilenga's avatar
Kurt Zeilenga committed
90
91
ldap_send_initial_request(
	LDAP *ld,
92
	ber_tag_t msgtype,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
93
	const char *dn,
94
95
	BerElement *ber,
	ber_int_t msgid)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
96
{
Howard Chu's avatar
Howard Chu committed
97
	int rc = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
98

99
	Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
100

Howard Chu's avatar
Howard Chu committed
101
102
103
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
104
	if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
105
		/* not connected yet */
Howard Chu's avatar
Howard Chu committed
106
		rc = ldap_open_defconn( ld );
107

Howard Chu's avatar
Howard Chu committed
108
109
110
111
112
113
114
115
	}
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
	if( rc < 0 ) {
		ber_free( ber, 1 );
		return( -1 );
	} else if ( rc == 0 ) {
116
		Debug( LDAP_DEBUG_TRACE,
117
118
			"ldap_open_defconn: successful\n",
			0, 0, 0 );
119
120
	}

121
122
123
124
125
126
127
128
129
130
131
132
#ifdef LDAP_CONNECTIONLESS
	if (LDAP_IS_UDP(ld)) {
		if (msgtype == LDAP_REQ_BIND) {
			if (ld->ld_options.ldo_cldapdn)
				ldap_memfree(ld->ld_options.ldo_cldapdn);
			ld->ld_options.ldo_cldapdn = ldap_strdup(dn);
			return 0;
		}
		if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH)
			return LDAP_PARAM_ERROR;
	}
#endif
133
134
135
136
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
	rc = ldap_send_server_request( ld, ber, msgid, NULL,
Howard Chu's avatar
Howard Chu committed
137
		NULL, NULL, NULL );
138
139
140
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
141
	return(rc);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
142
143
144
}


145
146
147
int
ldap_int_flush_request(
	LDAP *ld,
148
	LDAPRequest *lr )
149
150
151
{
	LDAPConn *lc = lr->lr_conn;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
152
	if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) {
153
		if ( sock_errno() == EAGAIN ) {
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
			/* 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 );
	}
	return 0;
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
177
178

int
179
180
181
182
183
ldap_send_server_request(
	LDAP *ld,
	BerElement *ber,
	ber_int_t msgid,
	LDAPRequest *parentreq,
184
	LDAPURLDesc **srvlist,
185
	LDAPConn *lc,
186
	LDAPreqinfo *bind )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
187
188
{
	LDAPRequest	*lr;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
189
	int		incparent, rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
190

191
	Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
192

193
	incparent = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
194
195
196
197
198
199
	ld->ld_errno = LDAP_SUCCESS;	/* optimistic */

	if ( lc == NULL ) {
		if ( srvlist == NULL ) {
			lc = ld->ld_defconn;
		} else {
200
			lc = find_connection( ld, *srvlist, 1 );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
201
			if ( lc == NULL ) {
202
				if ( (bind != NULL) && (parentreq != NULL) ) {
203
204
205
206
					/* Remember the bind in the parent */
					incparent = 1;
					++parentreq->lr_outrefcnt;
				}
207
				lc = ldap_new_connection( ld, srvlist, 0, 1, bind );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
208
209
210
211
			}
		}
	}

212
213
214
215
216
217
218
219
220
221
222
223
224
225
	/* 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 ... */
		switch ( ldap_int_poll( ld, sd, &tv ) ) {
		case 0:
			/* go on! */
			lc->lconn_status = LDAP_CONNST_CONNECTED;
			break;

Howard Chu's avatar
Howard Chu committed
226
		case -2:
227
			/* async only occurs if a network timeout is set */
Howard Chu's avatar
Howard Chu committed
228
229
230
231
232
233
234
235

			/* honor network timeout */
			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;
			}
			/* fallthru */
236
237
238
239
240
241
242

		default:
			/* error */
			break;
		}
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
243
244
245
246
	if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
		if ( ld->ld_errno == LDAP_SUCCESS ) {
			ld->ld_errno = LDAP_SERVER_DOWN;
		}
247
248

		ber_free( ber, 1 );
249
250
251
252
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
253
254
255
256
		return( -1 );
	}

	use_connection( ld, lc );
257

Howard Chu's avatar
Howard Chu committed
258
259
260
261
262
263
264
265
266
267
268
269
270
#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP( ld )) {
		BerElement tmpber = *ber;
		ber_rewind( &tmpber );
		rc = ber_write( &tmpber, ld->ld_options.ldo_peer,
			sizeof( struct sockaddr ), 0 );
		if ( rc == -1 ) {
			ld->ld_errno = LDAP_ENCODING_ERROR;
			return rc;
		}
	}
#endif

271
272
273
274
275
	/* 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.
	 */
276
	rc = 0;
277
278
	if ( ld->ld_requests &&
		ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
Pierangelo Masarati's avatar
Pierangelo Masarati committed
279
280
		ldap_int_flush_request( ld, ld->ld_requests ) < 0 )
	{
281
		rc = -1;
282
	}
283
	if ( rc ) return rc;
284

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
285
	lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
286
	if ( lr == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
287
		ld->ld_errno = LDAP_NO_MEMORY;
288
		ldap_free_connection( ld, lc, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
289
		ber_free( ber, 1 );
290
291
292
293
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
294
295
296
297
298
299
300
301
		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 */
302
303
304
305
		if ( !incparent ) { 
			/* Increment if we didn't do it before the bind */
			++parentreq->lr_outrefcnt;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
306
		lr->lr_origid = parentreq->lr_origid;
307
		lr->lr_parentcnt = ++parentreq->lr_parentcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
308
		lr->lr_parent = parentreq;
309
310
		lr->lr_refnext = parentreq->lr_child;
		parentreq->lr_child = lr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
311
312
313
314
	} else {			/* original request */
		lr->lr_origid = lr->lr_msgid;
	}

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
	/* 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
340
	lr->lr_prev = NULL;
341
342
	lr->lr_next = ld->ld_requests;
	if ( lr->lr_next != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
343
344
345
346
		lr->lr_next->lr_prev = lr;
	}
	ld->ld_requests = lr;

347
	ld->ld_errno = LDAP_SUCCESS;
348
	if ( ldap_int_flush_request( ld, lr ) == -1 ) {
349
		msgid = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
350
351
352
353
354
	}

	return( msgid );
}

Howard Chu's avatar
Howard Chu committed
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
/* 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
373
			!strcasecmp( ext, "X-StartTLS" ) ||
Howard Chu's avatar
Howard Chu committed
374
375
376
377
378
379
380
			!strcmp( ext, LDAP_EXOP_START_TLS )) {
			return crit + 1;
		}
	}
	return 0;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
381
LDAPConn *
382
ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
383
	int connect, LDAPreqinfo *bind )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
384
385
{
	LDAPConn	*lc;
386
	int		async = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
387

Pierangelo Masarati's avatar
Pierangelo Masarati committed
388
389
	Debug( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n",
		use_ldsb, connect, (bind != NULL) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
390
391
392
393
	/*
	 * make a new LDAP server connection
	 * XXX open connection synchronously for now
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
394
395
	lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ) );
	if ( lc == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
396
397
398
		ld->ld_errno = LDAP_NO_MEMORY;
		return( NULL );
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
399
400
	
	if ( use_ldsb ) {
401
		assert( ld->ld_sb != NULL );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
402
		lc->lconn_sb = ld->ld_sb;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
403

Pierangelo Masarati's avatar
Pierangelo Masarati committed
404
405
406
407
408
409
410
411
	} 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
412
413

	if ( connect ) {
414
415
		LDAPURLDesc	**srvp, *srv = NULL;

416
417
		async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );

418
		for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) {
419
420
421
422
			int		rc;

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

425
				if ( ld->ld_urllist_proc && ( !async || rc != -2 ) ) {
426
427
428
					ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params );
				}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
429
430
431
432
433
				break;
			}
		}

		if ( srv == NULL ) {
434
435
436
			if ( !use_ldsb ) {
				ber_sockbuf_free( lc->lconn_sb );
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
437
438
439
			LDAP_FREE( (char *)lc );
			ld->ld_errno = LDAP_SERVER_DOWN;
			return( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
440
441
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
442
		lc->lconn_server = ldap_url_dup( srv );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
443
444
	}

445
	lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED;
446
447
448
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
449
450
	lc->lconn_next = ld->ld_conns;
	ld->ld_conns = lc;
451
452
453
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
454

Howard Chu's avatar
Howard Chu committed
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
	if ( lc->lconn_server->lud_exts ) {
#ifdef HAVE_TLS
		if ( connect ) {
			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;

#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
				ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
#endif
				rc = ldap_start_tls_s( ld, NULL, NULL );
#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
				ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
				ld->ld_defconn = savedefconn;
				--lc->lconn_refcnt;

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

488
	if ( bind != NULL ) {
489
		int		err = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
490
491
		LDAPConn	*savedefconn;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
492
493
		/* Set flag to prevent additional referrals
		 * from being processed on this
494
495
496
497
		 * connection until the bind has completed
		 */
		lc->lconn_rebind_inprogress = 1;
		/* V3 rebind function */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
498
		if ( ld->ld_rebind_proc != NULL) {
499
			LDAPURLDesc	*srvfunc;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
500

501
			srvfunc = ldap_url_dup( *srvlist );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
502
			if ( srvfunc == NULL ) {
503
504
				ld->ld_errno = LDAP_NO_MEMORY;
				err = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
505
			} else {
506
507
508
509
				savedefconn = ld->ld_defconn;
				++lc->lconn_refcnt;	/* avoid premature free */
				ld->ld_defconn = lc;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
510
				Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0);
511
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
512
513
				ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
				ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
Julius Enarusai's avatar
   
Julius Enarusai committed
514
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
515
516
				err = (*ld->ld_rebind_proc)( ld,
					bind->ri_url, bind->ri_request, bind->ri_msgid,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
517
					ld->ld_rebind_params );
518
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
519
520
				ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
				ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
521
#endif
522
523
524
525

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
526
527
				if ( err != 0 ) {
					err = -1;
528
529
					ldap_free_connection( ld, lc, 1, 0 );
					lc = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
530
531
				}
				ldap_free_urldesc( srvfunc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
532
			}
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
533

534
		} else {
535
536
537
			int		msgid, rc;
			struct berval	passwd = BER_BVNULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
538
539
			savedefconn = ld->ld_defconn;
			++lc->lconn_refcnt;	/* avoid premature free */
540
			ld->ld_defconn = lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
541

542
543
544
545
			Debug( LDAP_DEBUG_TRACE,
				"anonymous rebind via ldap_sasl_bind(\"\")\n",
				0, 0, 0);

546
547
548
#ifdef LDAP_R_COMPILE
			ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
			ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
Julius Enarusai's avatar
   
Julius Enarusai committed
549
#endif
550
551
552
			rc = ldap_sasl_bind( ld, "", LDAP_SASL_SIMPLE, &passwd,
				NULL, NULL, &msgid );
			if ( rc != LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
553
				err = -1;
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582

			} 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:
583
584
585
586
						Debug( LDAP_DEBUG_TRACE,
							"ldap_new_connection %p: "
							"unexpected response %d "
							"from BIND request id=%d\n",
587
							(void *) ld, ldap_msgtype( res ), msgid );
588
589
						err = -1;
						break;
590
591
					}
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
592
			}
593
594
595
596
#ifdef LDAP_R_COMPILE
			ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
			ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
597
			ld->ld_defconn = savedefconn;
598
			--lc->lconn_refcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
599

Pierangelo Masarati's avatar
Pierangelo Masarati committed
600
601
602
603
			if ( err != 0 ) {
				ldap_free_connection( ld, lc, 1, 0 );
				lc = NULL;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
604
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
605
		if ( lc != NULL )
606
607
			lc->lconn_rebind_inprogress = 0;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
608
609
610
611
612
613

	return( lc );
}


static LDAPConn *
614
find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
615
616
617
618
619
620
/*
 * 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;
621
622
	LDAPURLDesc	*lcu, *lsu;
	int lcu_port, lsu_port;
623
	int found = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
624

625
626
627
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
628
	for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
629
		lcu = lc->lconn_server;
630
631
632
		lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme,
			lcu->lud_port );

633
		for ( lsu = srv; lsu != NULL; lsu = lsu->lud_next ) {
634
635
636
			lsu_port = ldap_pvt_url_scheme_port( lsu->lud_scheme,
				lsu->lud_port );

637
638
			if ( lsu_port == lcu_port
				&& strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0
639
				&& lcu->lud_host != NULL && *lcu->lud_host != '\0'
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
640
				&& lsu->lud_host != NULL && *lsu->lud_host != '\0'
641
				&& strcasecmp( lsu->lud_host, lcu->lud_host ) == 0 )
642
			{
643
644
				found = 1;
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
645
			}
646
647

			if ( !any ) break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
648
		}
649
650
		if ( found )
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
651
	}
652
653
654
655
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
	return lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
656
657
658
659
660
661
662
663
}



static void
use_connection( LDAP *ld, LDAPConn *lc )
{
	++lc->lconn_refcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
664
	lc->lconn_lastused = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
665
666
667
668
}


void
669
ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
670
671
672
{
	LDAPConn	*tmplc, *prevlc;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
673
674
675
	Debug( LDAP_DEBUG_TRACE,
		"ldap_free_connection %d %d\n",
		force, unbind, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
676
677

	if ( force || --lc->lconn_refcnt <= 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
678
		/* remove from connections list first */
679
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
680
		ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
681
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
682
683

		for ( prevlc = NULL, tmplc = ld->ld_conns;
684
685
686
			tmplc != NULL;
			tmplc = tmplc->lconn_next )
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
687
688
689
690
691
692
			if ( tmplc == lc ) {
				if ( prevlc == NULL ) {
				    ld->ld_conns = tmplc->lconn_next;
				} else {
				    prevlc->lconn_next = tmplc->lconn_next;
				}
693
694
695
				if ( ld->ld_defconn == lc ) {
					ld->ld_defconn = NULL;
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
696
697
				break;
			}
698
			prevlc = tmplc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
699
		}
700
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
701
		ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
702
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
703

704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
		/* process connection callbacks */
		{
			struct ldapoptions *lo;
			ldaplist *ll;
			ldap_conncb *cb;

			lo = &ld->ld_options;
			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 );
				}
			}
			lo = LDAP_INT_GLOBAL_OPT();
			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 );
				}
			}
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
726
727
728
729
730
731
732
733
734
735
736
737
738
		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 );
739
740
741
#ifdef HAVE_GSSAPI
		ldap_int_gssapi_close( ld, lc );
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
742

743
		ldap_free_urllist( lc->lconn_server );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
744

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
745
746
747
748
		/* 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
749
750
751
752
753
754
755
756
757
758
759
760
761
		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
762

763
		if ( lc->lconn_sb != ld->ld_sb ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
764
			ber_sockbuf_free( lc->lconn_sb );
765
766
		} else {
			ber_int_sb_close( lc->lconn_sb );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
767
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
768

Pierangelo Masarati's avatar
Pierangelo Masarati committed
769
		if ( lc->lconn_rebind_queue != NULL) {
770
			int i;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
771
772
			for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) {
				LDAP_VFREE( lc->lconn_rebind_queue[i] );
773
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
774
			LDAP_FREE( lc->lconn_rebind_queue );
775
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
776

777
		LDAP_FREE( lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
778

Pierangelo Masarati's avatar
Pierangelo Masarati committed
779
780
781
		Debug( LDAP_DEBUG_TRACE,
			"ldap_free_connection: actually freed\n",
			0, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
782

Kurt Zeilenga's avatar
Kurt Zeilenga committed
783
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
784
		lc->lconn_lastused = time( NULL );
785
		Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
786
				lc->lconn_refcnt, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
787
788
789
790
791
792
	}
}


#ifdef LDAP_DEBUG
void
793
ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
794
795
{
	LDAPConn	*lc;
796
   	char		timebuf[32];
Kurt Zeilenga's avatar
Kurt Zeilenga committed
797

798
	Debug( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "", 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
799
800
	for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
		if ( lc->lconn_server != NULL ) {
801
			Debug( LDAP_DEBUG_TRACE, "* host: %s  port: %d%s\n",
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
802
803
804
805
				( 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
806
		}
807
808
		Debug( LDAP_DEBUG_TRACE, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
			( lc->lconn_status == LDAP_CONNST_NEEDSOCKET )
809
810
811
				? "NeedSocket" :
				( lc->lconn_status == LDAP_CONNST_CONNECTING )
					? "Connecting" : "Connected", 0 );
812
813
814
815
816
817
818
819
820
821
822
823
		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] );
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 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
831
832
833
834
835
836
837
838
		if ( !all ) {
			break;
		}
	}
}


void
839
ldap_dump_requests_and_responses( LDAP *ld )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
840
841
842
{
	LDAPRequest	*lr;
	LDAPMessage	*lm, *l;
843
	int		i;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
844

845
846
	Debug( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n",
		(void *)ld, 0, 0 );
847
848
	lr = ld->ld_requests;
	if ( lr == NULL ) {
849
		Debug( LDAP_DEBUG_TRACE, "   Empty\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
850
	}
851
	for ( i = 0; lr != NULL; lr = lr->lr_next, i++ ) {
852
		Debug( LDAP_DEBUG_TRACE, " * msgid %d,  origid %d, status %s\n",
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
853
854
855
856
857
858
			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"
859
860
861
				: "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
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 );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
866
	if ( ( lm = ld->ld_responses ) == NULL ) {
867
		Debug( LDAP_DEBUG_TRACE, "   Empty\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
868
	}
869
	for ( i = 0; lm != NULL; lm = lm->lm_next, i++ ) {
870
871
		Debug( LDAP_DEBUG_TRACE, " * msgid %d,  type %lu\n",
		    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,
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
876
877
					"  * msgid %d,  type %lu\n",
					l->lm_msgid,
878
					(unsigned long)l->lm_msgtype, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
879
880
881
			}
		}
	}
882
	Debug( LDAP_DEBUG_TRACE, "  ld %p response count %d\n", (void *)ld, i, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
883
884
885
}
#endif /* LDAP_DEBUG */

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
886
static void
887
ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
888
{
889
890
891
892
893
	/* 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
894
	if ( lr->lr_prev == NULL ) {
895
896
897
898
899
900
901
902
		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;
		}
903

Kurt Zeilenga's avatar
Kurt Zeilenga committed
904
905
906
907
908
909
910
911
	} else {
		lr->lr_prev->lr_next = lr->lr_next;
	}

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

912
913
914
915
916
917
918
919
920
	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
921
922
	if ( lr->lr_ber != NULL ) {
		ber_free( lr->lr_ber, 1 );
923
		lr->lr_ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
924
925
926
	}

	if ( lr->lr_res_error != NULL ) {
927
		LDAP_FREE( lr->lr_res_error );
928
		lr->lr_res_error = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
929
930
931
	}

	if ( lr->lr_res_matched != NULL ) {
932
		LDAP_FREE( lr->lr_res_matched );
933
		lr->lr_res_matched = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
934
935
	}

936
	LDAP_FREE( lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
937
938
}

939
940
941
void
ldap_free_request( LDAP *ld, LDAPRequest *lr )
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
942
943
944
#ifdef LDAP_R_COMPILE
	LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
#endif
945
946
947
948

	Debug( LDAP_DEBUG_TRACE, "ldap_free_request (origid %d, msgid %d)\n",
		lr->lr_origid, lr->lr_msgid, 0 );

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
956
		LDAPRequest     **lrp;

957
		--lr->lr_parent->lr_outrefcnt;
958
959
960
961
962
963
964
		for ( lrp = &lr->lr_parent->lr_child;
			*lrp && *lrp != lr;
			lrp = &(*lrp)->lr_refnext );

		if ( *lrp == lr ) {
			*lrp = lr->lr_refnext;
		}
965
966
967
968
	}
	ldap_free_request_int( ld, lr );
}

969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
/*
 * 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;
}
999

1000
1001
1002
1003
1004
1005
1006
1007
/*
 * Chase v3 referrals
 *
 * Parameters:
 *  (IN) ld = LDAP connection handle
 *  (IN) lr = LDAP Request structure
 *  (IN) refs = array of pointers to referral strings that we will chase
 *              The array will be free'd by this function when no longer needed
1008
 *  (IN) sref != 0 if following search reference
1009
1010
1011
1012
1013
 *  (OUT) errstrp = Place to return a string of referrals which could not be followed
 *  (OUT) hadrefp = 1 if sucessfully followed referral
 *
 * Return value - number of referrals followed
 */
1014
int
1015
ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp )
1016
1017
{
	char		*unfollowed;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1018
	int		 unfollowedcnt = 0;
1019
1020
1021
1022
1023
	LDAPRequest	*origreq;
	LDAPURLDesc	*srv = NULL;
	BerElement	*ber;
	char		**refarray = NULL;
	LDAPConn	*lc;
1024
	int			 rc, count, i, j, id;
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
	LDAPreqinfo  rinfo;

	ld->ld_errno = LDAP_SUCCESS;	/* optimistic */
	*hadrefp = 0;

	Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n", 0, 0, 0 );

	unfollowed = NULL;
	rc = count = 0;

	/* If no referrals in array, return */
	if ( (refs == NULL) || ( (refs)[0] == NULL) ) {
		rc = 0;
		goto done;
	}

	/* Check for hop limit exceeded */
	if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
		Debug( LDAP_DEBUG_ANY,
		    "more than %d referral hops (dropping)\n", ld->ld_refhoplimit, 0, 0 );
		ld->ld_errno = LDAP_REFERRAL_LIMIT_EXCEEDED;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1046
		rc = -1;
1047
1048
1049
1050
		goto done;
	}

	/* find original request */
1051
1052
1053
1054
1055
	for ( origreq = lr;
		origreq->lr_parent != NULL;
		origreq = origreq->lr_parent )
	{
		/* empty */ ;
1056
1057
1058
1059
	}

	refarray = refs;
	refs = NULL;
1060
1061
1062
1063
1064

	if ( ld->ld_nextref_proc == NULL ) {
		ld->ld_nextref_proc = ldap_int_nextref;
	}

1065
	/* parse out & follow referrals */
1066
1067
1068
1069
1070
1071
	i = -1;
	for ( ld->ld_nextref_proc( ld, &refarray, &i, ld->ld_nextref_params );
			i != -1;
			ld->ld_nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ) )
	{

1072
		/* Parse the referral URL */
1073
		rc = ldap_url_parse_ext( refarray[i], &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN );
1074
1075
1076
1077
		if ( rc != LDAP_URL_SUCCESS ) {
			/* ldap_url_parse_ext() returns LDAP_URL_* errors
			 * which do not map on API errors */
			ld->ld_errno = LDAP_PARAM_ERROR;
1078
1079
1080
1081
			rc = -1;
			goto done;
		}

1082
		if( srv->lud_crit_exts ) {
Howard Chu's avatar
Howard Chu committed
1083
1084
1085
1086
1087
1088
1089
			int ok = 0;
#ifdef HAVE_TLS
			/* If StartTLS is the only critical ext, OK. */
			if ( find_tls_ext( srv ) == 2 && srv->lud_crit_exts == 1 )
				ok = 1;
#endif
			if ( !ok ) {
Howard Chu's avatar
Howard Chu committed
1090
1091
1092
1093
				/* we do not support any other extensions */
				ld->ld_errno = LDAP_NOT_SUPPORTED;
				rc = -1;
				goto done;
Howard Chu's avatar
Howard Chu committed
1094
			}
1095
1096
		}

1097
1098
		/* check connection for re-bind in progress */
		if (( lc = find_connection( ld, srv, 1 )) != NULL ) {
1099
1100
1101
			/* See if we've already requested this DN with this conn */
			LDAPRequest *lp;
			int looped = 0;
1102
			ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1103
			for ( lp = origreq; lp; ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1104
1105
1106
1107
1108
1109
1110
				if ( lp->lr_conn == lc
					&& len == lp->lr_dn.bv_len
					&& len
					&& strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) == 0 )
				{
					looped = 1;
					break;
1111
				}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1112
				if ( lp == origreq ) {
1113
					lp = lp->lr_child;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1114
				} else {
1115
					lp = lp->lr_refnext;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1116
				}
1117
1118
1119
1120
1121
1122
1123
1124
1125
			}
			if ( looped ) {
				ldap_free_urllist( srv );
				srv = NULL;
				ld->ld_errno = LDAP_CLIENT_LOOP;
				rc = -1;
				continue;
			}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
1126
			if ( lc->lconn_rebind_inprogress ) {
1127
1128
1129
1130
1131
1132
1133
				/* We are already chasing a referral or search reference and a
				 * bind on that connection is in progress.  We must queue
				 * referrals on that connection, so we don't get a request
				 * going out before the bind operation completes. This happens
				 * if two search references come in one behind the other
				 * for the same server with different contexts.
				 */
1134
1135
				Debug( LDAP_DEBUG_TRACE,
					"ldap_chase_v3referrals: queue referral \"%s\"\n",
1136
1137
1138
					refarray[i], 0, 0);
				if( lc->lconn_rebind_queue == NULL ) {
					/* Create a referral list */
1139
					lc->lconn_rebind_queue =
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1140
						(char ***) LDAP_MALLOC( sizeof(void *) * 2);
1141
1142