result.c 32.2 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-2006 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.
 */
40
/* Portions Copyright (C) The Internet Society (1997)
41
42
 * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
43

44
45
46
47
48
49
50
51
52
53
54
55
/*
 * 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)
 */

56
57
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
58
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
59
60

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

62
63
64
65
66
#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
67

Kurt Zeilenga's avatar
Kurt Zeilenga committed
68
#include "ldap-int.h"
Julius Enarusai's avatar
   
Julius Enarusai committed
69
#include "ldap_log.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
70

71
72
73
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,
74
	LDAPMessage **result ));
75
static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
76
	int all, LDAPConn **lc, LDAPMessage **result ));
77
static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr ));
78
static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));
79
static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
80

Kurt Zeilenga's avatar
Kurt Zeilenga committed
81
82
#define LDAP_MSG_X_KEEP_LOOKING		(-2)

Kurt Zeilenga's avatar
Kurt Zeilenga committed
83
84
85

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

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

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

118
119
120
121
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
#endif
	lm = chkResponseList(ld, msgid, all);
122
123

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

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

150
	Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
151
		"ldap_chkResponseList ld %p msgid %d all %d\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
152
		(void *)ld, msgid, all );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
153
	lastlm = &ld->ld_responses;
154
	for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
155
156
157
		nextlm = lm->lm_next;

		if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
158
159
			Debug( LDAP_DEBUG_TRACE,
				"ldap_chkResponseList msg abandoned, msgid %d\n",
160
			    msgid, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
161
162
			ldap_mark_abandoned( ld, lm->lm_msgid );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
163
164
			/* Remove this entry from list */
			*lastlm = nextlm;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
165
166
167
168
169
170
171
172
173

			ldap_msgfree( lm );

			continue;
		}

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
174
175
			if ( all == LDAP_MSG_ONE || all == LDAP_MSG_RECEIVED ||
				msgid == LDAP_RES_UNSOLICITED ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
176
				break;
177
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
178

Kurt Zeilenga's avatar
Kurt Zeilenga committed
179
180
181
182
183
			tmp = lm->lm_chain_tail;
			if ((tmp->lm_msgtype == LDAP_RES_SEARCH_ENTRY) ||
				(tmp->lm_msgtype == LDAP_RES_SEARCH_REFERENCE) ||
				(tmp->lm_msgtype == LDAP_RES_INTERMEDIATE)) {
				tmp = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
184
185
			}

186
			if ( tmp == NULL ) {
187
				lm = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
188
189
190
191
			}

			break;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
192
		lastlm = &lm->lm_next;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
193
	}
194

195
    if ( lm != NULL ) {
196
		/* Found an entry, remove it from the list */
197
	    if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
198
			*lastlm = lm->lm_chain;
199
200
201
202
			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;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
203
204
205
	    } else {
			*lastlm = lm->lm_next;
		}
206
207
	    lm->lm_next = NULL;
    }
208
209
210

#ifdef LDAP_DEBUG
	if( lm == NULL) {
211
		Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
212
			"ldap_chkResponseList returns ld %p NULL\n", (void *)ld, 0, 0);
213
	} else {
214
		Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
215
			"ldap_chkResponseList returns ld %p msgid %d, type 0x%02lu\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
216
			(void *)ld, lm->lm_msgid, (unsigned long) lm->lm_msgtype);
217
218
	}
#endif
219
    return lm;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
220
}
221

Kurt Zeilenga's avatar
Kurt Zeilenga committed
222
static int
223
224
225
226
227
wait4msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
	struct timeval *timeout,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
