result.c 35.4 KB
Newer Older
1
/* result.c - wait for an ldap result */
2
/* $OpenLDAP$ */
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 1998-2010 The OpenLDAP Foundation.
6
7
8
9
10
11
12
13
14
 * 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
15
 */
16
17
/* Portions Copyright (c) 1990 Regents of the University of Michigan.
 * All rights reserved.
18
 */
19
/* This notice applies to changes, created by or for Novell, Inc.,
20
21
22
23
24
25
26
27
28
29
30
31
 * 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. 
32
 *---
33
34
 * Modification to OpenLDAP source by Novell, Inc.
 * April 2000 sfs Add code to process V3 referrals and search results
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
/*
42
 * LDAPv3 (RFC 4511)
43
 *	LDAPResult ::= SEQUENCE {
44
45
 *		resultCode			ENUMERATED { ... },
 *		matchedDN			LDAPDN,
46
 *		diagnosticMessage		LDAPString,
47
 *		referral			[3] Referral OPTIONAL
48
49
 *	}
 *	Referral ::= SEQUENCE OF LDAPURL	(one or more)
50
 *	LDAPURL ::= LDAPString			(limited to URL chars)
51
52
 */

53
54
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
55
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
56
57

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

59
60
61
62
63
#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
64

Kurt Zeilenga's avatar
Kurt Zeilenga committed
65
#include "ldap-int.h"
Julius Enarusai's avatar
   
Julius Enarusai committed
66
#include "ldap_log.h"
67
#include "lutil.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
68

69
70
static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int *idx ));
static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int idx ));
71
static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout,
72
	LDAPMessage **result ));
73
static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
74
	int all, LDAPConn *lc, LDAPMessage **result ));
75
static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr ));
76
static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));
77
static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
78

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
79
80
#define LDAP_MSG_X_KEEP_LOOKING		(-2)

Kurt Zeilenga's avatar
Kurt Zeilenga committed
81
82
83

/*
 * ldap_result - wait for an ldap result response to a message from the
84
85
86
87
88
89
 * ldap server.  If msgid is LDAP_RES_ANY (-1), any message will be
 * accepted.  If msgid is LDAP_RES_UNSOLICITED (0), any unsolicited
 * message is accepted.  Otherwise ldap_result will wait for a response
 * with msgid.  If all is LDAP_MSG_ONE (0) the first message with id
 * msgid will be accepted, otherwise, ldap_result will wait for all
 * responses with id msgid and then return a pointer to the entire list
90
91
92
93
94
 * of messages.  In general, this is only useful for search responses,
 * which can be of three message types (zero or more entries, zero or
 * search references, followed by an ldap result).  An extension to
 * LDAPv3 allows partial extended responses to be returned in response
 * to any request.  The type of the first message received is returned.
95
96
 * When waiting, any messages that have been abandoned/discarded are 
 * discarded.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
97
98
99
100
101
 *
 * Example:
 *	ldap_result( s, msgid, all, timeout, result )
 */
