result.c 29.3 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
/*
3
4
5
6
 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
 * 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
30
 *
 *  result.c - wait for an ldap result
 */

31
32
33
34
35
36
37
38
39
40
41
/*
 * 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
42
43

#include "portable.h"
44
45
46
47
48
49
50
51
52
53
54

#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
55
56
#include "ldap-int.h"

57
58
59
60
61
62
63
64
65
66

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
67
68
69
70


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

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
	assert( ld != NULL );
	assert( result != NULL );

#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_ARGS, "ldap_result msgid %d\n", msgid ));
#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
126
127
128
129
130
	 * 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.
	 */

131
132
133
134
135
136
137
138
139
140
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_ARGS, 
		"ldap_chkResponseList for msgid=%d, all=%d\n", msgid, all ));
#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
141
142
143
		nextlm = lm->lm_next;

		if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
144
145
146
147
148
149
150
151
#ifdef NEW_LOGGING
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
				"ldap_chkResponseList msg abandoned, msgid %d\n", msgid ));
#else
			Debug( LDAP_DEBUG_TRACE,
				"ldap_chkResponseList msg abandoned, msgid %d\n",
			    msgid, 0, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
152
153
			ldap_mark_abandoned( ld, lm->lm_msgid );

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

169
			if ( all == LDAP_MSG_ONE || msgid == LDAP_RES_UNSOLICITED ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
170
				break;
171
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172

173
174
175
176
177
			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
178
					break;
179
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
180
181
			}

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

			break;
		}
		lastlm = lm;
	}

191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
    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
		LDAP_LOG (( "result", LDAP_LEVEL_RESULTS, 
			"ldap_chkResponseList returns NULL\n" ));
#else
		Debug( LDAP_DEBUG_TRACE,
			"ldap_chkResponseList returns NULL\n", 0, 0, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
216
	} else {
217
218
219
220
221
222
223
224
225
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_RESULTS, 
			"ldap_chkResponseList returns msgid %d, type 0x02lu\n",
			lm->lm_msgid, (unsigned long) lm->lm_msgtype ));
#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
226
	}
227
228
#endif
    return lm;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
229
230
231
}

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

	assert( ld != NULL );
	assert( result != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
247
248
249

#ifdef LDAP_DEBUG
	if ( timeout == NULL ) {
250
251
252
253
254
255
256
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_ARGS,
			"wait4msg (infinite timeout), msgid %d\n", msgid ));
#else
		Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout), msgid %d\n",
		    msgid, 0, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
	} else {
258
259
260
261
262
263
264
265
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_ARGS,
			"wait4msg (timeout %ld sec, %ld usec), msgid %d\n", 
			(long) timeout->tv_sec, (long) timeout->tv_usec, msgid ));
#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
266
267
268
269
270
271
272
273
	}
#endif /* LDAP_DEBUG */

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

293
294
295
        if( (*result = chkResponseList(ld, msgid, all)) != NULL ) {
            rc = (*result)->lm_msgtype;
        } else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
296

297
298
299
300
301
302
303
304
			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
305

306
307
		    if ( lc == NULL ) {
			    rc = ldap_int_select( ld, tvp );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
308

309
310
311
312
313
314
315

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

324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
			    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;
				    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
350
351
352
		}

		if ( rc == -2 && tvp != NULL ) {
353
			tmp_time = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
354
355
356
357
358
359
			if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
				rc = 0;	/* timed out */
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}

360
361
362
363
#ifdef NEW_LOGGING
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1,
				"wait4msg: %ld secs to go\n", (long) tv.tv_sec ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
364
			Debug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
365
366
			       (long) tv.tv_sec, 0, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
367
368
369
370
371
372
373
374
			start_time = tmp_time;
		}
	}

	return( rc );
}


375
376
377
378
379
380
381
382
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
383
{
384
	BerElement	*ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
385
	LDAPMessage	*new, *l, *prev, *tmp;
386
387
388
	ber_int_t	id;
	ber_tag_t	tag;
	ber_len_t	len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
389
	int		foundit = 0;
390
	LDAPRequest	*lr, *tmplr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
391
392
	BerElement	tmpber;
	int		rc, refer_cnt, hadref, simple_request;
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
	ber_int_t	lderr;
	/*
	 * 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
	LDAP_LOG (( "result", LDAP_LEVEL_ARGS, "read1msg: msgid %d, all %d\n",
		msgid, all ));
#else
	Debug( LDAP_DEBUG_TRACE, "read1msg: msgid %d, all %d\n", msgid, all, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
409

410
411
412
413
414
415
416
    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
417

418
419
	ber = lc->lconn_ber;
	assert( LBER_VALID (ber) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
420
421

	/* get the next message */
422
423
424
425
426
427
428
429
	errno = 0;
#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP(ld) ) {
		struct sockaddr from;
		ber_int_sb_read(sb, &from, sizeof(struct sockaddr));
	}