228
229
230
	LDAPMessage **result )
{
	int		rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
231
232
233
	struct timeval	tv = { 0 },
			tv0 = { 0 },
			*tvp;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
234
235
	time_t		start_time = 0;
	time_t		tmp_time;
236
	LDAPConn	*lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
237

Kurt Zeilenga's avatar
Kurt Zeilenga committed
238
239
240
	assert( ld != NULL );
	assert( result != NULL );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
241
242
#ifdef LDAP_DEBUG
	if ( timeout == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
243
		Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (infinite timeout)\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
244
			(void *)ld, msgid, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
245
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
246
		Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (timeout %ld usec)\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
247
			(void *)ld, msgid, (long)timeout->tv_sec * 1000000 + timeout->tv_usec );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
248
249
250
251
252
253
	}
#endif /* LDAP_DEBUG */

	if ( timeout == NULL ) {
		tvp = NULL;
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
254
		tv0 = *timeout;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
255
256
		tv = *timeout;
		tvp = &tv;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
		start_time = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
258
259
	}
		    
Kurt Zeilenga's avatar
Kurt Zeilenga committed
260
261
	rc = LDAP_MSG_X_KEEP_LOOKING;
	while ( rc == LDAP_MSG_X_KEEP_LOOKING ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
262
263
#ifdef LDAP_DEBUG
		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
264
			Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
265
				(void *)ld, msgid, all );
266
267
			ldap_dump_connection( ld, ld->ld_conns, 1 );
			ldap_dump_requests_and_responses( ld );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
268
269
270
		}
#endif /* LDAP_DEBUG */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
271
272
273
274
        	if ( (*result = chkResponseList(ld, msgid, all)) != NULL ) {
			rc = (*result)->lm_msgtype;

		} else {
275
			int lc_ready = 0;
276

Kurt Zeilenga's avatar
Kurt Zeilenga committed
277
278
279
#ifdef LDAP_R_COMPILE
			ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
280
			for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
281
282
				if ( ber_sockbuf_ctrl( lc->lconn_sb,
						LBER_SB_OPT_DATA_READY, NULL ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
283
284
285
#ifdef LDAP_R_COMPILE
					ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
286
					rc = try_read1msg( ld, msgid, all, &lc, result );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
287
288
289
#ifdef LDAP_R_COMPILE
					ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
290
					lc_ready = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
291
					break;
292
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
293
294
295
296
			}
#ifdef LDAP_R_COMPILE
			ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
297

Kurt Zeilenga's avatar
Kurt Zeilenga committed
298
		    	if ( !lc_ready ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
299
				rc = ldap_int_select( ld, tvp );
300
#ifdef LDAP_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
301
302
303
304
305
				if ( rc == -1 ) {
					Debug( LDAP_DEBUG_TRACE,
						"ldap_int_select returned -1: errno %d\n",
						errno, 0, 0 );
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
306
307
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
308
309
310
311
312
313
314
315
316
317
				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 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
318
					rc = LDAP_MSG_X_KEEP_LOOKING;	/* select interrupted: loop */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
319
				} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
320
					rc = LDAP_MSG_X_KEEP_LOOKING;
321
#ifdef LDAP_R_COMPILE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
322
					ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
323
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
324
					if ( ld->ld_requests &&
325
326
						ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
						ldap_is_write_ready( ld,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
327
328
							ld->ld_requests->lr_conn->lconn_sb ) )
					{
329
330
						ldap_int_flush_request( ld, ld->ld_requests );
					}
331
#ifdef LDAP_R_COMPILE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
332
					ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
333
					ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
334
#endif
335
					for ( lc = ld->ld_conns;
336
						rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
337
338
339
340
					{
						if ( lc->lconn_status == LDAP_CONNST_CONNECTED &&
							ldap_is_read_ready( ld, lc->lconn_sb ))
						{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
341
342
343
#ifdef LDAP_R_COMPILE
							ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
344
							rc = try_read1msg( ld, msgid, all, &lc, result );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
345
346
347
#ifdef LDAP_R_COMPILE
							ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
348
349
350
351
352
353
354
							if ( lc == NULL ) {
								/* if lc gets free()'d,
								 * there's no guarantee
								 * lc->lconn_next is still
								 * sane; better restart
								 * (ITS#4405) */
								lc = ld->ld_conns;
355
356
357

								/* don't get to next conn! */
								break;
358
							}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
359
						}
360
361
362

						/* next conn */
						lc = lc->lconn_next;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
363
					}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
364
365
366
#ifdef LDAP_R_COMPILE
					ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
367
368
				}
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
369
370
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
371
		if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
372
			tmp_time = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
373
374
			tv0.tv_sec -= ( tmp_time - start_time );
			if ( tv0.tv_sec <= 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
375
376
377
378
				rc = 0;	/* timed out */
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
379
			tv.tv_sec = tv0.tv_sec;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
380

Kurt Zeilenga's avatar
Kurt Zeilenga committed
381
			Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld secs to go\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
382
				(void *)ld, (long) tv.tv_sec, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
383
384
385
386
			start_time = tmp_time;
		}
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
387
	return( rc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
388
389
390
}


391
392
393
394
395
static ber_tag_t
try_read1msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
396
	LDAPConn **lcp,
397
	LDAPMessage **result )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
398
{
399
	BerElement	*ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
400
	LDAPMessage	*newmsg, *l, *prev;
401
402
403
	ber_int_t	id;
	ber_tag_t	tag;
	ber_len_t	len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
404
	int		foundit = 0;
405
	LDAPRequest	*lr, *tmplr;
406
	LDAPConn	*lc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
407
408
	BerElement	tmpber;
	int		rc, refer_cnt, hadref, simple_request;
409
	ber_int_t	lderr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
410

411
#ifdef LDAP_CONNECTIONLESS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
412
	LDAPMessage	*tmp = NULL, *chain_head = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
413
	int		moremsgs = 0, isv2 = 0;
414
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
415

416
417
418
419
	/*
	 * v3ref = flag for V3 referral / search reference
	 * 0 = not a ref, 1 = sucessfully chased ref, -1 = pass ref to application
	 */
420
421
422
423
424
	enum {
		V3REF_NOREF	= 0,
		V3REF_SUCCESS	= 1,
		V3REF_TOAPP	= -1
	}	v3ref;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
425
426

	assert( ld != NULL );
427
428
	assert( lcp != NULL );
	assert( *lcp != NULL );
429
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
430
431
	Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n",
		(void *)ld, msgid, all );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
432

433
434
	lc = *lcp;

435
retry:
436
	if ( lc->lconn_ber == NULL ) {
437
438
439
440
441
		lc->lconn_ber = ldap_alloc_ber_with_options(ld);

		if( lc->lconn_ber == NULL ) {
			return -1;
		}
442
	}
443
444

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
447
	/* get the next message */
448
	errno = 0;
449
450
451
#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP(ld) ) {
		struct sockaddr from;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
452
		ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr) );