int
102
103
104
105
106
ldap_result(
	LDAP *ld,
	int msgid,
	int all,
	struct timeval *timeout,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
107
108
	LDAPMessage **result )
{
109
	int		rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
110

Kurt Zeilenga's avatar
Kurt Zeilenga committed
111
112
113
	assert( ld != NULL );
	assert( result != NULL );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
114
	Debug( LDAP_DEBUG_TRACE, "ldap_result ld %p msgid %d\n", (void *)ld, msgid, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
115

116
117
118
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
#endif
119

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
120
	rc = wait4msg( ld, msgid, all, timeout, result );
121

122
123
124
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
#endif
125
126

	return rc;
127
128
129
}

static LDAPMessage *
130
131
132
133
chkResponseList(
	LDAP *ld,
	int msgid,
	int all)
134
{
135
	LDAPMessage	*lm, **lastlm, *nextlm;
136
	int		cnt = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
137
138

	/*
139
	 * Look through the list of responses we have received on
Kurt Zeilenga's avatar
Kurt Zeilenga committed
140
141
142
143
144
	 * this association and see if the response we're interested in
	 * is there.  If it is, return it.  If not, call wait4msg() to
	 * wait until it arrives or timeout occurs.
	 */

Pierangelo Masarati's avatar
Pierangelo Masarati committed
145
146
147
148
#ifdef LDAP_R_COMPILE
	LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
#endif

149
	Debug( LDAP_DEBUG_TRACE,
150
		"ldap_chkResponseList ld %p msgid %d all %d\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
151
		(void *)ld, msgid, all );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
152

153
	lastlm = &ld->ld_responses;
154
	for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
155
156
		int	idx;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
157
		nextlm = lm->lm_next;
158
		++cnt;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
159

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
		if ( ldap_abandoned( ld, lm->lm_msgid, &idx ) ) {
			Debug( LDAP_DEBUG_ANY,
				"response list msg abandoned, "
				"msgid %d message type %s\n",
				lm->lm_msgid, ldap_int_msgtype2str( lm->lm_msgtype ), 0 );

			switch ( lm->lm_msgtype ) {
			case LDAP_RES_SEARCH_ENTRY:
			case LDAP_RES_SEARCH_REFERENCE:
			case LDAP_RES_INTERMEDIATE:
				break;

			default:
				/* there's no need to keep the id
				 * in the abandoned list any longer */
				ldap_mark_abandoned( ld, lm->lm_msgid, idx );
				break;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
178

179
180
			/* Remove this entry from list */
			*lastlm = nextlm;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
181
182
183
184
185
186
187
188
189

			ldap_msgfree( lm );

			continue;
		}

		if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
			LDAPMessage	*tmp;

190
191
			if ( all == LDAP_MSG_ONE ||
				all == LDAP_MSG_RECEIVED ||
192
193
				msgid == LDAP_RES_UNSOLICITED )
			{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
194
				break;
195
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
196

197
			tmp = lm->lm_chain_tail;
198
199
200
			if ( tmp->lm_msgtype == LDAP_RES_SEARCH_ENTRY ||
				tmp->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ||
				tmp->lm_msgtype == LDAP_RES_INTERMEDIATE )
201
			{
202
				tmp = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
203
204
			}

205
			if ( tmp == NULL ) {
206
				lm = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
207
208
209
210
			}

			break;
		}
211
		lastlm = &lm->lm_next;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
212
	}
213

214
	if ( lm != NULL ) {
215
		/* Found an entry, remove it from the list */
216
		if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) {
217
			*lastlm = lm->lm_chain;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
218
219
220
221
			lm->lm_chain->lm_next = lm->lm_next;
			lm->lm_chain->lm_chain_tail = ( lm->lm_chain_tail != lm ) ? lm->lm_chain_tail : lm->lm_chain;
			lm->lm_chain = NULL;
			lm->lm_chain_tail = NULL;
222
		} else {
223
224
			*lastlm = lm->lm_next;
		}
225
226
		lm->lm_next = NULL;
	}
227
228

#ifdef LDAP_DEBUG
229
	if ( lm == NULL) {
230
		Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
231
			"ldap_chkResponseList returns ld %p NULL\n", (void *)ld, 0, 0);
232
	} else {
233
		Debug( LDAP_DEBUG_TRACE,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
234
			"ldap_chkResponseList returns ld %p msgid %d, type 0x%02lx\n",
235
			(void *)ld, lm->lm_msgid, (unsigned long)lm->lm_msgtype );
236
237
	}
#endif
238
239

	return lm;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
240
}
241

Kurt Zeilenga's avatar
Kurt Zeilenga committed
242
static int
243
244
245
246
247
wait4msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
	struct timeval *timeout,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
