request.c 36.2 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-2007 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
226
227
228
229
230
231
232
233
234
235
236
	/* 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;

		case -2:
			/* caller will have to call again */
			ld->ld_errno = LDAP_X_CONNECTING;
			/* fallthru */

		default:
			/* error */
			break;
		}
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
237
238
239
240
	if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
		if ( ld->ld_errno == LDAP_SUCCESS ) {
			ld->ld_errno = LDAP_SERVER_DOWN;
		}
241
242

		ber_free( ber, 1 );
243
244
245
246
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
247
248
249
250
		return( -1 );
	}

	use_connection( ld, lc );
251
252
253
254
255
256

	/* 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.
	 */
257
	rc = 0;
258
259
	if ( ld->ld_requests &&
		ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
Pierangelo Masarati's avatar
Pierangelo Masarati committed
260
261
		ldap_int_flush_request( ld, ld->ld_requests ) < 0 )
	{
262
		rc = -1;
263
	}
264
	if ( rc ) return rc;
265

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
266
	lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
267
	if ( lr == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
268
		ld->ld_errno = LDAP_NO_MEMORY;
269
		ldap_free_connection( ld, lc, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
270
		ber_free( ber, 1 );
271
272
273
274
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
275
276
277
278
279
280
281
282
		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 */
283
284
285
286
		if ( !incparent ) { 
			/* Increment if we didn't do it before the bind */
			++parentreq->lr_outrefcnt;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
287
		lr->lr_origid = parentreq->lr_origid;
288
		lr->lr_parentcnt = ++parentreq->lr_parentcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
289
		lr->lr_parent = parentreq;
290
291
		lr->lr_refnext = parentreq->lr_child;
		parentreq->lr_child = lr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
292
293
294
295
	} else {			/* original request */
		lr->lr_origid = lr->lr_msgid;
	}

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
	/* 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
321
	lr->lr_prev = NULL;
322
323
	lr->lr_next = ld->ld_requests;
	if ( lr->lr_next != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
324
325
326
327
		lr->lr_next->lr_prev = lr;
	}
	ld->ld_requests = lr;

328
	ld->ld_errno = LDAP_SUCCESS;
329
	if ( ldap_int_flush_request( ld, lr ) == -1 ) {
330
		msgid = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
331
332
333
334
335
336
	}

	return( msgid );
}

LDAPConn *
337
ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
338
	int connect, LDAPreqinfo *bind )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
339
340
{
	LDAPConn	*lc;
341
	int		async = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
342

Pierangelo Masarati's avatar
Pierangelo Masarati committed
343
344
	Debug( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n",
		use_ldsb, connect, (bind != NULL) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
345
346
347
348
	/*
	 * make a new LDAP server connection
	 * XXX open connection synchronously for now
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
349
350
	lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ) );
	if ( lc == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
351
352
353
		ld->ld_errno = LDAP_NO_MEMORY;
		return( NULL );
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
354
355
	
	if ( use_ldsb ) {
356
		assert( ld->ld_sb != NULL );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
357
		lc->lconn_sb = ld->ld_sb;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
358

Pierangelo Masarati's avatar
Pierangelo Masarati committed
359
360
361
362
363
364
365
366
	} 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
367
368

	if ( connect ) {
369
370
		LDAPURLDesc	**srvp, *srv = NULL;

371
372
		async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );

373
		for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) {
374
			if ( ldap_int_open_connection( ld, lc, *srvp, async) != -1 )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
375
			{
376
377
378
379
380
381
				srv = *srvp;

				if ( ld->ld_urllist_proc ) {
					ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params );
				}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
382
383
384
385
386
				break;
			}
		}

		if ( srv == NULL ) {
387
388
389
			if ( !use_ldsb ) {
				ber_sockbuf_free( lc->lconn_sb );
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
390
391
392
			LDAP_FREE( (char *)lc );
			ld->ld_errno = LDAP_SERVER_DOWN;
			return( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
393
394
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
395
		lc->lconn_server = ldap_url_dup( srv );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
396
397
	}

398
	lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED;
399
400
401
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
402
403
	lc->lconn_next = ld->ld_conns;
	ld->ld_conns = lc;
404
405
406
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
407

408
	if ( bind != NULL ) {
409
		int		err = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
410
411
		LDAPConn	*savedefconn;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
412
413
		/* Set flag to prevent additional referrals
		 * from being processed on this
414
415
416
417
		 * connection until the bind has completed
		 */
		lc->lconn_rebind_inprogress = 1;
		/* V3 rebind function */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
418
		if ( ld->ld_rebind_proc != NULL) {
419
			LDAPURLDesc	*srvfunc;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
420

421
			srvfunc = ldap_url_dup( *srvlist );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
422
			if ( srvfunc == NULL ) {
423
424
				ld->ld_errno = LDAP_NO_MEMORY;
				err = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
425
			} else {
426
427
428
429
				savedefconn = ld->ld_defconn;
				++lc->lconn_refcnt;	/* avoid premature free */
				ld->ld_defconn = lc;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
430
				Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0);
431
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
432
433
				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
434
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
435
436
				err = (*ld->ld_rebind_proc)( ld,
					bind->ri_url, bind->ri_request, bind->ri_msgid,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
437
					ld->ld_rebind_params );
438
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
439
440
				ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
				ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
441
#endif
442
443
444
445

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
446
447
				if ( err != 0 ) {
					err = -1;
448
449
					ldap_free_connection( ld, lc, 1, 0 );
					lc = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
450
451
				}
				ldap_free_urldesc( srvfunc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
452
			}
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
453

454
		} else {
455
456
457
			int		msgid, rc;
			struct berval	passwd = BER_BVNULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
458
459
			savedefconn = ld->ld_defconn;
			++lc->lconn_refcnt;	/* avoid premature free */
460
			ld->ld_defconn = lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
461

462
			Debug( LDAP_DEBUG_TRACE, "anonymous rebind via ldap_bind_s\n", 0, 0, 0);
463
464
465
#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
466
#endif
467
468
469
			rc = ldap_sasl_bind( ld, "", LDAP_SASL_SIMPLE, &passwd,
				NULL, NULL, &msgid );
			if ( rc != LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
470
				err = -1;
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502

			} 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:
						assert( 0 );
					}
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
503
			}
504
505
506
507
#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
508
			ld->ld_defconn = savedefconn;
509
			--lc->lconn_refcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
510

Pierangelo Masarati's avatar
Pierangelo Masarati committed
511
512
513
514
			if ( err != 0 ) {
				ldap_free_connection( ld, lc, 1, 0 );
				lc = NULL;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
515
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
516
		if ( lc != NULL )
517
518
			lc->lconn_rebind_inprogress = 0;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
519
520
521
522
523
524

	return( lc );
}


static LDAPConn *
525
find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
526
527
528
529
530
531
/*
 * 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;
532
533
	LDAPURLDesc	*lcu, *lsu;
	int lcu_port, lsu_port;
534
	int found = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
535

536
537
538
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
539
	for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
540
		lcu = lc->lconn_server;
541
542
543
		lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme,
			lcu->lud_port );

544
		for ( lsu = srv; lsu != NULL; lsu = lsu->lud_next ) {
545
546
547
			lsu_port = ldap_pvt_url_scheme_port( lsu->lud_scheme,
				lsu->lud_port );

548
549
			if ( lsu_port == lcu_port
				&& strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0
550
				&& lcu->lud_host != NULL && *lcu->lud_host != '\0'
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
551
				&& lsu->lud_host != NULL && *lsu->lud_host != '\0'
552
				&& strcasecmp( lsu->lud_host, lcu->lud_host ) == 0 )
553
			{
554
555
				found = 1;
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
			}
557
558

			if ( !any ) break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
559
		}
560
561
		if ( found )
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
562
	}
563
564
565
566
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
	return lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
567
568
569
570
571
572
573
574
}



static void
use_connection( LDAP *ld, LDAPConn *lc )
{
	++lc->lconn_refcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
575
	lc->lconn_lastused = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
576
577
578
579
}


void
580
ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
581
582
583
{
	LDAPConn	*tmplc, *prevlc;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
584
585
586
	Debug( LDAP_DEBUG_TRACE,
		"ldap_free_connection %d %d\n",
		force, unbind, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
587
588

	if ( force || --lc->lconn_refcnt <= 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
589
		/* remove from connections list first */
590
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
591
		ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
592
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
593
594

		for ( prevlc = NULL, tmplc = ld->ld_conns;
595
596
597
			tmplc != NULL;
			tmplc = tmplc->lconn_next )
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
598
599
600
601
602
603
604
605
			if ( tmplc == lc ) {
				if ( prevlc == NULL ) {
				    ld->ld_conns = tmplc->lconn_next;
				} else {
				    prevlc->lconn_next = tmplc->lconn_next;
				}
				break;
			}
606
			prevlc = tmplc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
607
		}