453
		if (ld->ld_options.ldo_version == LDAP_VERSION2) isv2=1;
454
	}
455
nextresp3:
456
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
457
	tag = ber_get_next( lc->lconn_sb, &len, ber );
458
459
460
461
462
463
464
465
	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 ) {
466
467
468
		if ( tag == LBER_DEFAULT) {
#ifdef LDAP_DEBUG		   
			Debug( LDAP_DEBUG_CONNS,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
469
				"ber_get_next failed.\n", 0, 0, 0 );
470
471
#endif		   
#ifdef EWOULDBLOCK			
Kurt Zeilenga's avatar
Kurt Zeilenga committed
472
			if (errno==EWOULDBLOCK) return LDAP_MSG_X_KEEP_LOOKING;
473
474
#endif
#ifdef EAGAIN
Kurt Zeilenga's avatar
Kurt Zeilenga committed
475
			if (errno == EAGAIN) return LDAP_MSG_X_KEEP_LOOKING;
476
477
478
479
480
481
#endif
			ld->ld_errno = LDAP_SERVER_DOWN;
			return -1;
		}
		ld->ld_errno = LDAP_LOCAL_ERROR;
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
482
483
484
	}

	/* message id */
485
	if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
486
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
487
488
489
490
491
		ld->ld_errno = LDAP_DECODING_ERROR;
		return( -1 );
	}

	/* if it's been abandoned, toss it */
