result.c 32.1 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.
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
24
25
26
 */
/*---
 * 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. 
 *---
 * 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
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
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.
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34

35
36
37
38
39
40
41
42
43
44
45
/*
 * 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)
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
46
47

#include "portable.h"
48
49
50
51
52
53
54
55
56
57
58

#include <stdio.h>

#include <ac/stdlib.h>

#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
59
#include "ldap-int.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
60
#include "ldap_log.h"
61
62
63
64
65
66
67
68
69
70

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,
	LDAPMessage **result ));
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 ));
static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));
static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
71
72
73
74


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

101
102
103
104
	assert( ld != NULL );
	assert( result != NULL );

#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
105
	LDAP_LOG ( OPERATION, ARGS, "ldap_result msgid %d\n", msgid, 0, 0 );
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#else
	Debug( LDAP_DEBUG_TRACE, "ldap_result msgid %d\n", msgid, 0, 0 );
#endif

    lm = chkResponseList(ld, msgid, all);

	if ( lm == NULL ) {
		return( wait4msg( ld, msgid, all, timeout, result ) );
	}

	*result = lm;
	ld->ld_errno = LDAP_SUCCESS;
	return( lm->lm_msgtype );
}

static LDAPMessage *
chkResponseList(
	LDAP *ld,
	int msgid,
	int all)
{
	LDAPMessage	*lm, *lastlm, *nextlm;
    /*
	 * Look through the list of responses we have received on
Kurt Zeilenga's avatar
Kurt Zeilenga committed
130
131
132
133
134
	 * 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.
	 */

135
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
136
137
	LDAP_LOG ( OPERATION, ARGS, "ldap_chkResponseList for msgid=%d, all=%d\n", 
		msgid, all, 0 );
138
139
140
141
142
143
144
#else
	Debug( LDAP_DEBUG_TRACE,
		"ldap_chkResponseList for msgid=%d, all=%d\n",
	    msgid, all, 0 );
#endif
	lastlm = NULL;
	for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
145
146
147
		nextlm = lm->lm_next;

		if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
148
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
149
150
			LDAP_LOG ( OPERATION, DETAIL1, 
				"ldap_chkResponseList msg abandoned, msgid %d\n", msgid, 0, 0 );
151
152
153
154
155
#else
			Debug( LDAP_DEBUG_TRACE,
				"ldap_chkResponseList msg abandoned, msgid %d\n",
			    msgid, 0, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
156
157
			ldap_mark_abandoned( ld, lm->lm_msgid );

158
159
			if ( lastlm == NULL ) {
				/* Remove first entry in list */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
160
161
162
163
164
165
166
167
168
169
170
171
172
				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;

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

177
178
179
180
181
			for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
				if ( tmp->lm_msgtype != LDAP_RES_SEARCH_ENTRY
				    && tmp->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
					&& tmp->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL )
				{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
182
					break;
183
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
184
185
			}

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

			break;
		}
		lastlm = lm;
	}

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

#ifdef LDAP_DEBUG
	if( lm == NULL) {
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
214
215
		LDAP_LOG ( OPERATION, RESULTS, "ldap_chkResponseList returns NULL\n",
			0, 0, 0 );
216
217
218
219
#else
		Debug( LDAP_DEBUG_TRACE,
			"ldap_chkResponseList returns NULL\n", 0, 0, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
220
	} else {
221
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
222
223
224
		LDAP_LOG ( OPERATION, RESULTS, 
			"ldap_chkResponseList returns msgid %d, type 0x%02lu\n",
			lm->lm_msgid, (unsigned long) lm->lm_msgtype, 0 );
225
226
227
228
229
#else
		Debug( LDAP_DEBUG_TRACE,
			"ldap_chkResponseList returns msgid %d, type 0x%02lu\n",
			lm->lm_msgid, (unsigned long) lm->lm_msgtype, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
230
	}
231
232
#endif
    return lm;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
233
234
235
}

static int
236
237
238
239
240
wait4msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
	struct timeval *timeout,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
241
242
243
244
	LDAPMessage **result )
{
	int		rc;
	struct timeval	tv, *tvp;
245
246
	time_t		start_time = 0;
	time_t		tmp_time;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
247
	LDAPConn	*lc, *nextlc;
248
249
250

	assert( ld != NULL );
	assert( result != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
251
252
253

#ifdef LDAP_DEBUG
	if ( timeout == NULL ) {
254
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
255
256
		LDAP_LOG ( OPERATION, ARGS, 
			"wait4msg (infinite timeout), msgid %d\n", msgid, 0, 0 );
257
258
259
260
#else
		Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout), msgid %d\n",
		    msgid, 0, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
261
	} else {
262
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
263
		LDAP_LOG ( OPERATION, ARGS, 
264
			"wait4msg (timeout %ld sec, %ld usec), msgid %d\n", 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
265
			(long) timeout->tv_sec, (long) timeout->tv_usec, msgid );
266
267
268
269
#else
		Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec), msgid %d\n",
		       (long) timeout->tv_sec, (long) timeout->tv_usec, msgid );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
