xref: /onnv-gate/usr/src/lib/libldap4/common/result.c (revision 0:68f95e015346)
1 /*
2  * Copyright 1998-2003 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  *  Copyright (c) 1990 Regents of the University of Michigan.
10  *  All rights reserved.
11  *
12  *  result.c - wait for an ldap result
13  */
14 
15 #ifndef lint
16 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
17 #endif
18 
19 #include <stdio.h>
20 #include <string.h>
21 #ifdef MACOS
22 #include <stdlib.h>
23 #include <time.h>
24 #include "macos.h"
25 #else /* MACOS */
26 #if defined( DOS ) || defined( _WIN32 )
27 #include <time.h>
28 #include "msdos.h"
29 #ifdef PCNFS
30 #include <tklib.h>
31 #include <tk_errno.h>
32 #include <bios.h>
33 #endif /* PCNFS */
34 #ifdef NCSA
35 #include "externs.h"
36 #endif /* NCSA */
37 #else /* DOS */
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <errno.h>
42 #ifdef _AIX
43 #include <sys/select.h>
44 #endif /* _AIX */
45 #include "portable.h"
46 #endif /* DOS */
47 #endif /* MACOS */
48 #ifdef VMS
49 #include "ucx_select.h"
50 #endif
51 #include "lber.h"
52 #include "ldap.h"
53 #include "ldap-private.h"
54 #include "ldap-int.h"
55 
56 #ifdef USE_SYSCONF
57 #include <unistd.h>
58 #endif /* USE_SYSCONF */
59 
60 #ifdef NEEDPROTOS
61 static int ldap_abandoned( LDAP *ld, int msgid );
62 static int ldap_mark_abandoned( LDAP *ld, int msgid );
63 static int wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
64 	LDAPMessage **result );
65 static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
66 	LDAPMessage **result );
67 static int build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr );
68 static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
69 #ifdef CLDAP
70 static int ldap_select1( LDAP *ld, struct timeval *timeout );
71 #endif
72 static int Ref_AddToRequest(LDAPRequest *lr, char **refs);
73 static void Ref_FreeAll(LDAPRequest *lr);
74 #else /* NEEDPROTOS */
75 static int ldap_abandoned();
76 static int ldap_mark_abandoned();
77 static int wait4msg();
78 static int read1msg();
79 static int build_result_ber();
80 static void merge_error_info();
81 #ifdef CLDAP
82 static int ldap_select1();
83 #endif
84 #endif /* NEEDPROTOS */
85 
86 #if !defined( MACOS ) && !defined( DOS )
87 extern int	errno;
88 #endif
89 
90 /*
91  * ldap_result - wait for an ldap result response to a message from the
92  * ldap server.  If msgid is -1, any message will be accepted, otherwise
93  * ldap_result will wait for a response with msgid.
94  * If all is LDAP_MSG_ONE the first message with id msgid will be accepted.
95  * If all is LDAP_MSG_RECEIVED, the received messages with the id msgid will
96  * be accepted.
97  * Otherwise, ldap_result will wait for all responses with id msgid and
98  * then return a pointer to the entire list of messages.  This is only
99  * useful for search responses, which can be of 3 message types (zero or
100  * more entries, zero or more references, one or more results).  The type
101  * of the first message* received is returned.
102  * When waiting, any messages that have been abandoned are discarded.
103  *
104  * Example:
105  *	ldap_result( s, msgid, all, timeout, result )
106  */
107 int
ldap_result(LDAP * ld,int msgid,int all,struct timeval * timeout,LDAPMessage ** result)108 ldap_result( LDAP *ld, int msgid, int all, struct timeval *timeout,
109 	LDAPMessage **result )
110 {
111 	LDAPMessage	*lm, *lastlm, *nextlm;
112 	int rv;
113 
114 	/*
115 	 * First, look through the list of responses we have received on
116 	 * this association and see if the response we're interested in
117 	 * is there.  If it is, return it.  If not, call wait4msg() to
118 	 * wait until it arrives or timeout occurs.
119 	 */
120 
121 #ifdef _REENTRANT
122 	LOCK_RESPONSE(ld);
123 	LOCK_LDAP(ld);
124 #endif
125 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 223, "ldap_result\n"), 0, 0, 0 );
126 
127 	*result = NULLMSG;
128 	lastlm = NULLMSG;
129 
130 	/* look in the received responses */
131 	for ( lm = ld->ld_responses; lm != NULLMSG; lm = nextlm ) {
132 		nextlm = lm->lm_next;
133 
134 		/* if the msg has been abandonned, free it */
135 		if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
136 			ldap_mark_abandoned( ld, lm->lm_msgid );
137 
138 			if ( lastlm == NULLMSG ) {
139 				ld->ld_responses = lm->lm_next;
140 			} else {
141 				lastlm->lm_next = nextlm;
142 			}
143 
144 			ldap_msgfree( lm );
145 
146 			continue;
147 		}
148 
149 		if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
150 			LDAPMessage	*tmp;
151 
152 			/* If return ONE or RECEIVED message(s) or not a search result, return lm */
153 			if ( all == LDAP_MSG_ONE || all == LDAP_MSG_RECEIVED
154 				 || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
155 					&& lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY
156 					&& lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) )
157 				break;
158 
159 			/* Search in the set of messages if one is a search result */
160 			for ( tmp = lm; tmp != NULLMSG; tmp = tmp->lm_chain ) {
161 				if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
162 					break;
163 			}
164 			/* No, well wait for the result message */
165 			if ( tmp == NULLMSG ) {
166 #ifdef _REENTRANT
167 				UNLOCK_LDAP(ld);
168 #endif
169 				rv = wait4msg( ld, msgid, all, timeout, result );
170 #ifdef _REENTRANT
171 				UNLOCK_RESPONSE(ld);
172 #endif
173 				return( rv );
174 			}
175 			/* Here we have the Search result pointed by tmp */
176 			break;
177 		}
178 		/* Check next response */
179 		lastlm = lm;
180 	}
181 
182 	/* No response matching found : Wait for one  */
183 	if ( lm == NULLMSG ) {
184 #ifdef _REENTRANT
185 		UNLOCK_LDAP(ld);
186 #endif
187 		rv = wait4msg( ld, msgid, all, timeout, result );
188 #ifdef _REENTRANT
189 		UNLOCK_RESPONSE(ld);
190 #endif
191 		return( rv );
192 	}
193 
194 	/* lm points to the message (chain) to return */
195 
196 	/* Remove message to return from ld_responses list */
197 	if ( lastlm == NULLMSG ) {
198 		if (all == LDAP_MSG_ONE && lm->lm_chain != NULLMSG){
199 			ld->ld_responses = lm->lm_chain;
200 		} else {
201 			ld->ld_responses = lm->lm_next;
202 		}
203 	} else {
204 		if (all == LDAP_MSG_ONE && lm->lm_chain != NULLMSG) {
205 			lastlm->lm_next = lm->lm_chain;
206 		} else {
207 			lastlm->lm_next = lm->lm_next;
208 		}
209 	}
210 
211 	if ( all == LDAP_MSG_ONE )
212 		lm->lm_chain = NULLMSG;
213 	/* Otherwise return the whole chain */
214 	/* No reponses attached */
215 	lm->lm_next = NULLMSG;
216 
217 	*result = lm;
218 	ld->ld_errno = LDAP_SUCCESS;
219 	rv = lm->lm_msgtype;
220 #ifdef _REENTRANT
221 	UNLOCK_LDAP(ld);
222 	UNLOCK_RESPONSE(ld);
223 #endif
224 	return( rv );
225 }
226 
227 static int
wait4msg(LDAP * ld,int msgid,int all,struct timeval * timeout,LDAPMessage ** result)228 wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
229 	LDAPMessage **result )
230 {
231 	int		rc;
232 	struct timeval	tv, *tvp;
233 	time_t		start_time, tmp_time;
234 	LDAPConn	*lc, *nextlc;
235 
236 #ifdef LDAP_DEBUG
237 	if ( timeout == NULL ) {
238 		Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 224, "wait4msg (infinite timeout)\n"),
239 		    0, 0, 0 );
240 	} else {
241 		Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 225, "wait4msg (timeout %1$ld sec, %2$ld usec)\n"),
242 		    timeout->tv_sec, timeout->tv_usec, 0 );
243 	}
244 #endif /* LDAP_DEBUG */
245 
246 	if ( timeout == NULL ) {
247 		tvp = NULL;
248 	} else {
249 		tv = *timeout;
250 		tvp = &tv;
251 		start_time = time( NULL );
252 	}
253 
254 	rc = -2;
255 	while ( rc == -2 ) {
256 #ifdef LDAP_DEBUG
257 		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
258 			dump_connection( ld, ld->ld_conns, 1 );
259 			dump_requests_and_responses( ld );
260 		}
261 #endif /* LDAP_DEBUG */
262 		for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
263 			if ( lc->lconn_sb->sb_ber.ber_ptr <
264 			    lc->lconn_sb->sb_ber.ber_end ) {
265 				/* A Message is available, decode and process it */
266 				rc = read1msg( ld, msgid, all, lc->lconn_sb,
267 				    lc, result );
268 				break;
269 			}
270 		}
271 		/* There was no message available : Wait for one */
272 		if ( lc == NULL ) {
273 			rc = do_ldap_select( ld, tvp );
274 
275 
276 #if defined( LDAP_DEBUG ) && !defined( MACOS ) && !defined( DOS )
277 			if ( rc == -1 ) {
278 			    Debug( LDAP_DEBUG_TRACE,
279 				    catgets(slapdcat, 1, 226, "do_ldap_select returned -1: errno %d\n"),
280 				    errno, 0, 0 );
281 			}
282 #endif
283 
284 #if !defined( MACOS ) && !defined( DOS )
285 			if ( rc == 0 || ( rc == -1 && (ld->ld_restart || errno != EINTR ))) {
286 #else
287 			if ( rc == -1 || rc == 0 ) {
288 #endif
289 				ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
290 				    LDAP_TIMEOUT);
291 				if ( rc == -1 ) {
292 #ifdef _REENTRANT
293 					LOCK_LDAP(ld);
294 #endif
295 					nsldapi_connection_lost_nolock( ld, NULL);
296 #ifdef _REENTRANT
297 					UNLOCK_LDAP(ld);
298 #endif
299 				}
300 				return( rc );
301 			}
302 
303 			if ( rc == -1 ) {
304 				rc = -2;	/* select interrupted: Continue the loop */
305 			} else {
306 				rc = -2;
307 				for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
308 				    lc = nextlc ) {
309 					nextlc = lc->lconn_next;
310 					if ( lc->lconn_status == LDAP_CONNST_CONNECTED) {
311 						/* Check on each connection. */
312 						long is_ready = is_read_ready( ld, lc->lconn_sb );
313 
314 						if (is_ready > 0) {
315 							/* A Message is available, decode and process it */
316 							rc = read1msg( ld, msgid, all,
317 										   lc->lconn_sb, lc, result );
318 						} else if ( is_ready < 0){
319 							/* Error in the select : what to do in here ? */
320 							/* So far : */
321 							rc = -1;
322 						}
323 					}
324 				}
325 			}
326 		}
327 
328 		if ( rc == -2 && tvp != NULL ) {
329 			tmp_time = time( NULL );
330 			if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
331 				/* At this point if all == LDAP_MSG_RECEIVED, we must
332 				   return all available messages for the msgid */
333 				if (all == LDAP_MSG_RECEIVED) {
334 					/* Search in responses if some have the correct id */
335 					/* if yes return the chain */
336 					/* Otherwise return timeout */
337 					break;
338 				}
339 
340 				rc = 0;	/* timed out */
341 				ld->ld_errno = LDAP_TIMEOUT;
342 				break;
343 			}
344 
345 			Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 227, "wait4msg:  %ld secs to go\n"),
346 				tv.tv_sec, 0, 0 );
347 			start_time = tmp_time;
348 		}
349 	}
350 
351 	return( rc );
352 }
353 
354 
355 static int
356 read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
357     LDAPConn *lc,
358     LDAPMessage **result )
359 {
360 	BerElement	ber;
361 	LDAPMessage	*new, *L_res, *l, *prev, *tmp;
362 	int		id;
363 	unsigned int	tag, atag, len;
364 	int		foundit = 0;
365 	LDAPRequest	*lr, *lrparent;
366 	LDAPRef *theReferences;
367 	BerElement	tmpber;
368 	int		rc, refer_cnt, hadref, simple_request, samereq = 0, total_count;
369 	int retcode;
370 	int theErrCode = LDAP_SUCCESS;
371 	unsigned int	lderr;
372 	char *msgtypestr;
373 	char ** theRefs = NULL;
374 	char * theOid = NULL;
375 	char *lddn, *lderrmsg;
376 
377 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 228, "read1msg\n"), 0, 0, 0 );
378 
379 read_from_sb:
380 	lderr = LDAP_SUCCESS; /* Be optimistic */
381 
382 	ber_zero_init( &ber, 0 );
383 	set_ber_options( ld, &ber );
384 
385 	/* get the next message */
386 	if ( (tag = ber_get_next( sb, &len, &ber ))
387 	    != LDAP_TAG_MESSAGE ) {
388 		ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
389 		    LDAP_LOCAL_ERROR);
390 		if ( tag == LBER_DEFAULT ) {
391 #ifdef _REENTRANT
392 			LOCK_LDAP(ld);
393 #endif
394 			nsldapi_connection_lost_nolock( ld, sb );
395 #ifdef _REENTRANT
396 			UNLOCK_LDAP(ld);
397 #endif
398 		}
399 		return( -1 );
400 	}
401 
402 	/* message id */
403 	if ( ber_get_int( &ber, &id ) == LBER_ERROR ) {
404 		ld->ld_errno = LDAP_DECODING_ERROR;
405 		return( -1 );
406 	}
407 
408 	/* if it's been abandoned, toss it */
409 	if ( ldap_abandoned( ld, (int)id ) ) {
410 		free( ber.ber_buf );	/* gack! */
411 		return( -2 );	/* continue looking */
412 	}
413 
414 	/* the message type */
415 	if ( (tag = ber_peek_tag( &ber, &len )) == LBER_ERROR ) {
416 		ld->ld_errno = LDAP_DECODING_ERROR;
417 		return( -1 );
418 	}
419 
420 	/* KE
421 	 * Treat unsolicited notification if we got one!
422 	 * 	id==0
423 	 * 	tag==LDAP_RES_EXTENDED
424 	 *
425 	 * 	resultCode==	protocolError
426 	 *							strongAuthRequired
427 	 * 						unavailable
428 	 *		tag==LDAP_TAG_EXT_RESPNAME
429 	 *		response name (oid)==1.3.6.1.1.4.1.1466.20036
430 	 * 	no response field
431 	 *
432 	 * Example:
433 	 * --------
434 	 * Ber format: 	{iaata}
435 	 * which means: 	returnCode dn errorMessage LDAP_TAG_EXT_RESPNAME "1.3.6.1.1.4.1.1466.20036"
436 	 */
437 	if ( (id==0) && (tag==LDAP_RES_EXTENDED) )
438 	{
439 		tmpber = ber;
440 		if (ber_scanf( &ber, "{iaa", &lderr, &lddn, &lderrmsg) != LBER_ERROR)
441 		{
442 			if (ber_peek_tag ( &ber, &atag) == LDAP_TAG_EXT_RESPNAME)
443 			{
444 			  if ( ber_get_stringa( &ber, &theOid) == LBER_ERROR )
445 				{
446 					ld->ld_errno = LDAP_DECODING_ERROR;
447 					return(-1);
448 				}
449 			}
450 			else
451 			{
452 				ld->ld_errno = LDAP_DECODING_ERROR;
453 				return(-1);
454 			}
455 
456 			if (ber_peek_tag ( &ber, &atag) == LDAP_TAG_EXT_RESPONSE)
457 			{
458 				/* this field must be absent */
459 				ld->ld_errno = LDAP_DECODING_ERROR;
460 				return(-1);
461 			}
462 			if ( ber_scanf(&ber, "}")== LBER_ERROR)
463 			{
464 				ld->ld_errno = LDAP_DECODING_ERROR;
465 				return(-1);
466 			}
467 
468 			/* make a new ldap message to return the result */
469 			if ( (new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) )) == NULL )
470 			{
471 				ld->ld_errno = LDAP_NO_MEMORY;
472 				return(-1);
473 			}
474 			new->lm_msgid = 0;
475 			new->lm_msgtype = tag;
476 			new->lm_ber = ber_dup( &tmpber );
477 
478 			if ( 	(strncmp(theOid, "1.3.6.1.1.4.1.1466.20036", 24)==0) &&
479 					(lderr==LDAP_PROTOCOL_ERROR) ||
480 					(lderr==LDAP_STRONG_AUTH_REQUIRED) ||
481 					(lderr==LDAP_UNAVAILABLE) )
482 			{
483 				/* make a new ldap message to return the result */
484 				if ( (L_res = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) )) == NULL )
485 				{
486 					ld->ld_errno = LDAP_NO_MEMORY;
487 					return(-1);
488 				}
489 				L_res->lm_msgid = 0;
490 				L_res->lm_msgtype = tag;
491 				L_res->lm_ber = ber_dup( &tmpber );
492 				*result = L_res;
493 
494 				/* It is a notice of disconnection
495 				 * Return immediatly with an error code to stop
496 				 * reading any new message and to prevent the use
497 				 */
498 				ld->ld_errno = LDAP_SERVER_DOWN;
499 				ldap_insert_notif(ld, new);		/* in head */
500 				return(-1);
501 			}
502 			else
503 			{
504 				/* This is another notification
505 				 *	Keep on the processing of received messages
506 				 */
507 				ldap_add_notif(ld, new);			/* in tail */
508 				goto read_from_sb;
509 			}
510 		}
511 		else
512 		{
513 			Debug(LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1673, "Error while decoding Extended Response message"), NULL, NULL, NULL);
514 			ld->ld_errno = LDAP_DECODING_ERROR;
515 			return(-1);
516 		}
517 	}
518 	else if (( lr = find_request_by_msgid( ld, id )) == NULL )
519 	{
520 		Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, 229, "no request for response with msgid %ld (tossing)\n"), id, 0, 0 );
521 		free( ber.ber_buf );	/* gack! */
522 		return( -2 );	/* continue looking */
523 	}
524 
525 	if (tag == LDAP_RES_SEARCH_ENTRY)
526 		msgtypestr = catgets(slapdcat, 1, 1281, "search entry");
527 	else if (tag == LDAP_RES_SEARCH_REFERENCE)
528 		msgtypestr = catgets(slapdcat, 1, 1282, "search reference");
529 	else
530 		msgtypestr = catgets(slapdcat, 1, 1283, "result");
531 
532 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 230, "got %1$s msgid %2$ld, original id %3$d\n"),
533 		   msgtypestr, id, lr->lr_origid );
534 
535 	id = lr->lr_origid;
536 
537 	/* REFERRALS HANDLING*/
538 	refer_cnt = 0;
539 	simple_request = 0;
540 	hadref = 0;
541 	rc = -2;	/* default is to keep looking (no response found) */
542 	lr->lr_res_msgtype = tag;
543 
544 	if ( tag != LDAP_RES_SEARCH_ENTRY ) { /* If it's not an entry, ie it's a result or a reference */
545 		if ( ld->ld_version >= LDAP_VERSION2 &&
546 			    ( lr->lr_parent != NULL ||
547 				  ld->ld_follow_referral /* || ClientControl to follow referral present */ )) {
548 			tmpber = ber;
549 			if (tag == LDAP_RES_SEARCH_REFERENCE){
550 				/* LDAP V3 reference. Decode it */
551 				Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, -1, "LDAP search reference received. Will follow it later\n"),
552 					  0, 0,0);
553 				if (ber_scanf(&tmpber, "{v}", &theRefs) == LBER_ERROR){
554 					Debug ( LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1284, "Error while decoding Search Reference Result message\n"),
555 							NULL, NULL, NULL);
556 					rc = -1;
557 					theRefs = NULL;
558 				} else {
559 					/* Store the referrals in request. We will follow them when the result arrives */
560 					Ref_AddToRequest(lr, theRefs);
561 					theRefs = NULL;
562 					free( ber.ber_buf );	/* gack! */
563 					ber.ber_buf = NULL;
564 					return (rc);
565 				}
566 			} else {
567 				if (ber_scanf( &tmpber, "{iaa", &lderr, &lr->lr_res_matched, &lr->lr_res_error) != LBER_ERROR){
568 					if (lderr == LDAP_PARTIAL_RESULTS){
569 						Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, -1, "LDAPv2 partial error received\n"), 0, 0,0);
570 						/* Ldapv2 referrals */
571 						theRefs = ldap_errormsg2referrals(lr->lr_res_error);
572 						ber_scanf(&tmpber, "}");
573 					} else if (lderr == LDAP_REFERRAL ){
574 						/* We have some referrals, decode them */
575 						Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, -1, "LDAPv3 referral error received\n"), 0, 0,0);
576 						if (ber_peek_tag ( &tmpber, &atag) == LDAP_TAG_REFERRAL){
577 							if (ber_scanf(&tmpber, "{v}}", &theRefs) == LBER_ERROR){
578 								Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1285, "Error while decoding referrals in msg\n"),
579 									   NULL, NULL, NULL );
580 								rc = -1; /* ??? */
581 								theRefs = NULL;
582 							}
583 						} /* else error there should be at least one ref */
584 					} else if (((lderr == LDAP_NO_SUCH_OBJECT) ||
585 							   (lderr == LDAP_BUSY) ||
586 							   (lderr == LDAP_UNAVAILABLE) ||
587 							   (lderr == LDAP_SERVER_DOWN) ||
588 							   (lderr == LDAP_CONNECT_ERROR)) &&
589 							   (lr->lr_parent != NULL) && /* its  subrequest */
590 							   (lr->lr_ref_tofollow != NULL)) { /* And it has some other referral to try */
591 						samereq = 1;
592 						theRefs = lr->lr_ref_tofollow;
593 						lr->lr_ref_tofollow = NULL;
594 						lrparent = lr->lr_parent;
595 						/* delete lr */
596 						free_request(ld, lr);
597 						/* lr now points on parent request */
598 						lr = lrparent;
599 						/* Follow referrals */
600 					} else {
601 						/* Here we have a simple result */
602 						hadref = lr->lr_outrefcnt;
603 					}
604 				} else {
605 					Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1286, "Error while decoding result for request %$1d\n"),
606 						   lr->lr_origid, NULL, NULL);
607 					rc = -1; /* ??? */
608 				}
609 			}
610 
611 			total_count = 0;
612 			if (tag != LDAP_RES_SEARCH_REFERENCE && lr->lr_references) {
613 				/* Some search references pending... Let's try to chase them */
614 				hadref = 1;
615 				theReferences = lr->lr_references;
616 
617 				Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, -1, "Now following the search references received\n"),
618 					  0, 0,0);
619 
620 				while (theReferences != NULL){
621 					if ((retcode = chase_referrals(ld, lr, theReferences->lref_refs , &refer_cnt, 0)) != LDAP_SUCCESS) {
622 						/* think about what to do */
623 						Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, -1, "Error while chasing referral (%1$d)\n"),
624 							   retcode, NULL, NULL);
625 						theErrCode = LDAP_REFERRAL;
626 					}
627 					if (refer_cnt >= 0)
628 						total_count += refer_cnt;
629 					theReferences = theReferences->lref_next;
630 				}
631 				Ref_FreeAll(lr);
632 				if (theErrCode != LDAP_SUCCESS) {
633 					if (ld->ld_error != NULL && *ld->ld_error) {
634 						if (lr->lr_res_error)
635 							free(lr->lr_res_error);
636 						lr->lr_res_error = strdup(ld->ld_error);
637 					}
638 				}
639 				lr->lr_res_errno = theErrCode;
640 			}
641 			/* if theRefs != NULL we have some referrals to chase, do it */
642 			if (theRefs){
643 				hadref = 1;
644 				if ((retcode = chase_referrals(ld, lr, theRefs, &refer_cnt, samereq)) != LDAP_SUCCESS){
645 					/* think about what to do */
646 					Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, -1, "Error while chasing referral (%1$d)\n"),
647 						   retcode, NULL, NULL);
648 				}
649 
650 				if (refer_cnt >= 0)
651 					total_count += refer_cnt;
652 
653 				ldap_value_free(theRefs);
654 				if (samereq){ /* Just tried another referral for same request */
655 					free(ber.ber_buf);
656 					ber.ber_buf = NULL;
657 					rc = -2;
658 					/* continue */
659 				}
660 				if (retcode != LDAP_SUCCESS) {
661 					if (ld->ld_version == LDAP_VERSION2){
662 						if (lr->lr_res_error)
663 							free(lr->lr_res_error);
664 						lr->lr_res_error = ldap_referral2error_msg(lr->lr_ref_unfollowed);
665 					} else if (ld->ld_error != NULL && *ld->ld_error) {
666 						if (lr->lr_res_error)
667 							free(lr->lr_res_error);
668 						lr->lr_res_error = strdup(ld->ld_error);
669 					}
670 				}
671 				lr->lr_res_errno = ld->ld_errno;
672 
673 			}  else if (theErrCode == LDAP_SUCCESS) {
674 				/* no referral have been chased */
675 				lr->lr_res_errno = (lderr == LDAP_PARTIAL_RESULTS || lderr == LDAP_REFERRAL) ? LDAP_SUCCESS : lderr;
676 			}
677 
678 			Debug( LDAP_DEBUG_TRACE,
679 				   catgets(slapdcat, 1, 231, "new result:  res_errno: %1$d, res_error: <%2$s>, res_matched: <%3$s>\n"),
680 				   lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
681 				   lr->lr_res_matched ? lr->lr_res_matched : "" );
682 		}
683 
684 
685 		Debug( LDAP_DEBUG_TRACE,
686 			   catgets(slapdcat, 1, 232, "read1msg:  %1$d new referrals\n"), total_count, 0, 0 );
687 
688 		if ( refer_cnt != 0 ) {	/* chasing referrals */
689 			free( ber.ber_buf );	/* gack! */
690 			ber.ber_buf = NULL;
691 			if ( refer_cnt < 0 ) {
692 				return( -1 );	/* fatal error */
693 			}
694 			lr->lr_status = LDAP_REQST_CHASINGREFS;
695 		} else if (tag == LDAP_RES_SEARCH_REFERENCE && !ld->ld_follow_referral) {
696 			/* We had a ref and we don't follow referral : Do nothing there ?! */
697 			Debug( LDAP_DEBUG_TRACE,
698 				   catgets(slapdcat, 1, -1, "read1msg: returning search reference\n"), 0, 0, 0 );
699 
700 		} else {
701 			/* No referral chasing */
702 			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
703 				/* request without any referrals */
704 				simple_request = ( hadref ? 0 : 1 );
705 			} else {
706 				/* request with referrals or child request */
707 				free( ber.ber_buf );	/* gack! */
708 				ber.ber_buf = NULL;
709 			}
710 
711 
712  			while ( lr->lr_parent != NULL ) {
713  				merge_error_info( ld, lr->lr_parent, lr );
714  				lr = lr->lr_parent;
715  				if ( --lr->lr_outrefcnt > 0 ) {
716  					break;	/* not completedly done yet */
717  				}
718  			}
719 
720 			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) { /* The main request has no more outstanding refs */
721 				id = lr->lr_msgid;
722 				tag = lr->lr_res_msgtype;
723 				Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 233, "request %1$ld done\n"),
724 				    id, 0, 0 );
725 				Debug( LDAP_DEBUG_TRACE,
726 					   catgets(slapdcat, 1, 234, "res_errno: %1$d, res_error: <%2$s>, res_matched: <%3$s>\n"),
727 					   lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
728 					   lr->lr_res_matched ? lr->lr_res_matched : "" );
729 				if ( !simple_request ) { /* We have to rebuild the result */
730 					if ( ber.ber_buf != NULL ) {
731 						free( ber.ber_buf ); /* gack! */
732 						ber.ber_buf = NULL;
733 					}
734 					if ( build_result_ber( ld, &ber, lr )
735 					    == LBER_ERROR ) {
736 						ld->ld_errno = LDAP_NO_MEMORY;
737 						rc = -1; /* fatal error */
738 					}
739 				}
740 
741 				free_request( ld, lr );
742 			}
743 
744 			if ( lc != NULL ) {
745 				free_connection( ld, lc, 0, 1 );
746 			}
747 		}
748 	}
749 
750 	if ( ber.ber_buf == NULL ) { /* If the buffer has been freed, return */
751 		return( rc );
752 	}
753 	/* End of REFERRALS */
754 
755 	/* make a new ldap message */
756 	if ( (new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) ))
757 	    == NULL ) {
758 		ld->ld_errno = LDAP_NO_MEMORY;
759 		return( -1 );
760 	}
761 	new->lm_msgid = (int)id;
762 	new->lm_msgtype = tag;
763 	new->lm_ber = ber_dup( &ber );
764 
765 #ifndef NO_CACHE
766 	if ( ld->ld_cache != NULL ) {
767 		add_result_to_cache( ld, new );
768 	}
769 #endif /* NO_CACHE */
770 
771 	/* is this the one we're looking for? */
772 	if ( msgid == LDAP_RES_ANY || id == msgid ) {
773 		if ( all == LDAP_MSG_ONE	/* all apply only to search, so if not a search,return the val */
774 		    || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
775 				&& new->lm_msgtype != LDAP_RES_SEARCH_ENTRY
776 				&& new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) ) {
777 			*result = new;
778 			ld->ld_errno = LDAP_SUCCESS;
779 			return( tag );
780 		} else if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
781 			foundit = 1;	/* return the chain later */
782 		}
783 	}
784 
785 	/*
786 	 * if not, we must add it to the list of responses.  if
787 	 * the msgid is already there, it must be part of an existing
788 	 * search response.
789 	 */
790 
791 	prev = NULLMSG;
792 	for ( l = ld->ld_responses; l != NULLMSG; l = l->lm_next ) {
793 		if ( l->lm_msgid == new->lm_msgid )
794 			break;
795 		prev = l;
796 	}
797 
798 	/* not part of an existing search response */
799 	if ( l == NULLMSG ) {
800 		if ( foundit ) { /* it a search result anyway, so return it */
801 			*result = new;
802 			ld->ld_errno = LDAP_SUCCESS;
803 			return( tag );
804 		}
805 
806 		new->lm_next = ld->ld_responses;
807 		ld->ld_responses = new;
808 		return( -2 );	/* continue looking */
809 	}
810 
811 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 235, "adding response id %1$d type %2$d:\n"),
812 	    new->lm_msgid, new->lm_msgtype, 0 );
813 
814 	/* part of a search response - add to end of list of entries or references */
815 	for ( tmp = l; tmp->lm_chain != NULLMSG &&
816 	    (tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ||
817 		 tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE);
818 	    tmp = tmp->lm_chain )
819 		;	/* NULL */
820 	tmp->lm_chain = new;
821 
822 	/* return the whole chain if that's what we were looking for */
823 	if ( foundit ) {
824 		if ( prev == NULLMSG )
825 			ld->ld_responses = l->lm_next;
826 		else
827 			prev->lm_next = l->lm_next;
828 		*result = l;
829 		ld->ld_errno = LDAP_SUCCESS;
830 		return( l->lm_msgtype ); /* Patch 16 : was return(tag) */
831 	}
832 
833 	return( -2 );	/* continue looking */
834 }
835 
836 
837 static int
838 build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr )
839 {
840 	unsigned int	len;
841 	int		along;
842 
843 	Debug (LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1287, "=> building_ber_error msgid %ld\n"), lr->lr_msgid, 0,0);
844 	ber_zero_init( ber, 0 );
845 	set_ber_options( ld, ber );
846 	if (ld->ld_version == LDAP_VERSION3){
847 		if ( ber_printf( ber, "{it{ess",
848 						 lr->lr_msgid,
849 						 lr->lr_res_msgtype,
850 						 lr->lr_res_errno,
851 						 lr->lr_res_matched ? lr->lr_res_matched : "",
852 						 lr->lr_res_error ? lr->lr_res_error : "" ) == LBER_ERROR){
853 			return (LBER_ERROR);
854 		}
855 		if (lr->lr_res_errno == LDAP_REFERRAL &&
856 			ber_printf(ber, "t{v}", LDAP_TAG_REFERRAL, lr->lr_ref_unfollowed) == LBER_ERROR){
857 			return (LBER_ERROR);
858 		}
859 		if (ber_printf(ber, "}}") == LBER_ERROR){
860 			return (LBER_ERROR);
861 		}
862 	} else {
863 		if ( ber_printf( ber, "{it{ess}}",
864 						 lr->lr_msgid,
865 						 lr->lr_res_msgtype,
866 						 lr->lr_res_errno,
867 						 lr->lr_res_matched ? lr->lr_res_matched : "",
868 						 lr->lr_res_error ? lr->lr_res_error : "" ) == LBER_ERROR ) {
869 			return( LBER_ERROR );
870 		}
871 	}
872 
873 	ber_reset( ber, 1 );
874 	if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
875 		return( LBER_ERROR );
876 	}
877 
878 	if ( ber_get_int( ber, &along ) == LBER_ERROR ) {
879 		return( LBER_ERROR );
880 	}
881 
882 	return( ber_peek_tag( ber, &len ));
883 }
884 
885 
886 static void
887 merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
888 {
889 	int i, j;
890 /*
891  * Merge error information in "lr" with "parentr" error code and string.
892  */
893 	if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
894 		parentr->lr_res_errno = lr->lr_res_errno;
895 		if ( lr->lr_res_error != NULL ) {
896 			(void)append_referral( ld, &parentr->lr_res_error,
897 			    lr->lr_res_error );
898 		}
899 	} else if ( lr->lr_res_errno != LDAP_SUCCESS &&
900 	    parentr->lr_res_errno == LDAP_SUCCESS ) {
901 		parentr->lr_res_errno = lr->lr_res_errno;
902 		if ( parentr->lr_res_error != NULL ) {
903 			free( parentr->lr_res_error );
904 		}
905 		parentr->lr_res_error = lr->lr_res_error;
906 		lr->lr_res_error = NULL;
907 		if ( NAME_ERROR( lr->lr_res_errno )) {
908 			if ( parentr->lr_res_matched != NULL ) {
909 				free( parentr->lr_res_matched );
910 			}
911 			parentr->lr_res_matched = lr->lr_res_matched;
912 			lr->lr_res_matched = NULL;
913 		}
914 		if (lr->lr_ref_unfollowed != NULL){
915 			for (i=0;lr->lr_ref_unfollowed[i] != NULL; i++);
916 			j = 0;
917 			if (parentr->lr_ref_unfollowed != NULL){
918 				for (j=0;parentr->lr_ref_unfollowed[j]!= NULL ;j++);
919 				j++;
920 			}
921 			parentr->lr_ref_unfollowed = (char **)realloc (parentr->lr_ref_unfollowed, (j+i+1) * sizeof(char *));
922 			if (parentr->lr_ref_unfollowed != NULL){
923 				for (i = 0; lr->lr_ref_unfollowed[i] != NULL; i++){
924 					parentr->lr_ref_unfollowed[j+i] = lr->lr_ref_unfollowed[i];
925 					lr->lr_ref_unfollowed[i] = NULL;
926 				}
927 				parentr->lr_ref_unfollowed[i+j+1] = NULL;
928 			} else {
929 				if (parentr->lr_res_errno == LDAP_SUCCESS)
930 					parentr->lr_res_errno =  LDAP_NO_MEMORY;
931 			}
932 		}
933 	}
934 
935 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 236, "merged parent (id %1$d) error info:  "),
936 	    parentr->lr_msgid, 0, 0 );
937 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 237, "result errno %1$d, error <%2$s>, matched <%3$s>\n"),
938 		   parentr->lr_res_errno,
939 		   parentr->lr_res_error ? parentr->lr_res_error : "",
940 		   parentr->lr_res_matched ? parentr->lr_res_matched : "" );
941 }
942 
943 #ifdef CLDAP
944 #if !defined( MACOS ) && !defined( DOS ) && !defined( _WIN32 )
945 static int
946 ldap_select1( LDAP *ld, struct timeval *timeout )
947 {
948 	fd_set		readfds;
949 	static int	tblsize;
950 
951 	if ( tblsize == 0 ) {
952 #ifdef USE_SYSCONF
953 		tblsize = (int) sysconf( _SC_OPEN_MAX );
954 #else /* USE_SYSCONF */
955 		tblsize = getdtablesize();
956 #endif /* USE_SYSCONF */
957 	}
958 
959 	FD_ZERO( &readfds );
960 	FD_SET( ld->ld_sb.sb_sd, &readfds );
961 
962 	return( select( tblsize, &readfds, 0, 0, timeout ) );
963 }
964 #endif /* !MACOS */
965 
966 
967 #ifdef MACOS
968 static int
969 ldap_select1( LDAP *ld, struct timeval *timeout )
970 {
971 	return( tcpselect( ld->ld_sb.sb_sd, timeout ));
972 }
973 #endif /* MACOS */
974 
975 
976 #if ( defined( DOS ) && defined( WINSOCK )) || defined( _WIN32 )
977 static int
978 ldap_select1( LDAP *ld, struct timeval *timeout )
979 {
980     fd_set          readfds;
981     int             rc;
982 
983     FD_ZERO( &readfds );
984     FD_SET( ld->ld_sb.sb_sd, &readfds );
985 
986     rc = select( 1, &readfds, 0, 0, timeout );
987     return( rc == SOCKET_ERROR ? -1 : rc );
988 }
989 #endif /* WINSOCK || _WIN32 */
990 
991 
992 #ifdef DOS
993 #ifdef PCNFS
994 static int
995 ldap_select1( LDAP *ld, struct timeval *timeout )
996 {
997 	fd_set	readfds;
998 	int	res;
999 
1000 	FD_ZERO( &readfds );
1001 	FD_SET( ld->ld_sb.sb_sd, &readfds );
1002 
1003 	res = select( FD_SETSIZE, &readfds, NULL, NULL, timeout );
1004 	if ( res == -1 && errno == EINTR) {
1005 		/* We've been CTRL-C'ed at this point.  It'd be nice to
1006 		   carry on but PC-NFS currently won't let us! */
1007 		printf("\n*** CTRL-C ***\n");
1008 		exit(-1);
1009 	}
1010 	return( res );
1011 }
1012 #endif /* PCNFS */
1013 
1014 #ifdef NCSA
1015 static int
1016 ldap_select1( LDAP *ld, struct timeval *timeout )
1017 {
1018 	int rc;
1019 	clock_t	endtime;
1020 
1021 	if ( timeout != NULL ) {
1022 		endtime = timeout->tv_sec * CLK_TCK +
1023 			timeout->tv_usec * CLK_TCK / 1000000 + clock();
1024 	}
1025 
1026 	do {
1027 		Stask();
1028 		rc = netqlen( ld->ld_sb.sb_sd );
1029 	} while ( rc <= 0 && ( timeout == NULL || clock() < endtime ));
1030 
1031 	return( rc > 0 ? 1 : 0 );
1032 }
1033 #endif /* NCSA */
1034 #endif /* DOS */
1035 #endif /* CLDAP */
1036 
1037 
1038 int
1039 ldap_msgfree( LDAPMessage *lm )
1040 {
1041 	LDAPMessage	*next;
1042 	int		type = 0;
1043 
1044 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 238, "ldap_msgfree\n"), 0, 0, 0 );
1045 
1046 	for ( ; lm != NULLMSG; lm = next ) {
1047 		next = lm->lm_chain;
1048 		type = lm->lm_msgtype;
1049 		if (lm->lm_ber)
1050 			ber_free( lm->lm_ber, 1 );
1051 		free( (char *) lm );
1052 	}
1053 
1054 	return( type );
1055 }
1056 
1057 /*
1058  * ldap_msgdelete - delete a message.  It returns:
1059  *	0	if the entire message was deleted
1060  *	-1	if the message was not found, or only part of it was found
1061  */
1062 int
1063 ldap_msgdelete( LDAP *ld, int msgid )
1064 {
1065 	LDAPMessage	*lm, *prev;
1066 
1067 #ifdef _REENTRANT
1068 	LOCK_LDAP(ld);
1069 	LOCK_RESPONSE(ld);
1070 #endif
1071 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 239, "ldap_msgdelete\n"), 0, 0, 0 );
1072 
1073 	prev = NULLMSG;
1074 	for ( lm = ld->ld_responses; lm != NULLMSG; lm = lm->lm_next ) {
1075 		if ( lm->lm_msgid == msgid )
1076 			break;
1077 		prev = lm;
1078 	}
1079 
1080 	if ( lm == NULLMSG ) {
1081 #ifdef _REENTRANT
1082 		UNLOCK_LDAP(ld);
1083 		UNLOCK_RESPONSE(ld);
1084 #endif
1085 		return( -1 );
1086 	}
1087 
1088 	if ( prev == NULLMSG )
1089 		ld->ld_responses = lm->lm_next;
1090 	else
1091 		prev->lm_next = lm->lm_next;
1092 
1093 	if ( ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY ) {
1094 #ifdef _REENTRANT
1095 		UNLOCK_LDAP(ld);
1096 		UNLOCK_RESPONSE(ld);
1097 #endif
1098 		return( -1 );
1099 	}
1100 
1101 #ifdef _REENTRANT
1102 	UNLOCK_LDAP(ld);
1103 	UNLOCK_RESPONSE(ld);
1104 #endif
1105 	return( 0 );
1106 }
1107 
1108 
1109 /*
1110  * return 1 if message msgid is waiting to be abandoned, 0 otherwise
1111  */
1112 static int
1113 ldap_abandoned( LDAP *ld, int msgid )
1114 {
1115 	int	i;
1116 
1117 	if ( ld == NULL ) return(1);
1118 	if ( ld->ld_abandoned == NULL )
1119 		return( 0 );
1120 
1121 	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
1122 		if ( ld->ld_abandoned[i] == msgid )
1123 			return( 1 );
1124 
1125 	return( 0 );
1126 }
1127 
1128 
1129 static int
1130 ldap_mark_abandoned( LDAP *ld, int msgid )
1131 {
1132 	int	i;
1133 
1134 	if ( ld->ld_abandoned == NULL )
1135 		return( -1 );
1136 
1137 	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
1138 		if ( ld->ld_abandoned[i] == msgid )
1139 			break;
1140 
1141 	if ( ld->ld_abandoned[i] == -1 )
1142 		return( -1 );
1143 
1144 	for ( ; ld->ld_abandoned[i] != -1; i++ ) {
1145 		ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
1146 	}
1147 
1148 	return( 0 );
1149 }
1150 
1151 
1152 #ifdef CLDAP
1153 int
1154 cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber )
1155 {
1156 	int		rc;
1157 	unsigned int	tag, len;
1158 
1159 #ifdef _REENTRANT
1160 	LOCK_LDAP(ld);
1161 #endif
1162 	if ( ld->ld_sb.sb_ber.ber_ptr >= ld->ld_sb.sb_ber.ber_end ) {
1163 		rc = ldap_select1( ld, timeout );
1164 		if ( rc == -1 || rc == 0 ) {
1165 			ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
1166 			    LDAP_TIMEOUT);
1167 #ifdef _REENTRANT
1168 			UNLOCK_LDAP(ld);
1169 #endif
1170 			return( rc );
1171 		}
1172 	}
1173 
1174 	/* get the next message */
1175 	if ( (tag = ber_get_next( &ld->ld_sb, &len, ber ))
1176 	    != LDAP_TAG_MESSAGE ) {
1177 		ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
1178 		    LDAP_LOCAL_ERROR);
1179 #ifdef _REENTRANT
1180 		UNLOCK_LDAP(ld);
1181 #endif
1182 		return( -1 );
1183 	}
1184 
1185 #ifdef _REENTRANT
1186 	UNLOCK_LDAP(ld);
1187 #endif
1188 	return( tag );
1189 }
1190 #endif /* CLDAP */
1191 
1192 /* ldapv3 API extensions */
1193 
1194 int ldap_msgtype(LDAPMessage *res)
1195 {
1196 	if (res == NULL)
1197 		return (LDAP_RES_ANY);
1198 	return (res->lm_msgtype);
1199 }
1200 
1201 
1202 int ldap_msgid(LDAPMessage *res)
1203 {
1204 	if (res == NULL)
1205 		return (LDAP_RES_ANY);
1206 	return (res->lm_msgid);
1207 }
1208 
1209 int ldap_parse_result(LDAP *ld, LDAPMessage *res, int *errcodep, char **matcheddnp,
1210 					  char **errmsgp, char ***referralsp, LDAPControl ***serverctrlsp,
1211 					  int freeit)
1212 {
1213 	LDAPMessage *lm;
1214 	BerElement ber;
1215 	unsigned int alen;
1216 	int along;
1217 	unsigned int tag;
1218 	int i;
1219 	size_t rc;
1220 	char * acharp = NULL, * a2ndcharp = NULL;
1221 	char ** arefs = NULL;
1222 
1223 	Debug( LDAP_DEBUG_TRACE, "ldap_parse_result\n", 0, 0, 0 );
1224 
1225 	if (res == NULLMSG)
1226 		return (LDAP_PARAM_ERROR);
1227 
1228 	if (matcheddnp && *matcheddnp){
1229 		free(*matcheddnp);
1230 		*matcheddnp = NULL;
1231 	}
1232 	if (errmsgp && *errmsgp){
1233 		free(*errmsgp);
1234 		*errmsgp = NULL;
1235 	}
1236 	if (referralsp && *referralsp){
1237 		free_strarray(*referralsp);
1238 		*referralsp = NULL;
1239 	}
1240 
1241 	if (serverctrlsp && *serverctrlsp){
1242 		ldap_controls_free(*serverctrlsp);
1243 		*serverctrlsp = NULL;
1244 	}
1245 
1246 	for (lm = res; lm->lm_chain != NULL; lm = lm->lm_chain)
1247 
1248 		if ( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY
1249 			 && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE)
1250 			break;
1251 
1252 	ber = *(lm->lm_ber);
1253 
1254 #ifdef _REENTRANT
1255 	LOCK_LDAP(ld);
1256 #endif
1257 	if (ld->ld_version == LDAP_VERSION3) {
1258 		rc = ber_scanf( &ber, "{iaa", &along, &acharp, &a2ndcharp);
1259 		if (rc == LBER_ERROR){
1260 			if (freeit)
1261 				ldap_msgfree( res );
1262 #ifdef _REENTRANT
1263 			UNLOCK_LDAP(ld);
1264 #endif
1265 			return (LDAP_DECODING_ERROR);
1266 		}
1267 		if (matcheddnp) {
1268 			*matcheddnp = acharp;
1269 		} else {
1270 			ldap_memfree(acharp);
1271 		}
1272 		if (errmsgp) {
1273 			*errmsgp = a2ndcharp;
1274 		} else {
1275 			ldap_memfree(a2ndcharp);
1276 		}
1277 
1278 		if (errcodep) {
1279 			*errcodep = along;
1280 		}
1281 
1282 		if (along == LDAP_REFERRAL){
1283 			if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_REFERRAL) {
1284 				rc = ber_scanf(&ber, "{v}", &arefs);
1285 				if (rc == LBER_ERROR){
1286 					/* try to free other stuff */
1287 					if (freeit)
1288 						ldap_msgfree( res );
1289 #ifdef _REENTRANT
1290 					UNLOCK_LDAP(ld);
1291 #endif
1292 					return (LDAP_DECODING_ERROR);
1293 				}
1294 				if (referralsp) {
1295 					*referralsp = arefs;
1296 				} else {
1297 					for (i = 0; arefs[i] != NULL; i++)
1298 						ldap_memfree(arefs[i]);
1299 					ldap_memfree((char *)arefs);
1300 				}
1301 			} else {
1302 				/* referral errcode without URL is forbiden */
1303 				if (freeit)
1304 					ldap_msgfree( res );
1305 #ifdef _REENTRANT
1306 				UNLOCK_LDAP(ld);
1307 #endif
1308 				return (LDAP_DECODING_ERROR);
1309 			}
1310 		}
1311 		rc = ber_scanf(&ber, "}");
1312 		if (rc == LBER_ERROR){
1313 			if (freeit)
1314 				ldap_msgfree( res );
1315 #ifdef _REENTRANT
1316 			UNLOCK_LDAP(ld);
1317 #endif
1318 			return (LDAP_DECODING_ERROR);
1319 		}
1320 		/* It's the end of the result but the PDU may have controls */
1321 		if (serverctrlsp && (ber_peek_tag(&ber, &alen) == LDAP_TAG_CONTROL_LIST)) {
1322 			Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 392, "Controls found in result\n"), 0, 0, 0 );
1323 			*serverctrlsp =  ldap_controls_decode(&ber,
1324 							    (int *)&rc);
1325 			if (*serverctrlsp == NULL) {
1326 				if (freeit)
1327 					ldap_msgfree( res );
1328 #ifdef _REENTRANT
1329 				UNLOCK_LDAP(ld);
1330 #endif
1331 				return (LDAP_DECODING_ERROR);
1332 			}
1333 		} else {
1334 			Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 393, "NO controls found in result\n"), 0, 0, 0 );
1335 		}
1336 	}
1337 	else if (ld->ld_version == LDAP_VERSION2) {
1338 		rc = ber_scanf( &ber, "{iaa}", &along, &acharp,
1339 		     &a2ndcharp );
1340 		if (rc == LBER_ERROR){
1341 			if (freeit)
1342 				ldap_msgfree( res );
1343 #ifdef _REENTRANT
1344 			UNLOCK_LDAP(ld);
1345 #endif
1346 			return (LDAP_DECODING_ERROR);
1347 		}
1348 		if (matcheddnp) {
1349 			*matcheddnp = acharp;
1350 		} else {
1351 			ldap_memfree(acharp);
1352 		}
1353 		if (errmsgp) {
1354 			*errmsgp = a2ndcharp;
1355 		} else {
1356 			ldap_memfree(a2ndcharp);
1357 		}
1358 		if (errcodep) {
1359 			*errcodep = along;
1360 		}
1361 	}
1362 	else {
1363 		rc = ber_scanf( &ber, "{ia}", &along, &a2ndcharp );
1364 		if (rc == LBER_ERROR){
1365 			if (freeit)
1366 				ldap_msgfree( res );
1367 #ifdef _REENTRANT
1368 			UNLOCK_LDAP(ld);
1369 #endif
1370 			return (LDAP_DECODING_ERROR);
1371 		}
1372 
1373 		if (errmsgp) {
1374 			*errmsgp = a2ndcharp;
1375 		} else {
1376 			ldap_memfree(a2ndcharp);
1377 		}
1378 		if (errcodep) {
1379 			*errcodep = along;
1380 		}
1381 	}
1382 
1383 	if ( freeit )
1384 		ldap_msgfree(res);
1385 
1386 #ifdef _REENTRANT
1387 	UNLOCK_LDAP(ld);
1388 #endif
1389 	return (LDAP_SUCCESS);
1390 }
1391 
1392 int ldap_parse_sasl_bind_result(LDAP *ld, LDAPMessage *res, struct berval **servercredp, int freeit)
1393 {
1394 	LDAPMessage *lm;
1395 	BerElement ber;
1396 	int along;
1397 	unsigned int tag;
1398 	int i;
1399 	size_t rc;
1400 	char * acharp = NULL, *a2ndcharp = NULL;
1401 	char ** arefs = NULL;
1402 	struct berval * creds = NULL;
1403 
1404 	Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
1405 
1406 	if (res == NULLMSG)
1407 		return (LDAP_PARAM_ERROR);
1408 
1409 #ifdef _REENTRANT
1410 	LOCK_LDAP(ld);
1411 #endif
1412 	if ((res->lm_msgtype != LDAP_RES_BIND) || (ld->ld_version != LDAP_VERSION3)){
1413 		ld->ld_errno = LDAP_PARAM_ERROR;
1414 #ifdef _REENTRANT
1415 		UNLOCK_LDAP(ld);
1416 #endif
1417 		return (LDAP_PARAM_ERROR);
1418 	}
1419 #ifdef _REENTRANT
1420 	UNLOCK_LDAP(ld);
1421 #endif
1422 
1423 	ber = *(res->lm_ber);
1424 	rc = ber_scanf( &ber, "{iaa", &along, &acharp, &a2ndcharp);
1425 	if (rc == LBER_ERROR){
1426 		if (freeit)
1427 			ldap_msgfree( res );
1428 #ifdef _REENTRANT
1429 		LOCK_LDAP(ld);
1430 #endif
1431 		ld->ld_errno = LDAP_DECODING_ERROR;
1432 #ifdef _REENTRANT
1433 		UNLOCK_LDAP(ld);
1434 #endif
1435 		return (LDAP_DECODING_ERROR);
1436 	}
1437 	ldap_memfree(acharp);
1438 	ldap_memfree(a2ndcharp);
1439 	if (along == LDAP_SUCCESS || along == LDAP_SASL_BIND_INPROGRESS){
1440 		/* Decode the serverSaslCreds if any */
1441 		if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_SASLCREDS) {
1442 			rc = ber_get_stringal( &ber, &creds);
1443 			if (rc == LBER_ERROR ){
1444 				if (freeit)
1445 					ldap_msgfree(res);
1446 #ifdef _REENTRANT
1447 				LOCK_LDAP(ld);
1448 #endif
1449 				ld->ld_errno = LDAP_DECODING_ERROR;
1450 #ifdef _REENTRANT
1451 				UNLOCK_LDAP(ld);
1452 #endif
1453 				return (LDAP_DECODING_ERROR);
1454 			}
1455 			if (servercredp) {
1456 				*servercredp = creds;
1457 			} else {
1458 				ber_bvfree( creds );
1459 			}
1460 		}
1461 	} else if (along == LDAP_REFERRAL) {
1462 		if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_REFERRAL){
1463 			rc = ber_scanf(&ber, "{v}", &arefs);
1464 			if (rc == LBER_ERROR){
1465 				/* try to free other stuff */
1466 				if (freeit)
1467 					ldap_msgfree( res );
1468 #ifdef _REENTRANT
1469 				LOCK_LDAP(ld);
1470 #endif
1471 				ld->ld_errno = LDAP_DECODING_ERROR;
1472 #ifdef _REENTRANT
1473 				UNLOCK_LDAP(ld);
1474 #endif
1475 				return (LDAP_DECODING_ERROR);
1476 			}
1477 			for (i = 0; arefs[i] != NULL; i++)
1478 				ldap_memfree(arefs[i]);
1479 			ldap_memfree((char *)arefs);
1480 		} else {
1481 			/* There should be at least one ref */
1482 			if (freeit)
1483 				ldap_msgfree( res );
1484 #ifdef _REENTRANT
1485 			LOCK_LDAP(ld);
1486 #endif
1487 			ld->ld_errno = LDAP_DECODING_ERROR;
1488 #ifdef _REENTRANT
1489 			UNLOCK_LDAP(ld);
1490 #endif
1491 			return (LDAP_DECODING_ERROR);
1492 		}
1493 	}
1494 
1495 	rc = ber_scanf(&ber, "}");
1496 	if (rc == LBER_ERROR){
1497 		if (freeit)
1498 			ldap_msgfree( res );
1499 #ifdef _REENTRANT
1500 		LOCK_LDAP(ld);
1501 #endif
1502 		ld->ld_errno = LDAP_DECODING_ERROR;
1503 #ifdef _REENTRANT
1504 		UNLOCK_LDAP(ld);
1505 #endif
1506 		return (LDAP_DECODING_ERROR);
1507 	}
1508 
1509 	if ( freeit )
1510 		ldap_msgfree(res);
1511 #ifdef _REENTRANT
1512 	LOCK_LDAP(ld);
1513 #endif
1514 	ld->ld_errno = along;
1515 #ifdef _REENTRANT
1516 	UNLOCK_LDAP(ld);
1517 #endif
1518 	return (along);
1519 }
1520 
1521 int ldap_parse_extended_result(LDAP *ld, LDAPMessage *res, char **resultoidp,
1522 							   struct berval **resultdata, int freeit)
1523 {
1524 	LDAPMessage *lm;
1525 	BerElement ber;
1526 	int along;
1527 	unsigned int tag;
1528 	int i;
1529 	size_t rc;
1530 	char * acharp = NULL, *a2ndcharp = NULL, *anoid = NULL;
1531 	char **arefs = NULL;
1532 	struct berval * aresp = NULL;
1533 
1534 	Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
1535 
1536 	if ( res == NULLMSG )
1537 		return (LDAP_PARAM_ERROR);
1538 
1539 #ifdef _REENTRANT
1540 	LOCK_LDAP(ld);
1541 #endif
1542 	if ((res->lm_msgtype != LDAP_RES_EXTENDED) || (ld->ld_version != LDAP_VERSION3))
1543 	{
1544 		if ( res->lm_msgid != 0 )
1545 #ifdef _REENTRANT
1546 			UNLOCK_LDAP(ld);
1547 #endif
1548 			return (LDAP_PARAM_ERROR);
1549 	}
1550 #ifdef _REENTRANT
1551 	UNLOCK_LDAP(ld);
1552 #endif
1553 
1554 	ber = *(res->lm_ber);
1555 	rc = ber_scanf( &ber, "{iaa", &along, &acharp, &a2ndcharp);
1556 	if (rc == LBER_ERROR){
1557 		if (freeit)
1558 			ldap_msgfree( res );
1559 		return (LDAP_DECODING_ERROR);
1560 	}
1561 	ldap_memfree(acharp);
1562 	ldap_memfree(a2ndcharp);
1563 
1564 	if (along == LDAP_REFERRAL) {
1565 		if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_REFERRAL){
1566 			rc = ber_scanf(&ber, "{v}", &arefs);
1567 			if (rc == LBER_ERROR){
1568 				/* try to free other stuff */
1569 				if (freeit)
1570 					ldap_msgfree( res );
1571 				return (LDAP_DECODING_ERROR);
1572 			}
1573 			for (i = 0; arefs[i] != NULL; i++)
1574 				ldap_memfree(arefs[i]);
1575 			ldap_memfree((char *)arefs);
1576 		} else {
1577 			/* There should be at least one ref */
1578 			if (freeit)
1579 				ldap_msgfree( res );
1580 			return (LDAP_DECODING_ERROR);
1581 		}
1582 	}
1583 
1584 	if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_EXT_RESPNAME) {
1585 		rc = ber_get_stringa( &ber, &anoid);
1586 		if (rc == LBER_ERROR ){
1587 			if (freeit)
1588 				ldap_msgfree(res);
1589 			return (LDAP_DECODING_ERROR);
1590 		}
1591 		if (resultoidp) {
1592 			*resultoidp = anoid;
1593 		} else {
1594 			ldap_memfree( anoid );
1595 		}
1596 	}
1597 	if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_EXT_RESPONSE) {
1598 		rc = ber_get_stringal( &ber, &aresp);
1599 		if (rc == LBER_ERROR ){
1600 			if (freeit)
1601 				ldap_msgfree(res);
1602 			return (LDAP_DECODING_ERROR);
1603 		}
1604 		if (resultdata) {
1605 			*resultdata = aresp;
1606 		} else {
1607 			ber_bvfree( aresp );
1608 		}
1609 	}
1610 
1611 	rc = ber_scanf(&ber, "}");
1612 	if (rc == LBER_ERROR){
1613 		if (freeit)
1614 			ldap_msgfree( res );
1615 		return (LDAP_DECODING_ERROR);
1616 	}
1617 
1618 	if ( freeit )
1619 		ldap_msgfree(res);
1620 
1621 	return (along);
1622 }
1623 
1624 
1625 static int Ref_AddToRequest(LDAPRequest *lr, char **refs) {
1626 	int count;
1627 	LDAPRef *lref;
1628 	LDAPRef *newRef;
1629 
1630 	if ((newRef = (LDAPRef *)calloc(1, sizeof (LDAPRef))) == NULL){
1631 		return LDAP_NO_MEMORY;
1632 	}
1633 	newRef->lref_refs = refs;
1634 	newRef->lref_next = NULL;
1635 	lref = lr->lr_references;
1636 	if (lref == NULL){
1637 		lr->lr_references = newRef;
1638 	} else {
1639 		while (lref->lref_next != NULL)
1640 			lref = lref->lref_next;
1641 		lref->lref_next = newRef;
1642 	}
1643 	return LDAP_SUCCESS;
1644 }
1645 
1646 static void Ref_FreeAll(LDAPRequest *lr)
1647 {
1648 	LDAPRef *lref, *next;
1649 	lref = lr->lr_references;
1650 	while (lref != NULL){
1651 		next = lref->lref_next;
1652 		ldap_value_free(lref->lref_refs);
1653 		free (lref);
1654 		lref = next;
1655 	}
1656 	lr->lr_references = NULL;
1657 }
1658