#endif
	if ( (tag = ber_get_next( sb, &len, ber ))
Kurt Zeilenga's avatar
Kurt Zeilenga committed
430
	    != LDAP_TAG_MESSAGE ) {
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
		if ( tag == LBER_DEFAULT) {
#ifdef LDAP_DEBUG		   
#ifdef NEW_LOGGING
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
				"read1msg: ber_get_next failed\n" ));
#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
452
453
	}

454
455
456
457
458
459
	/*
     * We read a complete message.
	 * The connection should no longer need this ber.
	 */
    lc->lconn_ber = NULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
460
	/* message id */
461
462
	if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
463
464
465
466
467
		ld->ld_errno = LDAP_DECODING_ERROR;
		return( -1 );
	}

	/* if it's been abandoned, toss it */
468
469
470
471
472
473
474
475
	if ( ldap_abandoned( ld, id ) ) {
		ber_free( ber, 1 );
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
			"read1msg: abandoned\n" ));
#else
		Debug( LDAP_DEBUG_ANY, "abandoned\n", 0, 0, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
476
477
478
		return( -2 );	/* continue looking */
	}

479
480
481
482
483
484
	if (( lr = ldap_find_request_by_msgid( ld, id )) == NULL ) {
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
			"read1msg: no request for response with msgid %ld (tossing)\n",
			(long) id ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
485
486
		Debug( LDAP_DEBUG_ANY,
		    "no request for response with msgid %ld (tossing)\n",
487
488
489
		    (long) id, 0, 0 );
#endif
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
490
491
		return( -2 );	/* continue looking */
	}
492
493
494
495
496
497
#ifdef LDAP_CONNECTIONLESS
	if (LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
		struct berval blank;
		ber_scanf(ber, "m{", &blank);
	}
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
498
	/* the message type */
499
	if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
500
		ld->ld_errno = LDAP_DECODING_ERROR;
501
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
502
503
504
		return( -1 );
	}

505
506
507
508
509
510
511
512
513
514
515
516
517
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
		"read1msg: ldap_read: message type %s msgid %ld, original id %ld\n",
	    ldap_int_msgtype2str( tag ),
		(long) lr->lr_msgid, (long) lr->lr_origid ));
#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
518
519
520
521
522
	refer_cnt = 0;
	hadref = simple_request = 0;
	rc = -2;	/* default is to keep looking (no response found) */
	lr->lr_res_msgtype = tag;

523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
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
571
572
573
574
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
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
	/*
	 * 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
							LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
								"read1msg: search ref chased,"
								"mark request chasing refs, id =	%d\n",
								lr->lr_msgid ));
#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
							LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
								"read1msg: referral decode error,"
								"mark request completed, id =	%d\n",
								lr->lr_msgid ));
#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
							LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
								"read1msg: referral chased,"
								"mark request completed, id =	%d\n",
								lr->lr_msgid ));
#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.
	 */
	if ( (tag != LDAP_RES_SEARCH_ENTRY) && (v3ref > -1) ) {
		/* For a v3 search referral/reference, only come here if already chased it */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
635
		if ( ld->ld_version >= LDAP_VERSION2 &&
636
637
638
639
640
			( lr->lr_parent != NULL ||
			LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ) )
		{
			tmpber = *ber;	/* struct copy */
			if ( v3ref == 1 ) {
641
642
643
644
645
646
647
				/* 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;
648
			} else if ( ber_scanf( &tmpber, "{iaa}", &lderr,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
649
650
651
652
			    &lr->lr_res_matched, &lr->lr_res_error )
			    != LBER_ERROR ) {
				if ( lderr != LDAP_SUCCESS ) {
					/* referrals are in error string */
653
654
655
656
657
658
659
660
661
662
663
664
					refer_cnt = ldap_chase_referrals( ld, lr,
						&lr->lr_res_error, -1, &hadref );
					lr->lr_status = LDAP_REQST_COMPLETED;
#ifdef NEW_LOGGING
					LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
						"read1msg: V2 referral chased,"
						"mark request completed, id =	%d\n",
						lr->lr_msgid ));
#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
665
666
667
668
669
670
671
672
673
674
675
676
				}

				/* 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;
				}
677
678
679
680
681
682
#ifdef NEW_LOGGING
LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
	"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 : "",
    lr->lr_res_matched ? lr->lr_res_matched : "" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
683
684
685
686
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 : "" );
687
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
688
689
690
			}
		}

691
692
693
694
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
			"read1msg: %d new referrals\n", refer_cnt ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
695
696
		Debug( LDAP_DEBUG_TRACE,
		    "read1msg:  %d new referrals\n", refer_cnt, 0, 0 );
697
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
698
699

		if ( refer_cnt != 0 ) {	/* chasing referrals */