270
271
272
273
274
275
276
277
	}
#endif /* LDAP_DEBUG */

	if ( timeout == NULL ) {
		tvp = NULL;
	} else {
		tv = *timeout;
		tvp = &tv;
278
		start_time = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
279
280
281
282
	}
		    
	rc = -2;
	while ( rc == -2 ) {
283
284
#ifdef LDAP_DEBUG
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
285
286
		LDAP_LOG ( OPERATION, ARGS, 
			"wait4msg continue, msgid %d, all %d\n", msgid, all, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
287
#else
288
289
		Debug( LDAP_DEBUG_TRACE, "wait4msg continue, msgid %d, all %d\n",
		    msgid, all, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
290
291
#endif
		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
292
293
			ldap_dump_connection( ld, ld->ld_conns, 1 );
			ldap_dump_requests_and_responses( ld );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
294
295
296
		}
#endif /* LDAP_DEBUG */

297
298
299
        if( (*result = chkResponseList(ld, msgid, all)) != NULL ) {
            rc = (*result)->lm_msgtype;
        } else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
300

301
302
303
304
305
306
307
308
			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;
				}
	        }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
309

310
311
		    if ( lc == NULL ) {
			    rc = ldap_int_select( ld, tvp );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
312

313
314
315
316

#ifdef LDAP_DEBUG
			    if ( rc == -1 ) {
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
317
					LDAP_LOG ( OPERATION, ARGS, 
318
						"wait4msg: ldap_int_select returned -1: errno %d\n", 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
319
						errno, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
320
#else
321
322
323
324
325
			        Debug( LDAP_DEBUG_TRACE,
				        "ldap_int_select returned -1: errno %d\n",
				        errno, 0, 0 );
#endif
			    }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
326
327
#endif

328
329
330
331
332
333
334
335
336
337
338
339
340
			    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;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
341
342
343
344
345
346
				    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 );
					}
347
348
349
350
351
352
353
354
355
356
357
358
359
				    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
360
361
362
		}

		if ( rc == -2 && tvp != NULL ) {
363
			tmp_time = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
364
365
366
367
368
369
			if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
				rc = 0;	/* timed out */
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}

370
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
371
372
			LDAP_LOG ( OPERATION, DETAIL1, 
				"wait4msg: %ld secs to go\n", (long) tv.tv_sec, 0, 0 );
373
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
374
			Debug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
375
376
			       (long) tv.tv_sec, 0, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
377
378
379
380
381
382
383
384
			start_time = tmp_time;
		}
	}

	return( rc );
}


385
386
387
388
389
390
391
392
static ber_tag_t
try_read1msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
	Sockbuf *sb,
	LDAPConn *lc,
	LDAPMessage **result )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