608
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
609
		ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
610
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625

		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 );

626
		ldap_free_urllist( lc->lconn_server );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
627
#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
Kurt Zeilenga's avatar
Kurt Zeilenga committed
628
		if ( lc->lconn_krbinstance != NULL ) {
629
			LDAP_FREE( lc->lconn_krbinstance );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
630
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
631
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
632

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
633
634
635
636
		/* 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
637
638
639
640
641
642
643
644
645
646
647
648
649
		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
650

651
		if ( lc->lconn_sb != ld->ld_sb ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
652
			ber_sockbuf_free( lc->lconn_sb );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
653
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
654

Pierangelo Masarati's avatar
Pierangelo Masarati committed
655
		if ( lc->lconn_rebind_queue != NULL) {
656
			int i;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
657
658
			for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) {
				LDAP_VFREE( lc->lconn_rebind_queue[i] );
659
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
660
			LDAP_FREE( lc->lconn_rebind_queue );
661
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
662

663
		LDAP_FREE( lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
664

Pierangelo Masarati's avatar
Pierangelo Masarati committed
665
666
667
		Debug( LDAP_DEBUG_TRACE,
			"ldap_free_connection: actually freed\n",
			0, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
668

Kurt Zeilenga's avatar
Kurt Zeilenga committed
669
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
670
		lc->lconn_lastused = time( NULL );
671
		Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
672
				lc->lconn_refcnt, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
673
674
675
676
677
678
	}
}


#ifdef LDAP_DEBUG
void
679
ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
680
681
{
	LDAPConn	*lc;
682
   	char		timebuf[32];
Kurt Zeilenga's avatar
Kurt Zeilenga committed
683

684
	Debug( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "", 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
685
686
	for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
		if ( lc->lconn_server != NULL ) {
687
			Debug( LDAP_DEBUG_TRACE, "* host: %s  port: %d%s\n",
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
688
689
690
691
				( 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
692
		}
693
694
		Debug( LDAP_DEBUG_TRACE, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
			( lc->lconn_status == LDAP_CONNST_NEEDSOCKET )
695
696
697
				? "NeedSocket" :
				( lc->lconn_status == LDAP_CONNST_CONNECTING )
					? "Connecting" : "Connected", 0 );
698
699
700
701
702
703
704
705
706
707
708
709
		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] );
710
711
712
					}
				}
			} else {
713
				Debug( LDAP_DEBUG_TRACE, "    queue is empty\n", 0, 0, 0 );
714
715
			}
		}
716
		Debug( LDAP_DEBUG_TRACE, "\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
717
718
719
720
721
722
723
724
		if ( !all ) {
			break;
		}
	}
}


void
725
ldap_dump_requests_and_responses( LDAP *ld )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
726
727
728
{
	LDAPRequest	*lr;
	LDAPMessage	*lm, *l;
729
	int		i;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
730

731
732
	Debug( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n",
		(void *)ld, 0, 0 );
733
734
	lr = ld->ld_requests;
	if ( lr == NULL ) {
735
		Debug( LDAP_DEBUG_TRACE, "   Empty\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
736
	}
737
	for ( i = 0; lr != NULL; lr = lr->lr_next, i++ ) {
738
		Debug( LDAP_DEBUG_TRACE, " * msgid %d,  origid %d, status %s\n",
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
739
740
741
742
743
744
			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"
745
746
747
				: "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
748
	}
749
	Debug( LDAP_DEBUG_TRACE, "  ld %p request count %d (abandoned %lu)\n",
750
		(void *)ld, i, ld->ld_nabandoned );
751
	Debug( LDAP_DEBUG_TRACE, "** ld %p Response Queue:\n", (void *)ld, 0, 0 );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
752
	if ( ( lm = ld->ld_responses ) == NULL ) {
753
		Debug( LDAP_DEBUG_TRACE, "   Empty\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
754
	}
755
	for ( i = 0; lm != NULL; lm = lm->lm_next, i++ ) {
756
757
		Debug( LDAP_DEBUG_TRACE, " * msgid %d,  type %lu\n",
		    lm->lm_msgid, (unsigned long)lm->lm_msgtype, 0 );
758
		if ( lm->lm_chain != NULL ) {
759
			Debug( LDAP_DEBUG_TRACE, "   chained responses:\n", 0, 0, 0 );
760
			for ( l = lm->lm_chain; l != NULL; l = l->lm_chain ) {
761
				Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
762
763
					"  * msgid %d,  type %lu\n",
					l->lm_msgid,
764
					(unsigned long)l->lm_msgtype, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
765
766
767
			}
		}
	}
768
	Debug( LDAP_DEBUG_TRACE, "  ld %p response count %d\n", (void *)ld, i, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
769
770
771
}
#endif /* LDAP_DEBUG */

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
772
static void
773
ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
774
{
775
776
777
778
779
	/* 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
780
	if ( lr->lr_prev == NULL ) {
781
782
783
784
785
786
787
788
		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;
		}
789

Kurt Zeilenga's avatar
Kurt Zeilenga committed
790
791
792
793
794
795
796
797
	} else {
		lr->lr_prev->lr_next = lr->lr_next;
	}

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

798
799
800
801
802
803
804
805
806
	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
807
808
	if ( lr->lr_ber != NULL ) {
		ber_free( lr->lr_ber, 1 );
809
		lr->lr_ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
810
811
812
	}

	if ( lr->lr_res_error != NULL ) {
813
		LDAP_FREE( lr->lr_res_error );
814
		lr->lr_res_error = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
815
816
817
	}

	if ( lr->lr_res_matched != NULL ) {
818
		LDAP_FREE( lr->lr_res_matched );
819
		lr->lr_res_matched = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
820
821
	}

822
	LDAP_FREE( lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
823
824
}

825
826
827
void
ldap_free_request( LDAP *ld, LDAPRequest *lr )
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
828
829
830
#ifdef LDAP_R_COMPILE
	LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
#endif
831
832
833
834

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

835
	/* free all referrals (child requests) */
836
	while ( lr->lr_child ) {
837
		ldap_free_request( ld, lr->lr_child );
838
	}
839

840
	if ( lr->lr_parent != NULL ) {
841
842
		LDAPRequest     **lrp;

843
		--lr->lr_parent->lr_outrefcnt;
844
845
846
847
848
849
850
		for ( lrp = &lr->lr_parent->lr_child;
			*lrp && *lrp != lr;
			lrp = &(*lrp)->lr_refnext );

		if ( *lrp == lr ) {
			*lrp = lr->lr_refnext;
		}
851
852
853
854
	}
	ldap_free_request_int( ld, lr );
}

855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
/*
 * 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;
}
885

886
887
888
889
890
891
892
893
/*
 * 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
894
 *  (IN) sref != 0 if following search reference
895
896
897
898
899
 *  (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
 */
900
int
901
ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp )
902
903
{
	char		*unfollowed;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
904
	int		 unfollowedcnt = 0;
905
906
907
908
909
	LDAPRequest	*origreq;
	LDAPURLDesc	*srv = NULL;
	BerElement	*ber;
	char		**refarray = NULL;
	LDAPConn	*lc;
910
	int			 rc, count, i, j, id;
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
	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
932
		rc = -1;
933
934
935
936
		goto done;
	}

	/* find original request */