248
249
250
	LDAPMessage **result )
{
	int		rc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
251
252
	struct timeval	tv = { 0 },
			tv0 = { 0 },
253
254
			start_time_tv = { 0 },
			*tvp = NULL;
255
	LDAPConn	*lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
256

Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
258
259
	assert( ld != NULL );
	assert( result != NULL );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
260
261
262
263
#ifdef LDAP_R_COMPILE
	LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
#endif

Howard Chu's avatar
Howard Chu committed
264
265
266
	if ( timeout == NULL && ld->ld_options.ldo_tm_api.tv_sec >= 0 ) {
		tv = ld->ld_options.ldo_tm_api;
		timeout = &tv;
267
268
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
269
270
#ifdef LDAP_DEBUG
	if ( timeout == NULL ) {
271
		Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (infinite timeout)\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
272
			(void *)ld, msgid, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
273
	} else {
274
		Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (timeout %ld usec)\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
275
			(void *)ld, msgid, (long)timeout->tv_sec * 1000000 + timeout->tv_usec );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
276
277
278
	}
#endif /* LDAP_DEBUG */

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
279
	if ( timeout != NULL && timeout->tv_sec != -1 ) {
280
		tv0 = *timeout;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
281
282
		tv = *timeout;
		tvp = &tv;
283
284
285
286
287
288
#ifdef HAVE_GETTIMEOFDAY
		gettimeofday( &start_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
		time( &start_time_tv.tv_sec );
		start_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
289
290
	}
		    
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
291
292
	rc = LDAP_MSG_X_KEEP_LOOKING;
	while ( rc == LDAP_MSG_X_KEEP_LOOKING ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
293
294
#ifdef LDAP_DEBUG
		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
295
			Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
296
				(void *)ld, msgid, all );
297
298
299
#ifdef LDAP_R_COMPILE
			ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
300
			ldap_dump_connection( ld, ld->ld_conns, 1 );
301
302
303
304
#ifdef LDAP_R_COMPILE
			ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
			ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
305
			ldap_dump_requests_and_responses( ld );
306
307
308
#ifdef LDAP_R_COMPILE
			ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
309
310
311
		}
#endif /* LDAP_DEBUG */

Quanah Gibson-Mount's avatar
cleanup    
Quanah Gibson-Mount committed
312
		if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) {
313
314
315
			rc = (*result)->lm_msgtype;

		} else {
316
			int lc_ready = 0;
317

318
319
320
#ifdef LDAP_R_COMPILE
			ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
321
			for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
322
				if ( ber_sockbuf_ctrl( lc->lconn_sb,
323
					LBER_SB_OPT_DATA_READY, NULL ) )
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
324
				{
325
					lc_ready = 1;
326
					break;
327
				}
328
329
330
331
			}
#ifdef LDAP_R_COMPILE
			ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
332

