request.c 36.3 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
	/* 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;

226
227
228
229
230
231
232
233
234
235
236
237
		case -2: {
			/* async only occurs if a network timeout is set */
				struct timeval *tvp = ld->ld_options.ldo_tm_net;
				assert( tvp != NULL );

				/* honor network timeout */
				if ( time( NULL ) - lc->lconn_created <= tvp->tv_sec )
				{
					/* caller will have to call again */
					ld->ld_errno = LDAP_X_CONNECTING;
				}
			} /* fallthru */
238
239
240
241
242
243
244

		default:
			/* error */
			break;
		}
	}

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

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

	use_connection( ld, lc );
259
260
261
262
263
264

	/* 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.
	 */
265
	rc = 0;
266
267
	if ( ld->ld_requests &&
		ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
Pierangelo Masarati's avatar
Pierangelo Masarati committed
268
269
		ldap_int_flush_request( ld, ld->ld_requests ) < 0 )
	{
270
		rc = -1;
271
	}
272
	if ( rc ) return rc;
273

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

304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
	/* 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
329
	lr->lr_prev = NULL;
330
331
	lr->lr_next = ld->ld_requests;
	if ( lr->lr_next != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
332
333
334
335
		lr->lr_next->lr_prev = lr;
	}
	ld->ld_requests = lr;

336
	ld->ld_errno = LDAP_SUCCESS;
337
	if ( ldap_int_flush_request( ld, lr ) == -1 ) {
338
		msgid = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
339
340
341
342
343
344
	}

	return( msgid );
}

LDAPConn *
345
ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
346
	int connect, LDAPreqinfo *bind )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
347
348
{
	LDAPConn	*lc;
349
	int		async = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
350

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
367
368
369
370
371
372
373
374
	} 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
375
376

	if ( connect ) {
377
378
		LDAPURLDesc	**srvp, *srv = NULL;

379
380
		async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );

381
		for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) {
382
			if ( ldap_int_open_connection( ld, lc, *srvp, async) != -1 )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
383
			{
384
385
386
387
388
389
				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
390
391
392
393
394
				break;
			}
		}

		if ( srv == NULL ) {
395
396
397
			if ( !use_ldsb ) {
				ber_sockbuf_free( lc->lconn_sb );
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
398
399
400
			LDAP_FREE( (char *)lc );
			ld->ld_errno = LDAP_SERVER_DOWN;
			return( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
401
402
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
403
		lc->lconn_server = ldap_url_dup( srv );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
404
405
	}

406
	lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED;
407
408
409
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
410
411
	lc->lconn_next = ld->ld_conns;
	ld->ld_conns = lc;
412
413
414
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
415

416
	if ( bind != NULL ) {
417
		int		err = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
418
419
		LDAPConn	*savedefconn;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
420
421
		/* Set flag to prevent additional referrals
		 * from being processed on this
422
423
424
425
		 * connection until the bind has completed
		 */
		lc->lconn_rebind_inprogress = 1;
		/* V3 rebind function */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
426
		if ( ld->ld_rebind_proc != NULL) {
427
			LDAPURLDesc	*srvfunc;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
428

429
			srvfunc = ldap_url_dup( *srvlist );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
430
			if ( srvfunc == NULL ) {
431
432
				ld->ld_errno = LDAP_NO_MEMORY;
				err = -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
433
			} else {
434
435
436
437
				savedefconn = ld->ld_defconn;
				++lc->lconn_refcnt;	/* avoid premature free */
				ld->ld_defconn = lc;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
438
				Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0);
439
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
440
441
				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
442
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
443
444
				err = (*ld->ld_rebind_proc)( ld,
					bind->ri_url, bind->ri_request, bind->ri_msgid,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
445
					ld->ld_rebind_params );
446
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
447
448
				ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
				ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
449
#endif
450
451
452
453

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
454
455
				if ( err != 0 ) {
					err = -1;
456
457
					ldap_free_connection( ld, lc, 1, 0 );
					lc = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
458
459
				}
				ldap_free_urldesc( srvfunc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
460
			}
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
461

462
		} else {
463
464
465
			int		msgid, rc;
			struct berval	passwd = BER_BVNULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
466
467
			savedefconn = ld->ld_defconn;
			++lc->lconn_refcnt;	/* avoid premature free */
468
			ld->ld_defconn = lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
469

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

			} 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
511
			}
512
513
514
515
#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
516
			ld->ld_defconn = savedefconn;
517
			--lc->lconn_refcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
518

Pierangelo Masarati's avatar
Pierangelo Masarati committed
519
520
521
522
			if ( err != 0 ) {
				ldap_free_connection( ld, lc, 1, 0 );
				lc = NULL;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
523
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
524
		if ( lc != NULL )
525
526
			lc->lconn_rebind_inprogress = 0;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
527
528
529
530
531
532

	return( lc );
}