492
	if ( ldap_abandoned( ld, id ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
493
		Debug( LDAP_DEBUG_ANY, "abandoned ld %p msgid %ld\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
494
			(void *)ld, (long) id, 0);
495
retry_ber:
496
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
497
		if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
498
			goto retry;
499
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
500
		return( LDAP_MSG_X_KEEP_LOOKING );	/* continue looking */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
501
502
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
503
504
	lr = ldap_find_request_by_msgid( ld, id );
	if ( lr == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
505
		Debug( LDAP_DEBUG_ANY,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
506
507
			"no request for response on ld %p msgid %ld (tossing)\n",
			(void *)ld, (long) id, 0 );
508
		goto retry_ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
509
	}
510
#ifdef LDAP_CONNECTIONLESS
511
512
	if (LDAP_IS_UDP(ld) && isv2) {
		ber_scanf(ber, "x{");
513
	}
Howard Chu's avatar
Howard Chu committed
514
nextresp2:
515
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
516
	/* the message type */
517
	if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
518
		ld->ld_errno = LDAP_DECODING_ERROR;
519
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
520
521
522
		return( -1 );
	}

523
	Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
524
		"read1msg: ld %p msgid %ld message type %s\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
525
		(void *)ld, (long) lr->lr_msgid, ldap_int_msgtype2str( tag ));
526
527

	id = lr->lr_origid;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
528
529
	refer_cnt = 0;
	hadref = simple_request = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
530
	rc = LDAP_MSG_X_KEEP_LOOKING;	/* default is to keep looking (no response found) */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
531
532
	lr->lr_res_msgtype = tag;

533
534
535
536
	/*
	 * This code figures out if we are going to chase a
	 * referral / search reference, or pass it back to the application
	 */
537
	v3ref = V3REF_NOREF;	/* Assume not a V3 search reference/referral */
538
539
540
541
	if( (tag != LDAP_RES_SEARCH_ENTRY) && (ld->ld_version > LDAP_VERSION2) ) {
		BerElement	tmpber = *ber; 	/* struct copy */
		char **refs = NULL;

542
		if( tag == LDAP_RES_SEARCH_REFERENCE ) {
543
			/* This is a V3 search reference */
544
545
546
			/* Assume we do not chase the reference,
			 * but pass it to application */
			v3ref = V3REF_TOAPP;
547
548
549
550
551
552
553
			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 {
554
					/* Note: refs array is freed by ldap_chase_v3referrals */
555
					refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
556
					    1, &lr->lr_res_error, &hadref );
557
558
					if ( refer_cnt > 0 ) {
						/* sucessfully chased reference */
559
560
561
562
						/* If haven't got end search, set chasing referrals */
						if( lr->lr_status != LDAP_REQST_COMPLETED) {
							lr->lr_status = LDAP_REQST_CHASINGREFS;
							Debug( LDAP_DEBUG_TRACE,
563
564
565
566
								"read1msg:  search ref chased, "
								"mark request chasing refs, "
								"id = %d\n",
								lr->lr_msgid, 0, 0);
567
						}
568
569
570

						/* We sucessfully chased the reference */
						v3ref = V3REF_SUCCESS;
571
572
573
574
575
					}
				}
			}
		} else {
			/* Check for V3 referral */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
576
577
578
			ber_len_t	len;
			char		*lr_res_error = NULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
579
580
581
582
583
#ifdef LDAP_NULL_IS_NULL
			if ( ber_scanf( &tmpber, "{eAA",/*}*/ &lderr,
				    &lr->lr_res_matched, &lr_res_error )
				    != LBER_ERROR )
#else /* ! LDAP_NULL_IS_NULL */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
584
			if ( ber_scanf( &tmpber, "{eaa",/*}*/ &lderr,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
585
586
				    &lr->lr_res_matched, &lr_res_error )
				    != LBER_ERROR )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
587
#endif /* ! LDAP_NULL_IS_NULL */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
588
589
			{
				if ( lr_res_error != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
590
591
592
593
594
595
596
597
598
599
#ifndef LDAP_NULL_IS_NULL
					if ( lr_res_error[ 0 ] == '\0' ) {
						LDAP_FREE( lr_res_error );
						lr_res_error = NULL;
					} else
#endif /* ! LDAP_NULL_IS_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 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
600

Kurt Zeilenga's avatar
Kurt Zeilenga committed
601
602
603
						} else {
							lr->lr_res_error = lr_res_error;
						}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
604
					}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
605
					lr_res_error = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
606
607
				}