393
{
394
	BerElement	*ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
395
	LDAPMessage	*new, *l, *prev, *tmp;
396
397
398
	ber_int_t	id;
	ber_tag_t	tag;
	ber_len_t	len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
399
	int		foundit = 0;
400
	LDAPRequest	*lr, *tmplr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
401
402
	BerElement	tmpber;
	int		rc, refer_cnt, hadref, simple_request;
403
	ber_int_t	lderr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
404
405
406
#ifdef LDAP_CONNECTIONLESS
	int		firstmsg = 1, moremsgs = 0, isv2 = 0;
#endif
407
408
409
410
411
412
413
414
415
416
	/*
	 * v3ref = flag for V3 referral / search reference
	 * 0 = not a ref, 1 = sucessfully chased ref, -1 = pass ref to application
	 */
	int     v3ref;

	assert( ld != NULL );
	assert( lc != NULL );
	
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
417
	LDAP_LOG ( OPERATION, ARGS, "read1msg: msgid %d, all %d\n", msgid, all, 0 );
418
419
420
#else
	Debug( LDAP_DEBUG_TRACE, "read1msg: msgid %d, all %d\n", msgid, all, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
421

422
retry:
423
424
425
426
427
428
429
    if ( lc->lconn_ber == NULL ) {
		lc->lconn_ber = ldap_alloc_ber_with_options(ld);

		if( lc->lconn_ber == NULL ) {
			return -1;
		}
    }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
430

431
432
	ber = lc->lconn_ber;
	assert( LBER_VALID (ber) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
433

434
retry2:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
435
	/* get the next message */
436
437
438
439
440
	errno = 0;
#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP(ld) ) {
		struct sockaddr from;
		ber_int_sb_read(sb, &from, sizeof(struct sockaddr));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
441
		if (ld->ld_options.ldo_version == LDAP_VERSION2) isv2=1;
442
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
443
nextresp3:
444
445
#endif
	if ( (tag = ber_get_next( sb, &len, ber ))
Kurt Zeilenga's avatar
Kurt Zeilenga committed
446
	    != LDAP_TAG_MESSAGE ) {
447
448
449
		if ( tag == LBER_DEFAULT) {
#ifdef LDAP_DEBUG		   
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
450
451
			LDAP_LOG ( OPERATION, DETAIL1, 
				"read1msg: ber_get_next failed\n", 0, 0, 0 );
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
#else
			Debug( LDAP_DEBUG_CONNS,
			      "ber_get_next failed.\n", 0, 0, 0 );
#endif		   
#endif		   
#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
468
469
	}

470
471
472
473
474
475
	/*
     * We read a complete message.
	 * The connection should no longer need this ber.
	 */
    lc->lconn_ber = NULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
476
	/* message id */
477
478
	if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
479
480
481
482
483
		ld->ld_errno = LDAP_DECODING_ERROR;
		return( -1 );
	}

	/* if it's been abandoned, toss it */
484
485
	if ( ldap_abandoned( ld, id ) ) {
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
486
		LDAP_LOG ( OPERATION, DETAIL1, "read1msg: abandoned\n", 0, 0, 0 );
487
488
489
#else
		Debug( LDAP_DEBUG_ANY, "abandoned\n", 0, 0, 0);
#endif
490
491
492
493
494
495
496
retry_ber:
		if ( ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
			ber_free_buf( ber );
			ber_init2( ber, NULL, ld->ld_lberoptions );
			goto retry2;
		}
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
497
498
499
		return( -2 );	/* continue looking */
	}

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

525
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
526
	LDAP_LOG ( OPERATION, DETAIL1, 
527
528
		"read1msg: ldap_read: message type %s msgid %ld, original id %ld\n",
	    ldap_int_msgtype2str( tag ),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
529
		(long) lr->lr_msgid, (long) lr->lr_origid );
530
531
532
533
534
535
536
537
#else
	Debug( LDAP_DEBUG_TRACE,
		"ldap_read: message type %s msgid %ld, original id %ld\n",
	    ldap_int_msgtype2str( tag ),
		(long) lr->lr_msgid, (long) lr->lr_origid );
#endif

	id = lr->lr_origid;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
538
539
540
541
542
	refer_cnt = 0;
	hadref = simple_request = 0;
	rc = -2;	/* default is to keep looking (no response found) */
	lr->lr_res_msgtype = tag;

543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
	/*
	 * 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,
					    1, &lr->lr_res_error, &hadref );
					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;
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
571
							LDAP_LOG ( OPERATION, DETAIL1, 
572
573
								"read1msg: search ref chased,"
								"mark request chasing refs, id =	%d\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
574
								lr->lr_msgid, 0, 0 );
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
#else
							Debug( LDAP_DEBUG_TRACE,
							    "read1msg:  search ref chased, mark request chasing refs, id = %d\n",
							    lr->lr_msgid, 0, 0);
#endif
						}
						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 */
						if( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) {
							rc = LDAP_DECODING_ERROR;
							lr->lr_status = LDAP_REQST_COMPLETED;
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
604
							LDAP_LOG ( OPERATION, DETAIL1, 
605
606
								"read1msg: referral decode error,"
								"mark request completed, id =	%d\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
607
								lr->lr_msgid, 0, 0 );
608
609
610
611
612
613
614
615
616
617
618
619
620
#else
							Debug( LDAP_DEBUG_TRACE,
							    "read1msg: referral decode error, mark request completed, id = %d\n",
								    lr->lr_msgid, 0, 0);
#endif
						} else {
							/* Chase the referral 
							 * Note: refs arrary is freed by ldap_chase_v3referrals
							 */
							refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
							    0, &lr->lr_res_error, &hadref );
							lr->lr_status = LDAP_REQST_COMPLETED;
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
621
							LDAP_LOG ( OPERATION, DETAIL1, 
622
623
								"read1msg: referral chased,"
								"mark request completed, id =	%d\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
624
								lr->lr_msgid, 0, 0 );
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
#else
							Debug( LDAP_DEBUG_TRACE,
							    "read1msg:  referral chased, mark request completed, id = %d\n",
							    lr->lr_msgid, 0, 0);
#endif
							if( refer_cnt > 0) {
								v3ref = 1;  /* Referral successfully chased */
							}
						}
					}
				}

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

	/* 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
Changes    
Kurt Zeilenga committed
653
654
655
656
657
	if ( (tag != LDAP_RES_SEARCH_ENTRY) && (v3ref > -1)
#ifdef LDAP_RES_INTERMEDIATE_RESP
		&& (tag != LDAP_RES_INTERMEDIATE_RESP )
#endif
	) {
658
		/* For a v3 search referral/reference, only come here if already chased it */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