700
701
			ber_free( ber, 1 );
			ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
702
703
704
			if ( refer_cnt < 0 ) {
				return( -1 );	/* fatal error */
			}
705
			lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
706
707
708
709
710
711
		} 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 */
712
713
				ber_free( ber, 1 );
				ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
714
715
			}

716
717
718
719
720
721
722
723
			lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */
#ifdef NEW_LOGGING
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
				"read1msg: mark request completed, id = %d\n", lr->lr_msgid ));
#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
724
725
726
727
728
729
730
731
732
			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 */
				}
			}

733
734
735
736
737
738
739
740
741
742
743
744
			/* 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
745
746
				id = lr->lr_msgid;
				tag = lr->lr_res_msgtype;
747
748
749
750
751
752
753
754
#ifdef NEW_LOGGING
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
				"read1msg: request %ld done\n", (long) id ));
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
				"read1msg: 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 : "" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
755
				Debug( LDAP_DEBUG_ANY, "request %ld done\n",
756
				    (long) id, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
757
758
759
760
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 : "" );
761
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
762
				if ( !simple_request ) {
763
764
					ber_free( ber, 1 );
					ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
765
766
767
768
769
770
					if ( build_result_ber( ld, &ber, lr )
					    == LBER_ERROR ) {
						rc = -1; /* fatal error */
					}
				}

771
				ldap_free_request( ld, lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
772
773
774
			}

			if ( lc != NULL ) {
775
				ldap_free_connection( ld, lc, 0, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
776
777
778
779
			}
		}
	}

780
	if ( ber == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
781
782
783
784
		return( rc );
	}

	/* make a new ldap message */
785
	if ( (new = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) ))
Kurt Zeilenga's avatar
Kurt Zeilenga committed
786
787
788
789
790
791
	    == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return( -1 );
	}
	new->lm_msgid = (int)id;
	new->lm_msgtype = tag;
792
	new->lm_ber = ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
793

794
#ifndef LDAP_NOCACHE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
795
		if ( ld->ld_cache != NULL ) {
796
			ldap_add_result_to_cache( ld, new );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
797
		}
798
#endif /* LDAP_NOCACHE */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
799
800
801

	/* is this the one we're looking for? */
	if ( msgid == LDAP_RES_ANY || id == msgid ) {
802
		if ( all == LDAP_MSG_ONE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
803
		    || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
804
805
		    && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY
		    && new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
806
807
808
809
810
811
812
813
814
815
816
817
818
819
			*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.
	 */

820
821
	prev = NULL;
	for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
822
823
824
825
826
827
		if ( l->lm_msgid == new->lm_msgid )
			break;
		prev = l;
	}

	/* not part of an existing search response */
828
	if ( l == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
829
830
831
832
833
834
835
836
837
838
839
		if ( foundit ) {
			*result = new;
			ld->ld_errno = LDAP_SUCCESS;
			return( tag );
		}

		new->lm_next = ld->ld_responses;
		ld->ld_responses = new;
		return( -2 );	/* continue looking */
	}

840
841
842
843
844
845
846
847
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
		"read1msg: adding response id %ld type %ld\n",
		(long) new->lm_msgid, (long) new->lm_msgtype ));
#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
848
849

	/* part of a search response - add to end of list of entries */
850
851
852
853
	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