Quanah Gibson-Mount's avatar
cleanup    
Quanah Gibson-Mount committed
333
			if ( !lc_ready ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
334
				int err;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
335
336
				rc = ldap_int_select( ld, tvp );
				if ( rc == -1 ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
337
338
					err = sock_errno();
#ifdef LDAP_DEBUG
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
339
340
					Debug( LDAP_DEBUG_TRACE,
						"ldap_int_select returned -1: errno %d\n",
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
341
						err, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
342
#endif
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
343
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
344

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
345
346
				if ( rc == 0 || ( rc == -1 && (
					!LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
347
						|| err != EINTR ) ) )
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
348
349
350
351
352
353
354
				{
					ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
						LDAP_TIMEOUT);
					return( rc );
				}

				if ( rc == -1 ) {
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
355
					rc = LDAP_MSG_X_KEEP_LOOKING;	/* select interrupted: loop */
356

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
357
				} else {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
358
359
360
361
362
363
					lc_ready = 1;
				}
			}
			if ( lc_ready ) {
				LDAPConn *lnext;
				rc = LDAP_MSG_X_KEEP_LOOKING;
364
#ifdef LDAP_R_COMPILE
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
365
				ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
366
#endif
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
367
368
369
370
371
372
373
				if ( ld->ld_requests &&
					ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
					ldap_is_write_ready( ld,
						ld->ld_requests->lr_conn->lconn_sb ) )
				{
					ldap_int_flush_request( ld, ld->ld_requests );
				}
374
#ifdef LDAP_R_COMPILE
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
375
376
				ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
				ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
377
#endif
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
378
379
380
381
382
383
				for ( lc = ld->ld_conns;
					rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL;
					lc = lnext )
				{
					if ( lc->lconn_status == LDAP_CONNST_CONNECTED &&
						ldap_is_read_ready( ld, lc->lconn_sb ) )
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
384
					{
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
385
386
387
388
389
390
391
392
393
394
						/* Don't let it get freed out from under us */
						++lc->lconn_refcnt;
#ifdef LDAP_R_COMPILE
						ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
						rc = try_read1msg( ld, msgid, all, lc, result );
						lnext = lc->lconn_next;

						/* Only take locks if we're really freeing */
						if ( lc->lconn_refcnt <= 1 ) {
395
#ifdef LDAP_R_COMPILE
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
396
							ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
397
#endif
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
398
							ldap_free_connection( ld, lc, 0, 1 );
399
#ifdef LDAP_R_COMPILE
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
400
							ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
401
#endif
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
402
403
						} else {
							--lc->lconn_refcnt;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
404
						}
405
#ifdef LDAP_R_COMPILE
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
406
						ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
407
#endif
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
408
409
410
					} else {
						lnext = lc->lconn_next;
					}
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
411
				}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
412
413
414
#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
415
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
416
417
		}

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
418
		if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) {
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
			struct timeval	curr_time_tv = { 0 },
					delta_time_tv = { 0 };

#ifdef HAVE_GETTIMEOFDAY
			gettimeofday( &curr_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
			time( &curr_time_tv.tv_sec );
			curr_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */

			/* delta_time = tmp_time - start_time */
			delta_time_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec;
			delta_time_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec;
			if ( delta_time_tv.tv_usec < 0 ) {
				delta_time_tv.tv_sec--;
				delta_time_tv.tv_usec += 1000000;
			}

			/* tv0 < delta_time ? */
			if ( ( tv0.tv_sec < delta_time_tv.tv_sec ) ||
			     ( ( tv0.tv_sec == delta_time_tv.tv_sec ) && ( tv0.tv_usec < delta_time_tv.tv_usec ) ) )
			{
				rc = 0; /* timed out */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
442
443
444
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}
445
446
447
448
449
450
451
452
453

			/* tv0 -= delta_time */
			tv0.tv_sec -= delta_time_tv.tv_sec;
			tv0.tv_usec -= delta_time_tv.tv_usec;
			if ( tv0.tv_usec < 0 ) {
				tv0.tv_sec--;
				tv0.tv_usec += 1000000;
			}

454
			tv.tv_sec = tv0.tv_sec;
455
456
457
458
			tv.tv_usec = tv0.tv_usec;

			Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld s %ld us to go\n",
				(void *)ld, (long) tv.tv_sec, (long) tv.tv_usec );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
459

460
461
			start_time_tv.tv_sec = curr_time_tv.tv_sec;
			start_time_tv.tv_usec = curr_time_tv.tv_usec;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
462
463
464
		}
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
465
	return( rc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
466
467
468
}


469
470
471
472
473
static ber_tag_t
try_read1msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
474
	LDAPConn *lc,
475
	LDAPMessage **result )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
476
{
477
	BerElement	*ber;
478
	LDAPMessage	*newmsg, *l, *prev;
479
	ber_int_t	id;
480
	int		idx;
481
482
	ber_tag_t	tag;
	ber_len_t	len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
483
	int		foundit = 0;
484
	LDAPRequest	*lr, *tmplr, dummy_lr = { 0 };
Kurt Zeilenga's avatar
Kurt Zeilenga committed
485
	BerElement	tmpber;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
486
	int		rc, refer_cnt, hadref, simple_request, err;
487
	ber_int_t	lderr;
488

489
#ifdef LDAP_CONNECTIONLESS
490
	LDAPMessage	*tmp = NULL, *chain_head = NULL;
491
	int		moremsgs = 0, isv2 = 0;
492
#endif
493

Kurt Zeilenga's avatar
Kurt Zeilenga committed
494
	assert( ld != NULL );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
495
	assert( lc != NULL );
496
	
Pierangelo Masarati's avatar
Pierangelo Masarati committed
497
498
499
500
#ifdef LDAP_R_COMPILE
	LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
#endif

Pierangelo Masarati's avatar
Pierangelo Masarati committed
501
502
	Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n",
		(void *)ld, msgid, all );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
503

504
retry:
505
	if ( lc->lconn_ber == NULL ) {
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
506
		lc->lconn_ber = ldap_alloc_ber_with_options( ld );
507

508
		if ( lc->lconn_ber == NULL ) {
509
510
			return -1;
		}
511
	}