static LDAPConn *
533
find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
534
535
536
537
538
539
/*
 * 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;
540
541
	LDAPURLDesc	*lcu, *lsu;
	int lcu_port, lsu_port;
542
	int found = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
543

544
545
546
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
547
	for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
548
		lcu = lc->lconn_server;
549
550
551
		lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme,
			lcu->lud_port );

552
		for ( lsu = srv; lsu != NULL; lsu = lsu->lud_next ) {
553
554
555
			lsu_port = ldap_pvt_url_scheme_port( lsu->lud_scheme,
				lsu->lud_port );

556
557
			if ( lsu_port == lcu_port
				&& strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0
558
				&& lcu->lud_host != NULL && *lcu->lud_host != '\0'
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
559
				&& lsu->lud_host != NULL && *lsu->lud_host != '\0'
560
				&& strcasecmp( lsu->lud_host, lcu->lud_host ) == 0 )
561
			{
562
563
				found = 1;
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
564
			}
565
566

			if ( !any ) break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
567
		}
568
569
		if ( found )
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
570
	}
571
572
573
574
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
	return lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
575
576
577
578
579
580
581
582
}



static void
use_connection( LDAP *ld, LDAPConn *lc )
{
	++lc->lconn_refcnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
583
	lc->lconn_lastused = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
584
585
586
587
}


void
588
ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
589
590
591
{
	LDAPConn	*tmplc, *prevlc;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
592
593
594
	Debug( LDAP_DEBUG_TRACE,
		"ldap_free_connection %d %d\n",
		force, unbind, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
595
596

	if ( force || --lc->lconn_refcnt <= 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
597
		/* remove from connections list first */
598
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
599
		ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
600
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
601
602

		for ( prevlc = NULL, tmplc = ld->ld_conns;
603
604
605
			tmplc != NULL;
			tmplc = tmplc->lconn_next )
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
606
607
608
609
610
611
612
613
			if ( tmplc == lc ) {
				if ( prevlc == NULL ) {
				    ld->ld_conns = tmplc->lconn_next;
				} else {
				    prevlc->lconn_next = tmplc->lconn_next;
				}
				break;
			}
614
			prevlc = tmplc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
615
		}
616
#ifdef LDAP_R_COMPILE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
617
		ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
618
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633

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

634
		ldap_free_urllist( lc->lconn_server );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
635

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

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

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

666
		LDAP_FREE( lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
667

Pierangelo Masarati's avatar
Pierangelo Masarati committed
668
669
670
		Debug( LDAP_DEBUG_TRACE,
			"ldap_free_connection: actually freed\n",
			0, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
671

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


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

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


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

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
793
794
795
796
797
798
799
800
	} else {
		lr->lr_prev->lr_next = lr->lr_next;
	}

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

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

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

	if ( lr->lr_res_matched != NULL ) {
821
		LDAP_FREE( lr->lr_res_matched );
822
		lr->lr_res_matched = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
823
824
	}

825
	LDAP_FREE( lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
826
827
}

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

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

838
	/* free all referrals (child requests) */
839
	while ( lr->lr_child ) {
840
		ldap_free_request( ld, lr->lr_child );
841
	}
842

843
	if ( lr->lr_parent != NULL ) {
844
845
		LDAPRequest     **lrp;

846
		--lr->lr_parent->lr_outrefcnt;
847
848
849
850
851
852
853
		for ( lrp = &lr->lr_parent->lr_child;
			*lrp && *lrp != lr;
			lrp = &(*lrp)->lr_refnext );

		if ( *lrp == lr ) {
			*lrp = lr->lr_refnext;
		}
854
855
856
857
	}
	ldap_free_request_int( ld, lr );
}

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
885
886
887
/*
 * 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;
}
888

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

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

	refarray = refs;
	refs = NULL;
949
950
951
952
953

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

954
	/* parse out & follow referrals */
955
956
957
958
959
960
	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 ) )
	{

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

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

978
979
		/* check connection for re-bind in progress */
		if (( lc = find_connection( ld, srv, 1 )) != NULL ) {
980
981
982
983
			/* 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
984
			for ( lp = origreq; lp; ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
985
986
987
988
989
990
991
				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;
992
				}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
993
				if ( lp == origreq ) {
994
					lp = lp->lr_child;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
995
				} else {
996
					lp = lr->lr_refnext;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
997
				}
998
999
1000
			}
			if ( looped ) {
				ldap_free_urllist( srv );
For faster browsing, not all history is shown. View entire blame