854
855
856
857
858
859
	    tmp = tmp->lm_chain )
		;	/* NULL */
	tmp->lm_chain = new;

	/* return the whole chain if that's what we were looking for */
	if ( foundit ) {
860
		if ( prev == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
861
862
863
864
865
			ld->ld_responses = l->lm_next;
		else
			prev->lm_next = l->lm_next;
		*result = l;
		ld->ld_errno = LDAP_SUCCESS;
866
867
868
869
870
871
872
873
874
875
#ifdef LDAP_WORLD_P16
		/*
		 * XXX questionable fix; see text for [P16] on
		 * http://www.critical-angle.com/ldapworld/patch/
		 *
		 * inclusion of this patch causes searchs to hang on
		 * multiple platforms
		 */
		return( l->lm_msgtype );
#else	/* LDAP_WORLD_P16 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
876
		return( tag );
877
#endif	/* !LDAP_WORLD_P16 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
878
879
880
881
882
883
	}

	return( -2 );	/* continue looking */
}


884
885
static ber_tag_t
build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
886
{
887
888
889
890
891
892
893
894
895
896
897
898
	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
899
900

	if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
901
	    lr->lr_res_msgtype, lr->lr_res_errno,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
902
	    lr->lr_res_matched ? lr->lr_res_matched : "",
903
904
905
906
	    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
907
908
909
910
		return( LBER_ERROR );
	}

	ber_reset( ber, 1 );
911

Kurt Zeilenga's avatar
Kurt Zeilenga committed
912
	if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
913
914
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free(ber, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
915
916
917
918
		return( LBER_ERROR );
	}

	if ( ber_get_int( ber, &along ) == LBER_ERROR ) {
919
920
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free(ber, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
921
922
923
		return( LBER_ERROR );
	}

924
925
926
927
928
929
930
931
932
933
	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
934
935
936
937
938
939
940
941
942
943
944
945
}


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 ) {
946
			(void)ldap_append_referral( ld, &parentr->lr_res_error,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
947
948
949
950
951
952
			    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 ) {
953
			LDAP_FREE( parentr->lr_res_error );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
954
955
956
		}
		parentr->lr_res_error = lr->lr_res_error;
		lr->lr_res_error = NULL;
957
		if ( LDAP_NAME_ERROR( lr->lr_res_errno )) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
958
			if ( parentr->lr_res_matched != NULL ) {
959
				LDAP_FREE( parentr->lr_res_matched );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
960
961
962
963
964
965
			}
			parentr->lr_res_matched = lr->lr_res_matched;
			lr->lr_res_matched = NULL;
		}
	}

966
967
968
969
970
971
972
973
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
		"read1msg: merged parent (id %d) error info: result errno %d, "
		"error <%s>, matched <%s>\n", parentr->lr_msgid,
	    parentr->lr_res_errno, parentr->lr_res_error ?
	    parentr->lr_res_error : "", parentr->lr_res_matched ?
	    parentr->lr_res_matched : "" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
974
975
976
977
978
979
	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 : "" );
980
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
981
982
983
984
}



985
986
int
ldap_msgtype( LDAPMessage *lm )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
987
{
988
989
	assert( lm != NULL );
	return ( lm != NULL ) ? lm->lm_msgtype : -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
990
991
992
}


993
994
int
ldap_msgid( LDAPMessage *lm )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
995
{
996
	assert( lm != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
997

998
	return ( lm != NULL ) ? lm->lm_msgid : -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
999
1000
1001
}


1002
char * ldap_int_msgtype2str( ber_tag_t tag )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1003
{
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
	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
1016
	}
1017
	return "unknown";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1018
1019
1020
1021
1022
1023
1024
1025
}

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

1026
1027
1028
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_ENTRY, "ldap_msgfree\n" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1029
	Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
1030
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1031

1032
	for ( ; lm != NULL; lm = next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1033
1034
1035
		next = lm->lm_chain;
		type = lm->lm_msgtype;
		ber_free( lm->lm_ber, 1 );
1036
		LDAP_FREE( (char *) lm );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
	}

	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;

1052
1053
1054
1055
1056
	assert( ld != NULL );

#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_ENTRY, "ldap_msgdelete\n" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1057
	Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
1058
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1059

1060
1061
	prev = NULL;
	for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1062
1063
1064
1065
1066
		if ( lm->lm_msgid == msgid )
			break;
		prev = lm;
	}

1067
	if ( lm == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1068
1069
		return( -1 );

1070
	if ( prev == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
		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
1086
ldap_abandoned( LDAP *ld, ber_int_t msgid )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
{
	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
1102
ldap_mark_abandoned( LDAP *ld, ber_int_t msgid )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
{
	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 );
}