result.c 32.6 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
5
6
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */
/*  Portions
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
8
 *  Copyright (c) 1990 Regents of the University of Michigan.
 *  All rights reserved.
9
10
 */
/*---
11
12
13
14
15
16
17
18
19
20
21
22
23
 * This notice applies to changes, created by or for Novell, Inc.,
 * 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. 
24
 *---
25
26
 * Modification to OpenLDAP source by Novell, Inc.
 * April 2000 sfs Add code to process V3 referrals and search results
Kurt Zeilenga's avatar
Kurt Zeilenga committed
27
28
29
 *
 *  result.c - wait for an ldap result
 */
30
31
32
33
/* Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License 
 * can be found in the file "build/LICENSE-2.0.1" in this distribution
 * of OpenLDAP Software.
 */
34
35
36
37
/*
 * Portions Copyright (C) The Internet Society (1997)
 * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
38

39
40
41
42
43
44
45
46
47
48
49
50
/*
 * LDAPv3 (RFC2251)
 *	LDAPResult ::= SEQUENCE {
 *		resultCode		ENUMERATED { ... },
 *		matchedDN		LDAPDN,
 *		errorMessage	LDAPString,
 *		referral		Referral OPTIONAL
 *	}
 *	Referral ::= SEQUENCE OF LDAPURL	(one or more)
 *	LDAPURL ::= LDAPString				(limited to URL chars)
 */

51
52
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
53
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
54
55

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

57
58
59
60
61
#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
62

Kurt Zeilenga's avatar
Kurt Zeilenga committed
63
#include "ldap-int.h"
Julius Enarusai's avatar
   
Julius Enarusai committed
64
#include "ldap_log.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
65

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


/*
 * ldap_result - wait for an ldap result response to a message from the
79
80
81
82
83
84
 * 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
85
86
87
88
89
 * 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.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
90
91
92
93
94
95
 * When waiting, any messages that have been abandoned are discarded.
 *
 * Example:
 *	ldap_result( s, msgid, all, timeout, result )
 */