659
		if ( ld->ld_version >= LDAP_VERSION2 &&
660
661
662
663
664
			( lr->lr_parent != NULL ||
			LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ) )
		{
			tmpber = *ber;	/* struct copy */
			if ( v3ref == 1 ) {
665
666
667
668
669
670
671
				/* 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;
672
			} else if ( ber_scanf( &tmpber, "{iaa}", &lderr,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
673
674
675
676
			    &lr->lr_res_matched, &lr->lr_res_error )
			    != LBER_ERROR ) {
				if ( lderr != LDAP_SUCCESS ) {
					/* referrals are in error string */
677
678
679
680
					refer_cnt = ldap_chase_referrals( ld, lr,
						&lr->lr_res_error, -1, &hadref );
					lr->lr_status = LDAP_REQST_COMPLETED;
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
681
					LDAP_LOG ( OPERATION, DETAIL1, 
682
683
						"read1msg: V2 referral chased,"
						"mark request completed, id =	%d\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
684
						lr->lr_msgid, 0, 0 );
685
686
687
688
#else
					Debug( LDAP_DEBUG_TRACE,
					    "read1msg:  V2 referral chased, mark request completed, id = %d\n", lr->lr_msgid, 0, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
689
690
691
692
693
694
695
696
697
698
699
700
				}

				/* 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;
				}
701
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
702
LDAP_LOG ( OPERATION, DETAIL1, 
703
704
	"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 : "",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
705
    lr->lr_res_matched ? lr->lr_res_matched : "" );
706
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
707
708
709
710
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 : "" );
711
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
712
713
714
			}
		}

715
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
716
717
		LDAP_LOG ( OPERATION, DETAIL1, "read1msg: %d new referrals\n", 
			refer_cnt, 0, 0 );
718
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
719
720
		Debug( LDAP_DEBUG_TRACE,
		    "read1msg:  %d new referrals\n", refer_cnt, 0, 0 );
721
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
722
723

		if ( refer_cnt != 0 ) {	/* chasing referrals */
724
725
			ber_free( ber, 1 );
			ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
726
727
728
			if ( refer_cnt < 0 ) {
				return( -1 );	/* fatal error */
			}
729
			lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
730
731
732
733
734
735
		} 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 */
736
737
				ber_free( ber, 1 );
				ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
738
739
			}