608
				/* Check if V3 referral */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
609
				if ( ber_peek_tag( &tmpber, &len ) == LDAP_TAG_REFERRAL ) {
610
					/* We have a V3 referral, assume we cannot chase it */
611
					v3ref = V3REF_TOAPP;
612
613
614
					if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS)
							 || (lr->lr_parent != NULL) )
					{
615
616
617
						/* Assume referral not chased and return it to app */
						v3ref = V3REF_TOAPP;

618
						/* Get the referral list */
619
						if( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) {
620
621
622
							rc = LDAP_DECODING_ERROR;
							lr->lr_status = LDAP_REQST_COMPLETED;
							Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
623
624
								"read1msg: referral decode error, mark request completed, ld %p msgid %d\n",
								(void *)ld, lr->lr_msgid, 0);
625
626
627
628
629
						} else {
							/* Chase the referral 
							 * Note: refs arrary is freed by ldap_chase_v3referrals
							 */
							refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
630
							    0, &lr->lr_res_error, &hadref );
631
632
							lr->lr_status = LDAP_REQST_COMPLETED;
							Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
633
634
								"read1msg: referral chased, mark request completed, ld %p msgid %d\n",
								(void *)ld, lr->lr_msgid, 0);
635
							if( refer_cnt > 0) {
636
637
								/* Referral successfully chased */
								v3ref = V3REF_SUCCESS;
638
639
640
641
							}
						}
					}
				}
642
643
644
645
646
647
648
649
650

				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;
				}
651
652
653
654
655
656
657
658
			}
		}
	}

	/* 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.
	 */
659
	if ( (tag != LDAP_RES_SEARCH_ENTRY) && (v3ref != V3REF_TOAPP) &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
660
661
		(tag != LDAP_RES_INTERMEDIATE ))
	{
662
		/* For a v3 search referral/reference, only come here if already chased it */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
663
		if ( ld->ld_version >= LDAP_VERSION2 &&
664
			( lr->lr_parent != NULL ||
665
			LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ) )
666
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
667
668
			char		*lr_res_error = NULL;

669
			tmpber = *ber;	/* struct copy */
670
			if ( v3ref == V3REF_SUCCESS ) {
671
672
673
674
675
676
677
				/* 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;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
678
679
680
681
682
#ifdef LDAP_NULL_IS_NULL
			} else if ( ber_scanf( &tmpber, "{eAA}", &lderr,
				&lr->lr_res_matched, &lr_res_error )
				!= LBER_ERROR )
#else /* ! LDAP_NULL_IS_NULL */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
683
			} else if ( ber_scanf( &tmpber, "{eaa}", &lderr,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
684
685
				&lr->lr_res_matched, &lr_res_error )
				!= LBER_ERROR )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
686
#endif /* ! LDAP_NULL_IS_NULL */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
687
688
			{
				if ( lr_res_error != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
689
690
691
692
693
694
695
696
697
698
699
700
#ifndef LDAP_NULL_IS_NULL
					if ( lr_res_error[ 0 ] == '\0' ) {
						LDAP_FREE( lr_res_error );
					} else
#endif /* ! LDAP_NULL_IS_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 );
						} else {
							lr->lr_res_error = lr_res_error;
						}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
701
					}
702
					lr_res_error = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
703
704
				}