512
513

	ber = lc->lconn_ber;
514
	assert( LBER_VALID (ber) );
Kurt Zeilenga's avatar
ldap.h:    
Kurt Zeilenga committed
515

Kurt Zeilenga's avatar
Kurt Zeilenga committed
516
	/* get the next message */
517
	sock_errset(0);
518
519
520
#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP(ld) ) {
		struct sockaddr from;
521
		ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr) );
522
		if ( ld->ld_options.ldo_version == LDAP_VERSION2 ) isv2 = 1;
523
	}
524
nextresp3:
525
#endif
526
	tag = ber_get_next( lc->lconn_sb, &len, ber );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
527
528
	switch ( tag ) {
	case LDAP_TAG_MESSAGE:
529
530
531
532
533
		/*
	 	 * We read a complete message.
	 	 * The connection should no longer need this ber.
	 	 */
		lc->lconn_ber = NULL;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
534
535
536
		break;

	case LBER_DEFAULT:
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
537
		err = sock_errno();
538
#ifdef LDAP_DEBUG		   
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
539
540
		Debug( LDAP_DEBUG_CONNS,
			"ber_get_next failed.\n", 0, 0, 0 );
541
542
#endif		   
#ifdef EWOULDBLOCK			
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
543
		if ( err == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING;
544
545
#endif
#ifdef EAGAIN
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
546
		if ( err == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING;
547
#endif
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
548
		ld->ld_errno = LDAP_SERVER_DOWN;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
549
550
		--lc->lconn_refcnt;
		lc->lconn_status = 0;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
551
552
553
		return -1;

	default:
554
555
		ld->ld_errno = LDAP_LOCAL_ERROR;
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
557
558
	}

	/* message id */
559
	if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
560
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
561
562
563
564
		ld->ld_errno = LDAP_DECODING_ERROR;
		return( -1 );
	}

565
566
	/* id == 0 iff unsolicited notification message (RFC 4511) */

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
567
568
569
570
571
	/* id < 0 is invalid, just toss it. FIXME: should we disconnect? */
	if ( id < 0 ) {
		goto retry_ber;
	}
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
572
	/* if it's been abandoned, toss it */
573
574
575
576
577
578
579
580
581
582
	if ( id > 0 ) {
		if ( ldap_abandoned( ld, id, &idx ) ) {
			/* the message type */
			tag = ber_peek_tag( ber, &len );
			switch ( tag ) {
			case LDAP_RES_SEARCH_ENTRY:
			case LDAP_RES_SEARCH_REFERENCE:
			case LDAP_RES_INTERMEDIATE:
			case LBER_ERROR:
				break;
583

584
585
586
587
588
589
			default:
				/* there's no need to keep the id
				 * in the abandoned list any longer */
				ldap_mark_abandoned( ld, id, idx );
				break;
			}
590

591
			Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
592
593
				"abandoned/discarded ld %p msgid %d message type %s\n",
				(void *)ld, id, ldap_int_msgtype2str( tag ) );
594

595
retry_ber:
596
597
598
599
600
			ber_free( ber, 1 );
			if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
				goto retry;
			}
			return( LDAP_MSG_X_KEEP_LOOKING );	/* continue looking */
601
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
602

603
604
605
		lr = ldap_find_request_by_msgid( ld, id );
		if ( lr == NULL ) {
			const char	*msg = "unknown";
606

607
608
609
610
611
			/* the message type */
			tag = ber_peek_tag( ber, &len );
			switch ( tag ) {
			case LBER_ERROR:
				break;
612

613
614
615
616
			default:
				msg = ldap_int_msgtype2str( tag );
				break;
			}
617

618
			Debug( LDAP_DEBUG_ANY,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
619
620
				"no request for response on ld %p msgid %d message type %s (tossing)\n",
				(void *)ld, id, msg );
621
622
623

			goto retry_ber;
		}
624

625
#ifdef LDAP_CONNECTIONLESS
626
627
628
		if ( LDAP_IS_UDP(ld) && isv2 ) {
			ber_scanf(ber, "x{");
		}
Howard Chu's avatar
Howard Chu committed
629
nextresp2:
630
		;
631
#endif
632
633
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
634
	/* the message type */
635
636
	tag = ber_peek_tag( ber, &len );
	if ( tag == LBER_ERROR ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
637
		ld->ld_errno = LDAP_DECODING_ERROR;
638
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
639
640
641
		return( -1 );
	}

642
	Debug( LDAP_DEBUG_TRACE,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
643
644
		"read1msg: ld %p msgid %d message type %s\n",
		(void *)ld, id, ldap_int_msgtype2str( tag ) );
645

646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
	if ( id == 0 ) {
		/* unsolicited notification message (RFC 4511) */
		if ( tag != LDAP_RES_EXTENDED ) {
			/* toss it */
			goto retry_ber;

			/* strictly speaking, it's an error; from RFC 4511:

4.4.  Unsolicited Notification

   An unsolicited notification is an LDAPMessage sent from the server to
   the client that is not in response to any LDAPMessage received by the
   server.  It is used to signal an extraordinary condition in the
   server or in the LDAP session between the client and the server.  The
   notification is of an advisory nature, and the server will not expect
   any response to be returned from the client.

   The unsolicited notification is structured as an LDAPMessage in which
   the messageID is zero and protocolOp is set to the extendedResp
   choice using the ExtendedResponse type (See Section 4.12).  The
   responseName field of the ExtendedResponse always contains an LDAPOID
   that is unique for this notification.

			 * however, since unsolicited responses
			 * are of advisory nature, better
			 * toss it, right now
			 */

#if 0
			ld->ld_errno = LDAP_DECODING_ERROR;
			ber_free( ber, 1 );
			return( -1 );
#endif
		}

		lr = &dummy_lr;
	}

684
	id = lr->lr_origid;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
685
686
	refer_cnt = 0;
	hadref = simple_request = 0;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
687
	rc = LDAP_MSG_X_KEEP_LOOKING;	/* default is to keep looking (no response found) */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
688
689
	lr->lr_res_msgtype = tag;

690
	/*
691
	 * Check for V3 search reference
692
	 */
693
694
	if ( tag == LDAP_RES_SEARCH_REFERENCE ) {
		if ( ld->ld_version > LDAP_VERSION2 ) {
695
			/* This is a V3 search reference */
696
697
			if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
					lr->lr_parent != NULL )
698
			{
699
700
701
				char **refs = NULL;
				tmpber = *ber;

702
703
704
				/* Get the referral list */
				if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) {
					rc = LDAP_DECODING_ERROR;
705

706
				} else {
707
					/* Note: refs array is freed by ldap_chase_v3referrals */
708
					refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
709
						1, &lr->lr_res_error, &hadref );
710
					if ( refer_cnt > 0 ) {
711
						/* successfully chased reference */
712
						/* If haven't got end search, set chasing referrals */
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
713
						if ( lr->lr_status != LDAP_REQST_COMPLETED ) {
714
715
							lr->lr_status = LDAP_REQST_CHASINGREFS;
							Debug( LDAP_DEBUG_TRACE,
716
717
718
								"read1msg:  search ref chased, "
								"mark request chasing refs, "
								"id = %d\n",
719
								lr->lr_msgid, 0, 0 );
720
721
722
723
						}
					}
				}
			}