740
741
			lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
742
743
744
			LDAP_LOG ( OPERATION, DETAIL1, 
				"read1msg: mark request completed, id = %d\n", 
				lr->lr_msgid, 0, 0 );
745
746
747
748
#else
			Debug( LDAP_DEBUG_TRACE,
			    "read1msg:  mark request completed, id = %d\n", lr->lr_msgid, 0, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
749
750
751
752
753
754
755
756
757
			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 */
				}
			}

758
759
760
761
762
763
764
765
766
767
768
769
			/* Check if all requests are finished, lr is now parent */
			tmplr = lr;
			if (tmplr->lr_status == LDAP_REQST_COMPLETED) {
				for(tmplr=lr->lr_child; tmplr != NULL; tmplr=tmplr->lr_refnext) {
				if( tmplr->lr_status != LDAP_REQST_COMPLETED) {
					break;
					}
				}
			}

			/* 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
770
771
				id = lr->lr_msgid;
				tag = lr->lr_res_msgtype;
772
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
773
774
775
			LDAP_LOG ( OPERATION, DETAIL1, 
				"read1msg: request %ld done\n", (long) id, 0, 0 );
			LDAP_LOG ( OPERATION, DETAIL1, 
776
777
				"read1msg: res_errno: %d,res_error: <%s>, res_matched: <%s>\n",
				lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
778
				lr->lr_res_matched ? lr->lr_res_matched : "" );
779
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
780
				Debug( LDAP_DEBUG_ANY, "request %ld done\n",
781
				    (long) id, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
782
783
784
785
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 : "" );
786
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
787
				if ( !simple_request ) {
788
789
					ber_free( ber, 1 );
					ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
790
791
792
793
794
795
					if ( build_result_ber( ld, &ber, lr )
					    == LBER_ERROR ) {
						rc = -1; /* fatal error */
					}
				}

796
				ldap_free_request( ld, lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
797
798
799
			}

			if ( lc != NULL ) {
800
				ldap_free_connection( ld, lc, 0, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
801
802
803
804
			}
		}
	}

805
	if ( ber == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
806
807
808
809
		return( rc );
	}

	/* make a new ldap message */
810
	if ( (new = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) ))
Kurt Zeilenga's avatar
Kurt Zeilenga committed
811
812
813
814
815
816
	    == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return( -1 );
	}
	new->lm_msgid = (int)id;
	new->lm_msgtype = tag;
817
	new->lm_ber = ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
818