int
96
97
98
99
100
ldap_result(
	LDAP *ld,
	int msgid,
	int all,
	struct timeval *timeout,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
101
102
	LDAPMessage **result )
{
103
	LDAPMessage	*lm;
104
	int	rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
105

Kurt Zeilenga's avatar
Kurt Zeilenga committed
106
107
108
	assert( ld != NULL );
	assert( result != NULL );

Julius Enarusai's avatar
   
Julius Enarusai committed
109
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
110
	LDAP_LOG ( OPERATION, ARGS, "ldap_result msgid %d\n", msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
111
#else
112
	Debug( LDAP_DEBUG_TRACE, "ldap_result msgid %d\n", msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
113
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
114

115
116
117
118
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
#endif
	lm = chkResponseList(ld, msgid, all);
119
120

	if ( lm == NULL ) {
121
122
123
124
125
		rc = wait4msg( ld, msgid, all, timeout, result );
	} else {
		*result = lm;
		ld->ld_errno = LDAP_SUCCESS;
		rc = lm->lm_msgtype;
126
	}
127
128
129
130
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
#endif
	return( rc );
131
132
133
}

static LDAPMessage *
134
135
136
137
chkResponseList(
	LDAP *ld,
	int msgid,
	int all)
138
139
140
141
{
	LDAPMessage	*lm, *lastlm, *nextlm;
    /*
	 * Look through the list of responses we have received on
Kurt Zeilenga's avatar
Kurt Zeilenga committed
142
143
144
145
146
	 * 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.
	 */

Julius Enarusai's avatar
   
Julius Enarusai committed
147
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
148
149
	LDAP_LOG ( OPERATION, ARGS, "ldap_chkResponseList for msgid=%d, all=%d\n", 
		msgid, all, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
150
#else
151
152
	Debug( LDAP_DEBUG_TRACE,
		"ldap_chkResponseList for msgid=%d, all=%d\n",
153
	    msgid, all, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
154
#endif
155
156
	lastlm = NULL;
	for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
157
158
159
		nextlm = lm->lm_next;

		if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
160
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
161
162
			LDAP_LOG ( OPERATION, DETAIL1, 
				"ldap_chkResponseList msg abandoned, msgid %d\n", msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
163
#else
164
165
			Debug( LDAP_DEBUG_TRACE,
				"ldap_chkResponseList msg abandoned, msgid %d\n",
166
			    msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
167
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
168
169
			ldap_mark_abandoned( ld, lm->lm_msgid );

170
			if ( lastlm == NULL ) {
171
				/* Remove first entry in list */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172
173
174
175
176
177
178
179
180
181
182
183
184
				ld->ld_responses = lm->lm_next;
			} else {
				lastlm->lm_next = nextlm;
			}

			ldap_msgfree( lm );

			continue;
		}

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

185
			if ( all == LDAP_MSG_ONE || msgid == LDAP_RES_UNSOLICITED ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
186
				break;
187
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
188

189
			for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
190
191
				if ( tmp->lm_msgtype != LDAP_RES_SEARCH_ENTRY
				    && tmp->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
192
					&& tmp->lm_msgtype != LDAP_RES_INTERMEDIATE )
193
				{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
194
					break;
195
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
196
197
			}

198
			if ( tmp == NULL ) {
199
				lm = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
200
201
202
203
204
205
			}

			break;
		}
		lastlm = lm;
	}
206

207
    if ( lm != NULL ) {
208
		/* Found an entry, remove it from the list */
209
210
211
212
213
214
215
	    if ( lastlm == NULL ) {
		    ld->ld_responses = (all == LDAP_MSG_ONE && lm->lm_chain != NULL
		        ? lm->lm_chain : lm->lm_next);
	    } else {
		    lastlm->lm_next = (all == LDAP_MSG_ONE && lm->lm_chain != NULL
		        ? lm->lm_chain : lm->lm_next);
	    }
216
	    if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) {
217
218
219
220
221
		    lm->lm_chain->lm_next = lm->lm_next;
		    lm->lm_chain = NULL;
	    }
	    lm->lm_next = NULL;
    }
222
223
224

#ifdef LDAP_DEBUG
	if( lm == NULL) {
Julius Enarusai's avatar
   
Julius Enarusai committed
225
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
226
227
		LDAP_LOG ( OPERATION, RESULTS, "ldap_chkResponseList returns NULL\n",
			0, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
228
#else
229
230
		Debug( LDAP_DEBUG_TRACE,
			"ldap_chkResponseList returns NULL\n", 0, 0, 0);
Julius Enarusai's avatar
   
Julius Enarusai committed
231
#endif
232
	} else {
Julius Enarusai's avatar
   
Julius Enarusai committed
233
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
234
235
236
		LDAP_LOG ( OPERATION, RESULTS, 
			"ldap_chkResponseList returns msgid %d, type 0x%02lu\n",
			lm->lm_msgid, (unsigned long) lm->lm_msgtype, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
237
#else
238
239
240
		Debug( LDAP_DEBUG_TRACE,
			"ldap_chkResponseList returns msgid %d, type 0x%02lu\n",
			lm->lm_msgid, (unsigned long) lm->lm_msgtype, 0);
Julius Enarusai's avatar
   
Julius Enarusai committed
241
#endif
242
243
	}
#endif
244
    return lm;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
245
}
246

Kurt Zeilenga's avatar
Kurt Zeilenga committed
247
static int
248
249
250
251
252
wait4msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
	struct timeval *timeout,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
253
254
255
256
	LDAPMessage **result )
{
	int		rc;
	struct timeval	tv, *tvp;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
258
	time_t		start_time = 0;
	time_t		tmp_time;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
259
260
	LDAPConn	*lc, *nextlc;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
261
262
263
	assert( ld != NULL );
	assert( result != NULL );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
264
265
#ifdef LDAP_DEBUG
	if ( timeout == NULL ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
266
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
267
268
		LDAP_LOG ( OPERATION, ARGS, 
			"wait4msg (infinite timeout), msgid %d\n", msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
269
#else
270
271
		Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout), msgid %d\n",
		    msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
272
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
273
	} else {
Julius Enarusai's avatar
   
Julius Enarusai committed
274
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
275
		LDAP_LOG ( OPERATION, ARGS, 
Julius Enarusai's avatar
   
Julius Enarusai committed
276
			"wait4msg (timeout %ld sec, %ld usec), msgid %d\n", 
Julius Enarusai's avatar
   
Julius Enarusai committed
277
			(long) timeout->tv_sec, (long) timeout->tv_usec, msgid );
Julius Enarusai's avatar
   
Julius Enarusai committed
278
#else
279
280
		Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec), msgid %d\n",
		       (long) timeout->tv_sec, (long) timeout->tv_usec, msgid );
Julius Enarusai's avatar
   
Julius Enarusai committed
281
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
282
283
284
285
286
287
288
289
	}
#endif /* LDAP_DEBUG */

	if ( timeout == NULL ) {
		tvp = NULL;
	} else {
		tv = *timeout;
		tvp = &tv;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
290
		start_time = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
291
292
293
294
295
	}
		    
	rc = -2;
	while ( rc == -2 ) {
#ifdef LDAP_DEBUG
Julius Enarusai's avatar
   
Julius Enarusai committed
296
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
297
298
		LDAP_LOG ( OPERATION, ARGS, 
			"wait4msg continue, msgid %d, all %d\n", msgid, all, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
299
#else
300
301
		Debug( LDAP_DEBUG_TRACE, "wait4msg continue, msgid %d, all %d\n",
		    msgid, all, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
302
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
303
		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
304
305
			ldap_dump_connection( ld, ld->ld_conns, 1 );
			ldap_dump_requests_and_responses( ld );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
306
307
308
		}
#endif /* LDAP_DEBUG */

309
310
311
312
313
314
315
316
317
318
319
320
321
322
        if( (*result = chkResponseList(ld, msgid, all)) != NULL ) {
            rc = (*result)->lm_msgtype;
        } else {

			for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
				if ( ber_sockbuf_ctrl( lc->lconn_sb,
						LBER_SB_OPT_DATA_READY, NULL ) ) {
					    rc = try_read1msg( ld, msgid, all, lc->lconn_sb,
					        lc, result );
				    break;
				}
	        }

		    if ( lc == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
323
			    rc = ldap_int_select( ld, tvp );
324
#ifdef LDAP_DEBUG
325
			    if ( rc == -1 ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
326
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
327
					LDAP_LOG ( OPERATION, ARGS, 
Julius Enarusai's avatar
   
Julius Enarusai committed
328
						"wait4msg: ldap_int_select returned -1: errno %d\n", 
Julius Enarusai's avatar
   
Julius Enarusai committed
329
						errno, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
330
#else
331
			        Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
332
				        "ldap_int_select returned -1: errno %d\n",
333
				        errno, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
334
#endif
335
			    }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
336
337
#endif

338
339
340
341
342
343
344
345
346
347
348
349
350
			    if ( rc == 0 || ( rc == -1 && (
				    !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)
				    || errno != EINTR )))
			    {
				    ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
				        LDAP_TIMEOUT);
				    return( rc );
			    }

			    if ( rc == -1 ) {
				    rc = -2;	/* select interrupted: loop */
			    } else {
				    rc = -2;
351
352
353
#ifdef LDAP_R_COMPILE
				    ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
354
355
356
357
358
359
				    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 );
					}
360
361
362
#ifdef LDAP_R_COMPILE
				    ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
363
364
365
366
367
368
369
370
371
372
373
374
375
				    for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
				        lc = nextlc ) {
					    nextlc = lc->lconn_next;
					    if ( lc->lconn_status ==
					        LDAP_CONNST_CONNECTED &&
					        ldap_is_read_ready( ld,
					        lc->lconn_sb )) {
						    rc = try_read1msg( ld, msgid, all,
						        lc->lconn_sb, lc, result );
					    }
				    }
			    }
		    }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
376
377
378
		}

		if ( rc == -2 && tvp != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
379
			tmp_time = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
380
381
382
383
384
385
			if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
				rc = 0;	/* timed out */
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}