724
		}
725
726
727
728
729
730

	} else if ( tag != LDAP_RES_SEARCH_ENTRY && tag != LDAP_RES_INTERMEDIATE ) {
		/* All results that just return a status, i.e. don't return data
		 * go through the following code.  This code also chases V2 referrals
		 * and checks if all referrals have been chased.
		 */
731
		char		*lr_res_error = NULL;
732

733
734
735
736
737
738
739
740
741
		tmpber = *ber; 	/* struct copy */
		if ( ber_scanf( &tmpber, "{eAA", &lderr,
				&lr->lr_res_matched, &lr_res_error )
				!= LBER_ERROR )
		{
			if ( lr_res_error != NULL ) {
				if ( lr->lr_res_error != NULL ) {
					(void)ldap_append_referral( ld, &lr->lr_res_error, lr_res_error );
					LDAP_FREE( (char *)lr_res_error );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
742

743
744
				} else {
					lr->lr_res_error = lr_res_error;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
745
				}
746
747
748
749
				lr_res_error = NULL;
			}

			/* Do we need to check for referrals? */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
750
751
752
			if ( tag != LDAP_RES_BIND &&
				( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
					lr->lr_parent != NULL ))
753
754
755
			{
				char		**refs = NULL;
				ber_len_t	len;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
756

757
				/* Check if V3 referral */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
758
				if ( ber_peek_tag( &tmpber, &len ) == LDAP_TAG_REFERRAL ) {
759
					if ( ld->ld_version > LDAP_VERSION2 ) {
760
						/* Get the referral list */
761
						if ( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) {
762
763
764
							rc = LDAP_DECODING_ERROR;
							lr->lr_status = LDAP_REQST_COMPLETED;
							Debug( LDAP_DEBUG_TRACE,
765
766
767
								"read1msg: referral decode error, "
								"mark request completed, ld %p msgid %d\n",
								(void *)ld, lr->lr_msgid, 0 );
768

769
770
						} else {
							/* Chase the referral 
771
							 * refs array is freed by ldap_chase_v3referrals
772
773
							 */
							refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
774
								0, &lr->lr_res_error, &hadref );
775
776
							lr->lr_status = LDAP_REQST_COMPLETED;
							Debug( LDAP_DEBUG_TRACE,
777
								"read1msg: referral %s chased, "
778
								"mark request completed, ld %p msgid %d\n",
779
								refer_cnt > 0 ? "" : "not",
780
								(void *)ld, lr->lr_msgid);
781
							if ( refer_cnt < 0 ) {
782
								refer_cnt = 0;
783
784
785
							}
						}
					}
786
787
788
789
790
791
				} else {
					switch ( lderr ) {
					case LDAP_SUCCESS:
					case LDAP_COMPARE_TRUE:
					case LDAP_COMPARE_FALSE:
						break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
792

793
					default:
794
						if ( lr->lr_res_error == NULL ) {
795
796
							break;
						}
797

798
799
800
801
802
803
804
						/* pedantic, should never happen */
						if ( lr->lr_res_error[ 0 ] == '\0' ) {
							LDAP_FREE( lr->lr_res_error );
							lr->lr_res_error = NULL;
							break;	
						}

805
806
807
808
809
810
811
812
						/* V2 referrals are in error string */
						refer_cnt = ldap_chase_referrals( ld, lr,
							&lr->lr_res_error, -1, &hadref );
						lr->lr_status = LDAP_REQST_COMPLETED;
						Debug( LDAP_DEBUG_TRACE,
							"read1msg:  V2 referral chased, "
							"mark request completed, id = %d\n",
							lr->lr_msgid, 0, 0 );
813
814
						break;
					}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
815
				}
816
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
817

818
819
820
821
822
			/* save errno, message, and matched string */
			if ( !hadref || lr->lr_res_error == NULL ) {
				lr->lr_res_errno =
					lderr == LDAP_PARTIAL_RESULTS
					? LDAP_SUCCESS : lderr;
823

824
825
			} else if ( ld->ld_errno != LDAP_SUCCESS ) {
				lr->lr_res_errno = ld->ld_errno;
826

827
828
			} else {
				lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
829
			}
830
		}
831

832
833
834
		/* in any case, don't leave any lr_res_error 'round */
		if ( lr_res_error ) {
			LDAP_FREE( lr_res_error );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
835
836
837
		}

		Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
838
839
			"read1msg: ld %p %d new referrals\n",
			(void *)ld, refer_cnt, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
840
841

		if ( refer_cnt != 0 ) {	/* chasing referrals */
842
843
			ber_free( ber, 1 );
			ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
844
			if ( refer_cnt < 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
845
				ldap_return_request( ld, lr, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
846
847
				return( -1 );	/* fatal error */
			}
848
			lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
849
850
851
852
			if ( lr->lr_res_matched ) {
				LDAP_FREE( lr->lr_res_matched );
				lr->lr_res_matched = NULL;
			}
853

Kurt Zeilenga's avatar
Kurt Zeilenga committed
854
855
856
857
		} else {
			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
				/* request without any referrals */
				simple_request = ( hadref ? 0 : 1 );
858

Kurt Zeilenga's avatar
Kurt Zeilenga committed
859
860
			} else {
				/* request with referrals or child request */
861
862
				ber_free( ber, 1 );
				ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
863
864
			}

865
866
			lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */
			Debug( LDAP_DEBUG_TRACE,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
867
868
				"read1msg:  mark request completed, ld %p msgid %d\n",
				(void *)ld, lr->lr_msgid, 0);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
869
870
871
872
873
874
875
876
877
			while ( lr->lr_parent != NULL ) {
				merge_error_info( ld, lr->lr_parent, lr );

				lr = lr->lr_parent;
				if ( --lr->lr_outrefcnt > 0 ) {
					break;	/* not completely done yet */
				}
			}

878
			/* Check if all requests are finished, lr is now parent */
879
			tmplr = lr;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
880
			if ( tmplr->lr_status == LDAP_REQST_COMPLETED ) {
881
				for ( tmplr = lr->lr_child;
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
882
					tmplr != NULL;
883
					tmplr = tmplr->lr_refnext )
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
884
				{
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
885
					if ( tmplr->lr_status != LDAP_REQST_COMPLETED ) break;
886
887
888
889
				}
			}

			/* This is the parent request if the request has referrals */
890
891
			if ( lr->lr_outrefcnt <= 0 &&
				lr->lr_parent == NULL &&
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
892
893
				tmplr == NULL )
			{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
894
895
				id = lr->lr_msgid;
				tag = lr->lr_res_msgtype;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
896
897
				Debug( LDAP_DEBUG_TRACE, "request done: ld %p msgid %d\n",
					(void *)ld, id, 0 );
898
899
900
901
902
903
				Debug( LDAP_DEBUG_TRACE,
					"res_errno: %d, res_error: <%s>, "
					"res_matched: <%s>\n",
					lr->lr_res_errno,
					lr->lr_res_error ? lr->lr_res_error : "",
					lr->lr_res_matched ? lr->lr_res_matched : "" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
904
				if ( !simple_request ) {
905
906
					ber_free( ber, 1 );
					ber = NULL;
907
					if ( build_result_ber( ld, &ber, lr )
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
908
909
					    == LBER_ERROR )
					{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
910
911
912
913
						rc = -1; /* fatal error */
					}
				}

914
915
916
				if ( lr != &dummy_lr ) {
					ldap_return_request( ld, lr, 1 );
				}
917
				lr = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
918
919
			}

920
921
922
923
924
			/*
			 * RF 4511 unsolicited (id == 0) responses
			 * shouldn't necessarily end the connection
			 */
			if ( lc != NULL && id != 0 ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
925
926
				--lc->lconn_refcnt;
				lc = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
927
928
929
930
			}
		}
	}

931
	if ( lr != NULL ) {
932
933
934
		if ( lr != &dummy_lr ) {
			ldap_return_request( ld, lr, 0 );
		}
935
936
937
		lr = NULL;
	}

938
	if ( ber == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
939
940
941
		return( rc );
	}

942
	/* try to handle unsolicited responses as appropriate */
943
	if ( id == 0 && msgid > LDAP_RES_UNSOLICITED ) {
944
945
		int	is_nod = 0;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
946
		tag = ber_peek_tag( &tmpber, &len );
947
948
949

		/* we have a res oid */
		if ( tag == LDAP_TAG_EXOP_RES_OID ) {
950
951
			static struct berval	bv_nod = BER_BVC( LDAP_NOTICE_OF_DISCONNECTION );
			struct berval		resoid = BER_BVNULL;
952

Pierangelo Masarati's avatar
Pierangelo Masarati committed
953
			if ( ber_scanf( &tmpber, "m", &resoid ) == LBER_ERROR ) {
954
955
956
957
958
				ld->ld_errno = LDAP_DECODING_ERROR;
				ber_free( ber, 1 );
				return -1;
			}

959
			assert( !BER_BVISEMPTY( &resoid ) );