705
706
707
708
709
710
711
712
713
714
715
716
717
				switch ( lderr ) {
				case LDAP_SUCCESS:
				case LDAP_COMPARE_TRUE:
				case LDAP_COMPARE_FALSE:
					break;

				default:
					if ( lr->lr_res_error == NULL
						|| lr->lr_res_error[ 0 ] == '\0' )
					{
						break;
					}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
718
					/* referrals are in error string */
719
					refer_cnt = ldap_chase_referrals( ld, lr,
720
						&lr->lr_res_error, -1, &hadref );
721
722
					lr->lr_status = LDAP_REQST_COMPLETED;
					Debug( LDAP_DEBUG_TRACE,
723
724
725
726
						"read1msg:  V2 referral chased, "
						"mark request completed, id = %d\n",
						lr->lr_msgid, 0, 0 );
					break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
727
728
729
730
731
732
733
734
735
736
737
738
				}

				/* 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;
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
739
740
741
742
743
744
745
746
747
748
749
750
751

				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 : "" );
			}

			/* 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
752
753
754
755
			}
		}

		Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
756
757
			"read1msg: ld %p %d new referrals\n",
			(void *)ld, refer_cnt, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
758
759

		if ( refer_cnt != 0 ) {	/* chasing referrals */
760
761
			ber_free( ber, 1 );
			ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
762
763
764
			if ( refer_cnt < 0 ) {
				return( -1 );	/* fatal error */
			}
765
			lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
766
767
768
769
770
771
		} 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 */
772
773
				ber_free( ber, 1 );
				ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
774
775
			}

776
777
			lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */
			Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
778
779
				"read1msg:  mark request completed, ld %p msgid %d\n",
				(void *)ld, lr->lr_msgid, 0);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
780
781
782
783
784
785
786
787
788
			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 */
				}
			}

789
			/* Check if all requests are finished, lr is now parent */
790
791
			tmplr = lr;
			if (tmplr->lr_status == LDAP_REQST_COMPLETED) {
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
792
793
794
795
796
				for ( tmplr=lr->lr_child;
					tmplr != NULL;
					tmplr=tmplr->lr_refnext)
				{
					if( tmplr->lr_status != LDAP_REQST_COMPLETED) break;
797
798
799
800
				}
			}

			/* This is the parent request if the request has referrals */
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
801
802
803
			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL &&
				tmplr == NULL )
			{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
804
805
				id = lr->lr_msgid;
				tag = lr->lr_res_msgtype;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
806
				Debug( LDAP_DEBUG_ANY, "request done: ld %p msgid %ld\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
807
					(void *)ld, (long) id, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
808
809
810
811
812
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 : "" );
				if ( !simple_request ) {
813
814
					ber_free( ber, 1 );
					ber = NULL;
815
					if ( build_result_ber( ld, &ber, lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
816
817
818
819
820
					    == LBER_ERROR ) {
						rc = -1; /* fatal error */
					}
				}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
821
822
823
#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
824
				ldap_free_request( ld, lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
825
826
827
#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
828
829
830
			}

			if ( lc != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
831
832
833
#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
834
				ldap_free_connection( ld, lc, 0, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
835
836
837
#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
838
				lc = *lcp = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
839
840
841
842
			}
		}
	}

843
	if ( ber == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
844
845
846
847
		return( rc );
	}

	/* make a new ldap message */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
848
849
	newmsg = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) );
	if ( newmsg == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
850
851
852
		ld->ld_errno = LDAP_NO_MEMORY;
		return( -1 );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
853
854
855
	newmsg->lm_msgid = (int)id;
	newmsg->lm_msgtype = tag;
	newmsg->lm_ber = ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
856
	newmsg->lm_chain_tail = newmsg;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
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
#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.
				 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
899
900
				ber = ldap_alloc_ber_with_options( ld );
				if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) ok = 1;