937
938
939
940
941
	for ( origreq = lr;
		origreq->lr_parent != NULL;
		origreq = origreq->lr_parent )
	{
		/* empty */ ;
942
943
944
945
	}

	refarray = refs;
	refs = NULL;
946
947
948
949
950

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

951
	/* parse out & follow referrals */
952
953
954
955
956
957
	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 ) )
	{

958
		/* Parse the referral URL */
959
		rc = ldap_url_parse_ext( refarray[i], &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN );
960
961
962
963
		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;
964
965
966
967
			rc = -1;
			goto done;
		}

968
969
970
971
972
973
974
		if( srv->lud_crit_exts ) {
			/* we do not support any extensions */
			ld->ld_errno = LDAP_NOT_SUPPORTED;
			rc = -1;
			goto done;
		}

975
976
		/* check connection for re-bind in progress */
		if (( lc = find_connection( ld, srv, 1 )) != NULL ) {
977
978
979
980
			/* See if we've already requested this DN with this conn */
			LDAPRequest *lp;
			int looped = 0;
			int len = srv->lud_dn ? strlen( srv->lud_dn ) : 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
981
			for ( lp = origreq; lp; ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
982
983
984
985
986
987
988
				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;
989
				}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
990
				if ( lp == origreq ) {
991
					lp = lp->lr_child;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
992
				} else {
993
					lp = lr->lr_refnext;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
994
				}
995
996
997
998
999
1000
			}
			if ( looped ) {
				ldap_free_urllist( srv );
				srv = NULL;
				ld->ld_errno = LDAP_CLIENT_LOOP;
				rc = -1;
For faster browsing, not all history is shown. View entire blame