Kurt Zeilenga's avatar
Kurt Zeilenga committed
819
820
821
822
823
824
825
826
827
828
829
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
#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
897
898
899

	/* is this the one we're looking for? */
	if ( msgid == LDAP_RES_ANY || id == msgid ) {
900
		if ( all == LDAP_MSG_ONE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
901
		    || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
902
903
		    && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY
		    && new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
904
905
906
907
908
909
910
911
912
913
914
915
916
917
			*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.
	 */

918
919
	prev = NULL;
	for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
920
921
922
923
924
925
		if ( l->lm_msgid == new->lm_msgid )
			break;
		prev = l;
	}

	/* not part of an existing search response */
926
	if ( l == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
927
928
929
930
931
932
933
934
		if ( foundit ) {
			*result = new;
			ld->ld_errno = LDAP_SUCCESS;
			return( tag );
		}

		new->lm_next = ld->ld_responses;
		ld->ld_responses = new;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
935
		goto exit;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
936
937
	}

938
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
939
	LDAP_LOG ( OPERATION, DETAIL1, 
940
		"read1msg: adding response id %ld type %ld\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
941
		(long) new->lm_msgid, (long) new->lm_msgtype, 0 );
942
943
944
945
#else
	Debug( LDAP_DEBUG_TRACE, "adding response id %ld type %ld:\n",
	    (long) new->lm_msgid, (long) new->lm_msgtype, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
946
947

	/* part of a search response - add to end of list of entries */
948
949
950
951
	for ( tmp = l; (tmp->lm_chain != NULL) &&
	    	((tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY) ||
	    	 (tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE) ||
			 (tmp->lm_chain->lm_msgtype == LDAP_RES_EXTENDED_PARTIAL ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
952
953
954
955
956
957
	    tmp = tmp->lm_chain )
		;	/* NULL */
	tmp->lm_chain = new;

	/* return the whole chain if that's what we were looking for */
	if ( foundit ) {
958
		if ( prev == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
959
960
961
962
963
964
965
966
			ld->ld_responses = l->lm_next;
		else
			prev->lm_next = l->lm_next;
		*result = l;
		ld->ld_errno = LDAP_SUCCESS;
		return( tag );
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
967
exit:
968
969
970
	if ( ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
		goto retry;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
971
972
973
974
	return( -2 );	/* continue looking */
}


975
976
static ber_tag_t
build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
977
{
978
979
980
981
982
983
984
985
986
987
988
989
	ber_len_t	len;
	ber_tag_t	tag;
	ber_int_t	along;
	BerElement *ber;

	*bp = NULL;
	ber = ldap_alloc_ber_with_options( ld );

	if( ber == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return LBER_ERROR;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
990
991

	if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
992
	    lr->lr_res_msgtype, lr->lr_res_errno,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
993
	    lr->lr_res_matched ? lr->lr_res_matched : "",
994
995
996
997
	    lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {

		ld->ld_errno = LDAP_ENCODING_ERROR;
		ber_free(ber, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
998
999
1000
1001
		return( LBER_ERROR );
	}

	ber_reset( ber, 1 );
1002

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1003
	if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
1004
1005
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free(ber, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1006
1007
1008
1009
		return( LBER_ERROR );
	}

	if ( ber_get_int( ber, &along ) == LBER_ERROR ) {
1010
1011
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free(ber, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1012
1013
1014
		return( LBER_ERROR );
	}

1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
	tag = ber_peek_tag( ber, &len );

	if ( tag == LBER_ERROR ) {
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free(ber, 1);
		return( LBER_ERROR );
	}

	*bp = ber;
	return tag;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
}


static void
merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
{
/*
 * Merge error information in "lr" with "parentr" error code and string.
 */
	if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
		parentr->lr_res_errno = lr->lr_res_errno;
		if ( lr->lr_res_error != NULL ) {
1037
			(void)ldap_append_referral( ld, &parentr->lr_res_error,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1038
1039
1040
1041
1042
1043
			    lr->lr_res_error );
		}
	} else if ( lr->lr_res_errno != LDAP_SUCCESS &&
	    parentr->lr_res_errno == LDAP_SUCCESS ) {
		parentr->lr_res_errno = lr->lr_res_errno;
		if ( parentr->lr_res_error != NULL ) {
1044
			LDAP_FREE( parentr->lr_res_error );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1045
1046
1047
		}
		parentr->lr_res_error = lr->lr_res_error;
		lr->lr_res_error = NULL;
1048
		if ( LDAP_NAME_ERROR( lr->lr_res_errno )) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1049
			if ( parentr->lr_res_matched != NULL ) {
1050
				LDAP_FREE( parentr->lr_res_matched );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1051
1052
1053
1054
1055
1056
			}
			parentr->lr_res_matched = lr->lr_res_matched;
			lr->lr_res_matched = NULL;
		}
	}

1057
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1058
1059
1060
	LDAP_LOG( OPERATION, DETAIL1, "merged parent (id %d) error info:  ",
	    parentr->lr_msgid, 0, 0 );
	LDAP_LOG( OPERATION, DETAIL1, "result errno %d, error <%s>, matched <%s>\n",
1061
1062
	    parentr->lr_res_errno, parentr->lr_res_error ?
	    parentr->lr_res_error : "", parentr->lr_res_matched ?
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1063
	    parentr->lr_res_matched : "" );
1064
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1065
1066
1067
1068
1069
1070
	Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
	    parentr->lr_msgid, 0, 0 );
	Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n",
	    parentr->lr_res_errno, parentr->lr_res_error ?
	    parentr->lr_res_error : "", parentr->lr_res_matched ?
	    parentr->lr_res_matched : "" );
1071
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1072
1073
1074
1075
}



1076
1077
int
ldap_msgtype( LDAPMessage *lm )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1078
{
1079
1080
	assert( lm != NULL );
	return ( lm != NULL ) ? lm->lm_msgtype : -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1081
1082
1083
}


1084
1085
int
ldap_msgid( LDAPMessage *lm )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1086
{
1087
	assert( lm != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1088

1089
	return ( lm != NULL ) ? lm->lm_msgid : -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1090
1091
1092
}


1093
char * ldap_int_msgtype2str( ber_tag_t tag )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1094
{
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
	switch( tag ) {
	case LDAP_RES_ADD: return "add";
	case LDAP_RES_BIND: return "bind";
	case LDAP_RES_COMPARE: return "compare";
	case LDAP_RES_DELETE: return "delete";
	case LDAP_RES_EXTENDED: return "extended-result";
	case LDAP_RES_EXTENDED_PARTIAL: return "extended-partial";
	case LDAP_RES_MODIFY: return "modify";
	case LDAP_RES_RENAME: return "rename";
	case LDAP_RES_SEARCH_ENTRY: return "search-entry";
	case LDAP_RES_SEARCH_REFERENCE: return "search-reference";
	case LDAP_RES_SEARCH_RESULT: return "search-result";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1107
	}
1108
	return "unknown";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1109
1110
1111
1112
1113
1114
1115
1116
}

int
ldap_msgfree( LDAPMessage *lm )
{
	LDAPMessage	*next;
	int		type = 0;

1117
#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1118
	LDAP_LOG ( OPERATION, ENTRY, "ldap_msgfree\n", 0, 0, 0 );
1119
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1120
	Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
1121
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1122

1123
	for ( ; lm != NULL; lm = next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1124
1125
1126
		next = lm->lm_chain;
		type = lm->lm_msgtype;
		ber_free( lm->lm_ber, 1 );
1127
		LDAP_FREE( (char *) lm );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
	}

	return( type );
}

/*
 * ldap_msgdelete - delete a message.  It returns:
 *	0	if the entire message was deleted
 *	-1	if the message was not found, or only part of it was found
 */
int
ldap_msgdelete( LDAP *ld, int msgid )
{
	LDAPMessage	*lm, *prev;

1143
1144
1145
	assert( ld != NULL );

#ifdef NEW_LOGGING
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1146
	LDAP_LOG ( OPERATION, ENTRY, "ldap_msgdelete\n", 0, 0, 0 );
1147
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1148
	Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
1149
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1150

1151
1152
	prev = NULL;
	for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1153
1154
1155
1156
1157
		if ( lm->lm_msgid == msgid )
			break;
		prev = lm;
	}

1158
	if ( lm == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1159
1160
		return( -1 );

1161
	if ( prev == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
		ld->ld_responses = lm->lm_next;
	else
		prev->lm_next = lm->lm_next;

	if ( ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY )
		return( -1 );

	return( 0 );
}


/*
 * return 1 if message msgid is waiting to be abandoned, 0 otherwise
 */
static int
1177
ldap_abandoned( LDAP *ld, ber_int_t msgid )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
{
	int	i;

	if ( ld->ld_abandoned == NULL )
		return( 0 );

	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
		if ( ld->ld_abandoned[i] == msgid )
			return( 1 );

	return( 0 );
}


static int
1193
ldap_mark_abandoned( LDAP *ld, ber_int_t msgid )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
{
	int	i;

	if ( ld->ld_abandoned == NULL )
		return( -1 );

	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
		if ( ld->ld_abandoned[i] == msgid )
			break;

	if ( ld->ld_abandoned[i] == -1 )
		return( -1 );

	for ( ; ld->ld_abandoned[i] != -1; i++ ) {
		ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
	}

	return( 0 );
}