Julius Enarusai's avatar
   
Julius Enarusai committed
386
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
387
388
			LDAP_LOG ( OPERATION, DETAIL1, 
				"wait4msg: %ld secs to go\n", (long) tv.tv_sec, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
389
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
390
			Debug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
Hallvard Furuseth's avatar
Hallvard Furuseth committed
391
			       (long) tv.tv_sec, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
392
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
393
394
395
396
397
398
399
400
			start_time = tmp_time;
		}
	}

	return( rc );
}


401
402
403
404
405
406
static ber_tag_t
try_read1msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
	Sockbuf *sb,
407
	LDAPConn *lc,
408
	LDAPMessage **result )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
409
{
410
	BerElement	*ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
411
	LDAPMessage	*new, *l, *prev, *tmp;
412
413
414
	ber_int_t	id;
	ber_tag_t	tag;
	ber_len_t	len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
415
	int		foundit = 0;
416
	LDAPRequest	*lr, *tmplr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
417
418
	BerElement	tmpber;
	int		rc, refer_cnt, hadref, simple_request;
419
	ber_int_t	lderr;
420
421
422
#ifdef LDAP_CONNECTIONLESS
	int		firstmsg = 1, moremsgs = 0, isv2 = 0;
#endif
423
424
425
426
427
	/*
	 * v3ref = flag for V3 referral / search reference
	 * 0 = not a ref, 1 = sucessfully chased ref, -1 = pass ref to application
	 */
	int     v3ref;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
428
429
430

	assert( ld != NULL );
	assert( lc != NULL );
431
	
Julius Enarusai's avatar
   
Julius Enarusai committed
432
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
433
	LDAP_LOG ( OPERATION, ARGS, "read1msg: msgid %d, all %d\n", msgid, all, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
434
#else
435
	Debug( LDAP_DEBUG_TRACE, "read1msg: msgid %d, all %d\n", msgid, all, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
436
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
437

438
retry:
439
	if ( lc->lconn_ber == NULL ) {
440
441
442
443
444
		lc->lconn_ber = ldap_alloc_ber_with_options(ld);

		if( lc->lconn_ber == NULL ) {
			return -1;
		}
445
	}
446
447

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
450
	/* get the next message */
451
	errno = 0;
452
453
454
455
#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP(ld) ) {
		struct sockaddr from;
		ber_int_sb_read(sb, &from, sizeof(struct sockaddr));
456
		if (ld->ld_options.ldo_version == LDAP_VERSION2) isv2=1;
457
	}
458
nextresp3:
459
#endif
460
461
462
463
464
465
466
467
468
	tag = ber_get_next( sb, &len, ber );
	if ( tag == LDAP_TAG_MESSAGE ) {
		/*
	 	 * We read a complete message.
	 	 * The connection should no longer need this ber.
	 	 */
		lc->lconn_ber = NULL;
	}
	if ( tag != LDAP_TAG_MESSAGE ) {
469
470
		if ( tag == LBER_DEFAULT) {
#ifdef LDAP_DEBUG		   
Julius Enarusai's avatar
   
Julius Enarusai committed
471
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
472
473
			LDAP_LOG ( OPERATION, DETAIL1, 
				"read1msg: ber_get_next failed\n", 0, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
474
#else
475
476
477
			Debug( LDAP_DEBUG_CONNS,
			      "ber_get_next failed.\n", 0, 0, 0 );
#endif		   
Julius Enarusai's avatar
   
Julius Enarusai committed
478
#endif		   
479
480
481
482
483
484
485
486
487
488
489
#ifdef EWOULDBLOCK			
			if (errno==EWOULDBLOCK) return -2;
#endif
#ifdef EAGAIN
			if (errno == EAGAIN) return -2;
#endif
			ld->ld_errno = LDAP_SERVER_DOWN;
			return -1;
		}
		ld->ld_errno = LDAP_LOCAL_ERROR;
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
490
491
492
	}

	/* message id */
493
	if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
494
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
495
496
497
498
499
		ld->ld_errno = LDAP_DECODING_ERROR;
		return( -1 );
	}

	/* if it's been abandoned, toss it */
500
	if ( ldap_abandoned( ld, id ) ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
501
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
502
		LDAP_LOG ( OPERATION, DETAIL1, "read1msg: abandoned\n", 0, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
503
#else
504
		Debug( LDAP_DEBUG_ANY, "abandoned\n", 0, 0, 0);
Julius Enarusai's avatar
   
Julius Enarusai committed
505
#endif
506
retry_ber:
507
		ber_free( ber, 1 );
508
		if ( ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
509
			goto retry;
510
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
511
512
513
		return( -2 );	/* continue looking */
	}

514
	if (( lr = ldap_find_request_by_msgid( ld, id )) == NULL ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
515
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
516
		LDAP_LOG ( OPERATION, DETAIL1, 
Julius Enarusai's avatar
   
Julius Enarusai committed
517
			"read1msg: no request for response with msgid %ld (tossing)\n",
Julius Enarusai's avatar
   
Julius Enarusai committed
518
			(long) id, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
519
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
520
521
		Debug( LDAP_DEBUG_ANY,
		    "no request for response with msgid %ld (tossing)\n",
Hallvard Furuseth's avatar
Hallvard Furuseth committed
522
		    (long) id, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
523
#endif
524
		goto retry_ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
525
	}
526
#ifdef LDAP_CONNECTIONLESS
527
528
	if (LDAP_IS_UDP(ld) && isv2) {
		ber_scanf(ber, "x{");
529
	}
Howard Chu's avatar
Howard Chu committed
530
nextresp2:
531
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
532
	/* the message type */
533
	if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
534
		ld->ld_errno = LDAP_DECODING_ERROR;
535
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
536
537
538
		return( -1 );
	}

Julius Enarusai's avatar
   
Julius Enarusai committed
539
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
540
	LDAP_LOG ( OPERATION, DETAIL1, 
Julius Enarusai's avatar
   
Julius Enarusai committed
541
542
		"read1msg: ldap_read: message type %s msgid %ld, original id %ld\n",
	    ldap_int_msgtype2str( tag ),
Julius Enarusai's avatar
   
Julius Enarusai committed
543
		(long) lr->lr_msgid, (long) lr->lr_origid );
Julius Enarusai's avatar
   
Julius Enarusai committed
544
#else
545
546
	Debug( LDAP_DEBUG_TRACE,
		"ldap_read: message type %s msgid %ld, original id %ld\n",
547
	    ldap_int_msgtype2str( tag ),
548
		(long) lr->lr_msgid, (long) lr->lr_origid );
Julius Enarusai's avatar
   
Julius Enarusai committed
549
#endif
550
551

	id = lr->lr_origid;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
552
553
554
555
556
	refer_cnt = 0;
	hadref = simple_request = 0;
	rc = -2;	/* default is to keep looking (no response found) */
	lr->lr_res_msgtype = tag;

557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
	/*
	 * This code figures out if we are going to chase a
	 * referral / search reference, or pass it back to the application
	 */
	v3ref = 0;	/* Assume not a V3 search reference or referral */
	if( (tag != LDAP_RES_SEARCH_ENTRY) && (ld->ld_version > LDAP_VERSION2) ) {
		BerElement	tmpber = *ber; 	/* struct copy */
		char **refs = NULL;

		if( tag == LDAP_RES_SEARCH_REFERENCE) {
			/* This is a V3 search reference */
			/* Assume we do not chase the reference, but pass it to application */
			v3ref = -1;
			if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
					(lr->lr_parent != NULL) )
			{
				/* Get the referral list */
				if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) {
					rc = LDAP_DECODING_ERROR;
				} else {
					/* Note: refs arrary is freed by ldap_chase_v3referrals */
					refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
579
					    1, &lr->lr_res_error, &hadref );
580
581
582
583
					if ( refer_cnt > 0 ) {	/* sucessfully chased reference */
						/* If haven't got end search, set chasing referrals */
						if( lr->lr_status != LDAP_REQST_COMPLETED) {
							lr->lr_status = LDAP_REQST_CHASINGREFS;
Julius Enarusai's avatar
   
Julius Enarusai committed
584
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
585
							LDAP_LOG ( OPERATION, DETAIL1, 
Julius Enarusai's avatar
   
Julius Enarusai committed
586
587
								"read1msg: search ref chased,"
								"mark request chasing refs, id =	%d\n",
Julius Enarusai's avatar
   
Julius Enarusai committed
588
								lr->lr_msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
589
#else
590
591
592
							Debug( LDAP_DEBUG_TRACE,
							    "read1msg:  search ref chased, mark request chasing refs, id = %d\n",
							    lr->lr_msgid, 0, 0);
Julius Enarusai's avatar
   
Julius Enarusai committed
593
#endif
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
						}
						v3ref = 1;	/* We sucessfully chased the reference */
					}
				}
			}
		} else {
			/* Check for V3 referral */
			ber_len_t len;
			if ( ber_scanf( &tmpber, "{iaa",/*}*/ &lderr,
				    &lr->lr_res_matched, &lr->lr_res_error )
				    != LBER_ERROR ) {
				/* Check if V3 referral */
				if( ber_peek_tag( &tmpber, &len) == LDAP_TAG_REFERRAL ) {
					/* We have a V3 referral, assume we cannot chase it */
					v3ref = -1;
					if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS)
							 || (lr->lr_parent != NULL) )
					{
						v3ref = -1;  /* Assume referral not chased and return it to app */
						/* Get the referral list */
614
						if( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) {
615
616
							rc = LDAP_DECODING_ERROR;
							lr->lr_status = LDAP_REQST_COMPLETED;
Julius Enarusai's avatar
   
Julius Enarusai committed
617
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
618
							LDAP_LOG ( OPERATION, DETAIL1, 
Julius Enarusai's avatar
   
Julius Enarusai committed
619
620
								"read1msg: referral decode error,"
								"mark request completed, id =	%d\n",
Julius Enarusai's avatar
   
Julius Enarusai committed
621
								lr->lr_msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
622
#else
623
624
625
							Debug( LDAP_DEBUG_TRACE,
							    "read1msg: referral decode error, mark request completed, id = %d\n",
								    lr->lr_msgid, 0, 0);
Julius Enarusai's avatar
   
Julius Enarusai committed
626
#endif
627
628
629
630
631
						} else {
							/* Chase the referral 
							 * Note: refs arrary is freed by ldap_chase_v3referrals
							 */
							refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
632
							    0, &lr->lr_res_error, &hadref );
633
							lr->lr_status = LDAP_REQST_COMPLETED;
Julius Enarusai's avatar
   
Julius Enarusai committed
634
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
635
							LDAP_LOG ( OPERATION, DETAIL1, 
Julius Enarusai's avatar
   
Julius Enarusai committed
636
637
								"read1msg: referral chased,"
								"mark request completed, id =	%d\n",
Julius Enarusai's avatar
   
Julius Enarusai committed
638
								lr->lr_msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
639
#else
640
641
642
							Debug( LDAP_DEBUG_TRACE,
							    "read1msg:  referral chased, mark request completed, id = %d\n",
							    lr->lr_msgid, 0, 0);
Julius Enarusai's avatar
   
Julius Enarusai committed
643
#endif
644
645
646
647
648
649
							if( refer_cnt > 0) {
								v3ref = 1;  /* Referral successfully chased */
							}
						}
					}
				}
650
651
652
653
654
655
656
657
658

				if( lr->lr_res_matched != NULL ) {
					LDAP_FREE( lr->lr_res_matched );
					lr->lr_res_matched = NULL;
				}
				if( lr->lr_res_error != NULL ) {
					LDAP_FREE( lr->lr_res_error );
					lr->lr_res_error = NULL;
				}
659
660
661
662
663
664
665
666
			}
		}
	}

	/* 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.
	 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
667
668
669
	if ( (tag != LDAP_RES_SEARCH_ENTRY) && (v3ref > -1) &&
		(tag != LDAP_RES_INTERMEDIATE ))
	{
670
		/* For a v3 search referral/reference, only come here if already chased it */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
671
		if ( ld->ld_version >= LDAP_VERSION2 &&
672
			( lr->lr_parent != NULL ||
673
			LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ) )
674
		{
675
			tmpber = *ber;	/* struct copy */
676
			if ( v3ref == 1 ) {
677
678
679
680
681
682
683
				/* V3 search reference or V3 referral
				 * sucessfully chased. If this message
				 * is a search result, then it has no more
				 * outstanding referrals.
				 */
				if ( tag == LDAP_RES_SEARCH_RESULT )
					refer_cnt = 0;
684
			} else if ( ber_scanf( &tmpber, "{iaa}", &lderr,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
685
686
687
688
			    &lr->lr_res_matched, &lr->lr_res_error )
			    != LBER_ERROR ) {
				if ( lderr != LDAP_SUCCESS ) {
					/* referrals are in error string */
689
					refer_cnt = ldap_chase_referrals( ld, lr,
690
						&lr->lr_res_error, -1, &hadref );
691
					lr->lr_status = LDAP_REQST_COMPLETED;
Julius Enarusai's avatar
   
Julius Enarusai committed
692
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
693
					LDAP_LOG ( OPERATION, DETAIL1, 
Julius Enarusai's avatar
   
Julius Enarusai committed
694
695
						"read1msg: V2 referral chased,"
						"mark request completed, id =	%d\n",
Julius Enarusai's avatar
   
Julius Enarusai committed
696
						lr->lr_msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
697
#else
698
699
					Debug( LDAP_DEBUG_TRACE,
					    "read1msg:  V2 referral chased, mark request completed, id = %d\n", lr->lr_msgid, 0, 0);
Julius Enarusai's avatar
   
Julius Enarusai committed
700
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
701
702
703
704
705
706
707
708
709
710
711
712
				}

				/* save errno, message, and matched string */
				if ( !hadref || lr->lr_res_error == NULL ) {
					lr->lr_res_errno = ( lderr ==
					LDAP_PARTIAL_RESULTS ) ? LDAP_SUCCESS
					: lderr;
				} else if ( ld->ld_errno != LDAP_SUCCESS ) {
					lr->lr_res_errno = ld->ld_errno;
				} else {
					lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
				}
Julius Enarusai's avatar
   
Julius Enarusai committed
713
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
714
LDAP_LOG ( OPERATION, DETAIL1, 
Julius Enarusai's avatar
   
Julius Enarusai committed
715
716
	"read1msg: new result: res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
    lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
Julius Enarusai's avatar
   
Julius Enarusai committed
717
    lr->lr_res_matched ? lr->lr_res_matched : "" );
Julius Enarusai's avatar
   
Julius Enarusai committed
718
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
719
720
721
722
Debug( LDAP_DEBUG_TRACE,
    "new result:  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 : "" );
Julius Enarusai's avatar
   
Julius Enarusai committed
723
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
724
725
726
			}
		}

Julius Enarusai's avatar
   
Julius Enarusai committed
727
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
728
729
		LDAP_LOG ( OPERATION, DETAIL1, "read1msg: %d new referrals\n", 
			refer_cnt, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
730
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
731
732
		Debug( LDAP_DEBUG_TRACE,
		    "read1msg:  %d new referrals\n", refer_cnt, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
733
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
734
735

		if ( refer_cnt != 0 ) {	/* chasing referrals */
736
737
			ber_free( ber, 1 );
			ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
738
739
740
			if ( refer_cnt < 0 ) {
				return( -1 );	/* fatal error */
			}
741
			lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
742
743
744
745
746
747
		} else {
			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
				/* request without any referrals */
				simple_request = ( hadref ? 0 : 1 );
			} else {
				/* request with referrals or child request */
748
749
				ber_free( ber, 1 );
				ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
750
751
			}

752
			lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */
Julius Enarusai's avatar
   
Julius Enarusai committed
753
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
754
755
756
			LDAP_LOG ( OPERATION, DETAIL1, 
				"read1msg: mark request completed, id = %d\n", 
				lr->lr_msgid, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
757
#else
758
759
			Debug( LDAP_DEBUG_TRACE,
			    "read1msg:  mark request completed, id = %d\n", lr->lr_msgid, 0, 0);
Julius Enarusai's avatar
   
Julius Enarusai committed
760
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
761
762
763
764
765
766
767
768
769
			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 */
				}
			}

770
			/* Check if all requests are finished, lr is now parent */
771
772
773
			tmplr = lr;
			if (tmplr->lr_status == LDAP_REQST_COMPLETED) {
				for(tmplr=lr->lr_child; tmplr != NULL; tmplr=tmplr->lr_refnext) {
774
775
				if( tmplr->lr_status != LDAP_REQST_COMPLETED) {
					break;
776
					}
777
778
779
780
781
				}
			}

			/* This is the parent request if the request has referrals */
			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL && tmplr == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
782
783
				id = lr->lr_msgid;
				tag = lr->lr_res_msgtype;
Julius Enarusai's avatar
   
Julius Enarusai committed
784
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
785
786
787
			LDAP_LOG ( OPERATION, DETAIL1, 
				"read1msg: request %ld done\n", (long) id, 0, 0 );
			LDAP_LOG ( OPERATION, DETAIL1, 
Julius Enarusai's avatar
   
Julius Enarusai committed
788
789
				"read1msg: res_errno: %d,res_error: <%s>, res_matched: <%s>\n",
				lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
Julius Enarusai's avatar
   
Julius Enarusai committed
790
				lr->lr_res_matched ? lr->lr_res_matched : "" );
Julius Enarusai's avatar
   
Julius Enarusai committed
791
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
792
				Debug( LDAP_DEBUG_ANY, "request %ld done\n",
Hallvard Furuseth's avatar
Hallvard Furuseth committed
793
				    (long) id, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
794
795
796
797
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 : "" );
Julius Enarusai's avatar
   
Julius Enarusai committed
798
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
799
				if ( !simple_request ) {
800
801
					ber_free( ber, 1 );
					ber = NULL;
802
					if ( build_result_ber( ld, &ber, lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
803
804
805
806
807
					    == LBER_ERROR ) {
						rc = -1; /* fatal error */
					}
				}

808
				ldap_free_request( ld, lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
809
810
811
			}

			if ( lc != NULL ) {
812
				ldap_free_connection( ld, lc, 0, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
813
814
815
816
			}
		}
	}

817
	if ( ber == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
818
819
820
821
		return( rc );
	}

	/* make a new ldap message */
822
	if ( (new = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) ))
Kurt Zeilenga's avatar
Kurt Zeilenga committed
823
824
825
826
827
828
	    == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return( -1 );
	}
	new->lm_msgid = (int)id;
	new->lm_msgtype = tag;
829
	new->lm_ber = ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
830

831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
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
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
#ifdef LDAP_CONNECTIONLESS
	/* CLDAP replies all fit in a single datagram. In LDAPv2 RFC1798
	 * the responses are all a sequence wrapped in one message. In
	 * LDAPv3 each response is in its own message. The datagram must
	 * end with a SearchResult. We can't just parse each response in
	 * separate calls to try_read1msg because the header info is only
	 * present at the beginning of the datagram, not at the beginning
	 * of each response. So parse all the responses at once and queue
	 * them up, then pull off the first response to return to the
	 * caller when all parsing is complete.
	 */
	if ( LDAP_IS_UDP(ld) ) {
		/* If not a result, look for more */
		if ( tag != LDAP_RES_SEARCH_RESULT ) {
			int ok = 0;
			moremsgs = 1;
			if (isv2) {
				/* LDAPv2: dup the current ber, skip past the current
				 * response, and see if there are any more after it.
				 */
				ber = ber_dup( ber );
				ber_scanf( ber, "x" );
				if (ber_peek_tag(ber, &len) != LBER_DEFAULT) {
					/* There's more - dup the ber buffer so they can all be
					 * individually freed by ldap_msgfree.
					 */
					struct berval bv;
					ber_get_option(ber, LBER_OPT_BER_REMAINING_BYTES, &len);
					bv.bv_val = LDAP_MALLOC(len);
					if (bv.bv_val) {
						ok=1;
						ber_read(ber, bv.bv_val, len);
						bv.bv_len = len;
						ber_init2(ber, &bv, ld->ld_lberoptions );
					}
				}
			} else {
				/* LDAPv3: Just allocate a new ber. Since this is a buffered
				 * datagram, if the sockbuf is readable we still have data
				 * to parse.
				 */
				ber = ldap_alloc_ber_with_options(ld);
				if (ber_sockbuf_ctrl(sb, LBER_SB_OPT_DATA_READY, NULL)) ok=1;
			}
			/* set up response chain */
			if ( firstmsg ) {
				firstmsg = 0;
				new->lm_next = ld->ld_responses;
				ld->ld_responses = new;
			} else {
				tmp->lm_chain = new;
			}
			tmp = new;
			/* "ok" means there's more to parse */
			if (ok) {
				if (isv2) goto nextresp2;
				else goto nextresp3;
			} else {
				/* got to end of datagram without a SearchResult. Free
				 * our dup'd ber, but leave any buffer alone. For v2 case,
				 * the previous response is still using this buffer. For v3,
				 * the new ber has no buffer to free yet.
				 */
				ber_free(ber, 0);
				return -1;
			}
		} else if ( moremsgs ) {
		/* got search result, and we had multiple responses in 1 datagram.
		 * stick the result onto the end of the chain, and then pull the
		 * first response off the head of the chain.
		 */
			tmp->lm_chain = new;
			*result = chkResponseList( ld, msgid, all );
			ld->ld_errno = LDAP_SUCCESS;
			return( (*result)->lm_msgtype );
		}
	}
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
909
910
911

	/* is this the one we're looking for? */
	if ( msgid == LDAP_RES_ANY || id == msgid ) {
912
		if ( all == LDAP_MSG_ONE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
913
		    || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
914
915
		    && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY
		    && new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
916
917
918
919
920
921
922
923
924
925
926
927
928
929
			*result = new;
			ld->ld_errno = LDAP_SUCCESS;
			return( tag );
		} else if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
			foundit = 1;	/* return the chain later */
		}
	}

	/* 
	 * if not, we must add it to the list of responses.  if
	 * the msgid is already there, it must be part of an existing
	 * search response.
	 */

930
931
	prev = NULL;
	for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
932
933
934
935
936
937
		if ( l->lm_msgid == new->lm_msgid )
			break;
		prev = l;
	}

	/* not part of an existing search response */
938
	if ( l == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
939
940
		if ( foundit ) {
			*result = new;
941
			goto exit;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
942
943
944
945
		}

		new->lm_next = ld->ld_responses;
		ld->ld_responses = new;
946
		goto exit;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
947
948
	}

Julius Enarusai's avatar
   
Julius Enarusai committed
949
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
950
	LDAP_LOG ( OPERATION, DETAIL1, 
Julius Enarusai's avatar
   
Julius Enarusai committed
951
		"read1msg: adding response id %ld type %ld\n",
Julius Enarusai's avatar
   
Julius Enarusai committed
952
		(long) new->lm_msgid, (long) new->lm_msgtype, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
953
#else
Hallvard Furuseth's avatar
Hallvard Furuseth committed
954
955
	Debug( LDAP_DEBUG_TRACE, "adding response id %ld type %ld:\n",
	    (long) new->lm_msgid, (long) new->lm_msgtype, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
956
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
957
958

	/* part of a search response - add to end of list of entries */
959
960
	for ( tmp = l; (tmp->lm_chain != NULL) &&
	    	((tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY) ||
961
	    	 (tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE) ||
962
			 (tmp->lm_chain->lm_msgtype == LDAP_RES_INTERMEDIATE ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
963
964
965
966
967
968
	    tmp = tmp->lm_chain )
		;	/* NULL */
	tmp->lm_chain = new;

	/* return the whole chain if that's what we were looking for */
	if ( foundit ) {
969
		if ( prev == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
970
971
972
973
974
975
			ld->ld_responses = l->lm_next;
		else
			prev->lm_next = l->lm_next;
		*result = l;
	}

976
exit:
977
978
979
980
	if ( foundit ) {
		ld->ld_errno = LDAP_SUCCESS;
		return( tag );
	}
981
982
983
	if ( ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
		goto retry;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
984
985
986
987
	return( -2 );	/* continue looking */
}


988
static ber_tag_t
989
build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
990
{
991
	ber_len_t	len;
Howard Chu's avatar
Howard Chu committed
992
	ber_tag_t	tag;
993
	ber_int_t	along;
994
995
	BerElement *ber;

996
997
	*bp = NULL;
	ber = ldap_alloc_ber_with_options( ld );
998
999

	if( ber == NULL ) {
1000
		ld->ld_errno = LDAP_NO_MEMORY;
For faster browsing, not all history is shown. View entire blame