901
902
			}
			/* set up response chain */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
903
			if ( tmp == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
904
905
906
				newmsg->lm_next = ld->ld_responses;
				ld->ld_responses = newmsg;
				chain_head = newmsg;
907
			} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
908
				tmp->lm_chain = newmsg;
909
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
910
			chain_head->lm_chain_tail = newmsg;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
911
			tmp = newmsg;
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
			/* "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.
		 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
930
			tmp->lm_chain = newmsg;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
931
			chain_head->lm_chain_tail = newmsg;
932
933
934
935
936
			*result = chkResponseList( ld, msgid, all );
			ld->ld_errno = LDAP_SUCCESS;
			return( (*result)->lm_msgtype );
		}
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
937
#endif /* LDAP_CONNECTIONLESS */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
938
939
940

	/* is this the one we're looking for? */
	if ( msgid == LDAP_RES_ANY || id == msgid ) {
941
		if ( all == LDAP_MSG_ONE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
942
943
944
945
		    || (newmsg->lm_msgtype != LDAP_RES_SEARCH_RESULT
		    && newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY
		    && newmsg->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) ) {
			*result = newmsg;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
946
947
			ld->ld_errno = LDAP_SUCCESS;
			return( tag );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
948
		} else if ( newmsg->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
949
950
951
952
953
954
955
956
957
958
			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.
	 */

959
960
	prev = NULL;
	for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
961
		if ( l->lm_msgid == newmsg->lm_msgid )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
962
963
964
965
966
			break;
		prev = l;
	}

	/* not part of an existing search response */
967
	if ( l == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
968
		if ( foundit ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
969
			*result = newmsg;
970
			goto exit;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
971
972
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
973
974
		newmsg->lm_next = ld->ld_responses;
		ld->ld_responses = newmsg;
975
		goto exit;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
976
977
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
978
	Debug( LDAP_DEBUG_TRACE, "adding response ld %p msgid %ld type %ld:\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
979
		(void *)ld, (long) newmsg->lm_msgid, (long) newmsg->lm_msgtype );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
980
981

	/* part of a search response - add to end of list of entries */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
982
983
	l->lm_chain_tail->lm_chain = newmsg;
	l->lm_chain_tail = newmsg;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
984
985
986

	/* return the whole chain if that's what we were looking for */
	if ( foundit ) {
987
		if ( prev == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
988
989
990
991
992
993
			ld->ld_responses = l->lm_next;
		else
			prev->lm_next = l->lm_next;
		*result = l;
	}

994
exit:
995
996
997
998
	if ( foundit ) {
		ld->ld_errno = LDAP_SUCCESS;
		return( tag );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
999
	if ( lc && ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
1000
1001
		goto retry;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1002
	return( LDAP_MSG_X_KEEP_LOOKING );	/* continue looking */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1003
1004
1005
}


1006
static ber_tag_t
1007
build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1008
{
1009
	ber_len_t	len;
Howard Chu's avatar
Howard Chu committed
1010
	ber_tag_t	tag;
1011
	ber_int_t	along;
1012
1013
	BerElement *ber;

1014
1015
	*bp = NULL;
	ber = ldap_alloc_ber_with_options( ld );
1016
1017

	if( ber == NULL ) {
1018
		ld->ld_errno = LDAP_NO_MEMORY;
1019
1020
		return LBER_ERROR;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1021
1022

	if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1023
1024
1025
1026
		lr->lr_res_msgtype, lr->lr_res_errno,
		lr->lr_res_matched ? lr->lr_res_matched : "",
		lr->lr_res_error ? lr->lr_res_error : "" ) == -1 )
	{
1027
		ld->ld_errno = LDAP_ENCODING_ERROR;
1028
		ber_free(ber, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1029
1030
1031
1032
		return( LBER_ERROR );
	}

	ber_reset( ber, 1 );
1033

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1034
	if ( ber_skip_tag( ber, &len ) ==