17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public License
97c478bd9Sstevel@tonic-gate  * Version 1.0 (the "NPL"); you may not use this file except in
107c478bd9Sstevel@tonic-gate  * compliance with the NPL.  You may obtain a copy of the NPL at
117c478bd9Sstevel@tonic-gate  * http://www.mozilla.org/NPL/
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Software distributed under the NPL is distributed on an "AS IS" basis,
147c478bd9Sstevel@tonic-gate  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
157c478bd9Sstevel@tonic-gate  * for the specific language governing rights and limitations under the
167c478bd9Sstevel@tonic-gate  * NPL.
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  * The Initial Developer of this code under the NPL is Netscape
197c478bd9Sstevel@tonic-gate  * Communications Corporation.  Portions created by Netscape are
207c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
217c478bd9Sstevel@tonic-gate  * Reserved.
227c478bd9Sstevel@tonic-gate  */
237c478bd9Sstevel@tonic-gate /*
247c478bd9Sstevel@tonic-gate  *  Copyright (c) 1990 Regents of the University of Michigan.
257c478bd9Sstevel@tonic-gate  *  All rights reserved.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  *  result.c - wait for an ldap result
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #if 0
32*1da57d55SToomas Soome #ifndef lint
337c478bd9Sstevel@tonic-gate static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
347c478bd9Sstevel@tonic-gate #endif
357c478bd9Sstevel@tonic-gate #endif
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include "ldap-int.h"
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
407c478bd9Sstevel@tonic-gate /* high resolution timer usage */
417c478bd9Sstevel@tonic-gate #include <sys/time.h>
427c478bd9Sstevel@tonic-gate #endif
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static int check_response_queue( LDAP *ld, int msgid, int all,
457c478bd9Sstevel@tonic-gate 	int do_abandon_check, LDAPMessage **result );
467c478bd9Sstevel@tonic-gate static int ldap_abandoned( LDAP *ld, int msgid );
477c478bd9Sstevel@tonic-gate static int ldap_mark_abandoned( LDAP *ld, int msgid );
487c478bd9Sstevel@tonic-gate static int wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
497c478bd9Sstevel@tonic-gate 	struct timeval *timeout, LDAPMessage **result );
507c478bd9Sstevel@tonic-gate static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
517c478bd9Sstevel@tonic-gate 	LDAPMessage **result );
527c478bd9Sstevel@tonic-gate static void check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
537c478bd9Sstevel@tonic-gate 	int ldapversion, int *totalcountp, int *chasingcountp );
547c478bd9Sstevel@tonic-gate static int build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr );
557c478bd9Sstevel@tonic-gate static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
567c478bd9Sstevel@tonic-gate #if defined( CLDAP )
577c478bd9Sstevel@tonic-gate static int cldap_select1( LDAP *ld, struct timeval *timeout );
587c478bd9Sstevel@tonic-gate #endif
597c478bd9Sstevel@tonic-gate static void link_pend( LDAP *ld, LDAPPend *lp );
607c478bd9Sstevel@tonic-gate #if 0 /* these functions are no longer used */
617c478bd9Sstevel@tonic-gate static void unlink_pend( LDAP *ld, LDAPPend *lp );
627c478bd9Sstevel@tonic-gate static int unlink_msg( LDAP *ld, int msgid, int all );
637c478bd9Sstevel@tonic-gate #endif /* 0 */
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate  * ldap_result - wait for an ldap result response to a message from the
677c478bd9Sstevel@tonic-gate  * ldap server.  If msgid is -1, any message will be accepted, otherwise
687c478bd9Sstevel@tonic-gate  * ldap_result will wait for a response with msgid.  If all is 0 the
697c478bd9Sstevel@tonic-gate  * first message with id msgid will be accepted, otherwise, ldap_result
707c478bd9Sstevel@tonic-gate  * will wait for all responses with id msgid and then return a pointer to
717c478bd9Sstevel@tonic-gate  * the entire list of messages.  This is only useful for search responses,
727c478bd9Sstevel@tonic-gate  * which can be of two message types (zero or more entries, followed by an
737c478bd9Sstevel@tonic-gate  * ldap result).  The type of the first message received is returned.
747c478bd9Sstevel@tonic-gate  * When waiting, any messages that have been abandoned are discarded.
757c478bd9Sstevel@tonic-gate  *
767c478bd9Sstevel@tonic-gate  * Example:
777c478bd9Sstevel@tonic-gate  *	ldap_result( s, msgid, all, timeout, result )
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate int
807c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_result(LDAP * ld,int msgid,int all,struct timeval * timeout,LDAPMessage ** result)817c478bd9Sstevel@tonic-gate ldap_result(
827c478bd9Sstevel@tonic-gate     LDAP 		*ld,
837c478bd9Sstevel@tonic-gate     int 		msgid,
847c478bd9Sstevel@tonic-gate     int 		all,
857c478bd9Sstevel@tonic-gate     struct timeval	*timeout,
867c478bd9Sstevel@tonic-gate     LDAPMessage		**result
877c478bd9Sstevel@tonic-gate )
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate 	int		rc;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
947c478bd9Sstevel@tonic-gate 		return( -1 );	/* punt */
957c478bd9Sstevel@tonic-gate 	}
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK );
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	rc = nsldapi_result_nolock(ld, msgid, all, 1, timeout, result);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK );
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	return( rc );
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate int
nsldapi_result_nolock(LDAP * ld,int msgid,int all,int unlock_permitted,struct timeval * timeout,LDAPMessage ** result)1087c478bd9Sstevel@tonic-gate nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted,
1097c478bd9Sstevel@tonic-gate     struct timeval *timeout, LDAPMessage **result )
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	int		rc;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
1147c478bd9Sstevel@tonic-gate 		"nsldapi_result_nolock (msgid=%d, all=%d)\n", msgid, all, 0 );
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	/*
1177c478bd9Sstevel@tonic-gate 	 * First, look through the list of responses we have received on
1187c478bd9Sstevel@tonic-gate 	 * this association and see if the response we're interested in
1197c478bd9Sstevel@tonic-gate 	 * is there.  If it is, return it.  If not, call wait4msg() to
1207c478bd9Sstevel@tonic-gate 	 * wait until it arrives or timeout occurs.
1217c478bd9Sstevel@tonic-gate 	 */
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	if ( result == NULL ) {
1247c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
1257c478bd9Sstevel@tonic-gate 		return( -1 );
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	if ( check_response_queue( ld, msgid, all, 1, result ) != 0 ) {
1297c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
1307c478bd9Sstevel@tonic-gate 		rc = (*result)->lm_msgtype;
1317c478bd9Sstevel@tonic-gate 	} else {
1327c478bd9Sstevel@tonic-gate 		rc = wait4msg( ld, msgid, all, unlock_permitted, timeout,
1337c478bd9Sstevel@tonic-gate 		    result );
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	/*
1377c478bd9Sstevel@tonic-gate 	 * XXXmcs should use cache function pointers to hook in memcache
1387c478bd9Sstevel@tonic-gate 	 */
1397c478bd9Sstevel@tonic-gate 	if ( ld->ld_memcache != NULL && NSLDAPI_SEARCH_RELATED_RESULT( rc ) &&
1407c478bd9Sstevel@tonic-gate 	     !((*result)->lm_fromcache )) {
1417c478bd9Sstevel@tonic-gate 		ldap_memcache_append( ld, (*result)->lm_msgid,
1427c478bd9Sstevel@tonic-gate 		    (all || NSLDAPI_IS_SEARCH_RESULT( rc )), *result );
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	return( rc );
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * Look through the list of queued responses for a message that matches the
1517c478bd9Sstevel@tonic-gate  * criteria in the msgid and all parameters.  msgid == LDAP_RES_ANY matches
1527c478bd9Sstevel@tonic-gate  * all ids.
1537c478bd9Sstevel@tonic-gate  *
1547c478bd9Sstevel@tonic-gate  * If an appropriate message is found, a non-zero value is returned and the
1557c478bd9Sstevel@tonic-gate  * message is dequeued and assigned to *result.
1567c478bd9Sstevel@tonic-gate  *
1577c478bd9Sstevel@tonic-gate  * If not, *result is set to NULL and this function returns 0.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static int
check_response_queue(LDAP * ld,int msgid,int all,int do_abandon_check,LDAPMessage ** result)1607c478bd9Sstevel@tonic-gate check_response_queue( LDAP *ld, int msgid, int all, int do_abandon_check,
1617c478bd9Sstevel@tonic-gate     LDAPMessage **result )
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate 	LDAPMessage	*lm, *lastlm, *nextlm;
1647c478bd9Sstevel@tonic-gate 	LDAPRequest	*lr;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
1677c478bd9Sstevel@tonic-gate 	    "=> check_response_queue (msgid=%d, all=%d)\n", msgid, all, 0 );
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	*result = NULL;
1707c478bd9Sstevel@tonic-gate 	lastlm = NULL;
1717c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
1727c478bd9Sstevel@tonic-gate 	for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
1737c478bd9Sstevel@tonic-gate 		nextlm = lm->lm_next;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 		if ( do_abandon_check && ldap_abandoned( ld, lm->lm_msgid ) ) {
1767c478bd9Sstevel@tonic-gate 			ldap_mark_abandoned( ld, lm->lm_msgid );
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 			if ( lastlm == NULL ) {
1797c478bd9Sstevel@tonic-gate 				ld->ld_responses = lm->lm_next;
1807c478bd9Sstevel@tonic-gate 			} else {
1817c478bd9Sstevel@tonic-gate 				lastlm->lm_next = nextlm;
1827c478bd9Sstevel@tonic-gate 			}
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 			ldap_msgfree( lm );
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 			continue;
1877c478bd9Sstevel@tonic-gate 		}
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 		if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
1907c478bd9Sstevel@tonic-gate 			LDAPMessage	*tmp;
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 			if ( all == 0
1937c478bd9Sstevel@tonic-gate 			    || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
1947c478bd9Sstevel@tonic-gate 			    && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
1957c478bd9Sstevel@tonic-gate 			    && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
1967c478bd9Sstevel@tonic-gate 				break;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 			for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
1997c478bd9Sstevel@tonic-gate 				if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
2007c478bd9Sstevel@tonic-gate 					break;
2017c478bd9Sstevel@tonic-gate 			}
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 			if ( tmp == NULL ) {
2047c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
2057c478bd9Sstevel@tonic-gate 				LDAPDebug( LDAP_DEBUG_TRACE,
2067c478bd9Sstevel@tonic-gate 				    "<= check_response_queue NOT FOUND\n",
2077c478bd9Sstevel@tonic-gate 				    0, 0, 0 );
2087c478bd9Sstevel@tonic-gate 				return( 0 );	/* no message to return */
2097c478bd9Sstevel@tonic-gate 			}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 			break;
2127c478bd9Sstevel@tonic-gate 		}
2137c478bd9Sstevel@tonic-gate 		lastlm = lm;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	/*
2177c478bd9Sstevel@tonic-gate 	 * if we did not find a message OR if the one we found is a result for
2187c478bd9Sstevel@tonic-gate 	 * a request that is still pending, return failure.
2197c478bd9Sstevel@tonic-gate 	 */
220*1da57d55SToomas Soome 	if ( lm == NULL
2217c478bd9Sstevel@tonic-gate              || (( lr = nsldapi_find_request_by_msgid( ld, lm->lm_msgid ))
2227c478bd9Sstevel@tonic-gate 		   != NULL && lr->lr_outrefcnt > 0 )) {
2237c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
2247c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_TRACE,
2257c478bd9Sstevel@tonic-gate 		    "<= check_response_queue NOT FOUND\n",
2267c478bd9Sstevel@tonic-gate 		    0, 0, 0 );
2277c478bd9Sstevel@tonic-gate 		return( 0 );	/* no message to return */
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	if ( all == 0 ) {
2317c478bd9Sstevel@tonic-gate 		if ( lm->lm_chain == NULL ) {
2327c478bd9Sstevel@tonic-gate 			if ( lastlm == NULL ) {
2337c478bd9Sstevel@tonic-gate 				ld->ld_responses = lm->lm_next;
2347c478bd9Sstevel@tonic-gate 			} else {
2357c478bd9Sstevel@tonic-gate 				lastlm->lm_next = lm->lm_next;
2367c478bd9Sstevel@tonic-gate 			}
2377c478bd9Sstevel@tonic-gate 		} else {
2387c478bd9Sstevel@tonic-gate 			if ( lastlm == NULL ) {
2397c478bd9Sstevel@tonic-gate 				ld->ld_responses = lm->lm_chain;
2407c478bd9Sstevel@tonic-gate 				ld->ld_responses->lm_next = lm->lm_next;
2417c478bd9Sstevel@tonic-gate 			} else {
2427c478bd9Sstevel@tonic-gate 				lastlm->lm_next = lm->lm_chain;
2437c478bd9Sstevel@tonic-gate 				lastlm->lm_next->lm_next = lm->lm_next;
2447c478bd9Sstevel@tonic-gate 			}
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 	} else {
2477c478bd9Sstevel@tonic-gate 		if ( lastlm == NULL ) {
2487c478bd9Sstevel@tonic-gate 			ld->ld_responses = lm->lm_next;
2497c478bd9Sstevel@tonic-gate 		} else {
2507c478bd9Sstevel@tonic-gate 			lastlm->lm_next = lm->lm_next;
2517c478bd9Sstevel@tonic-gate 		}
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	if ( all == 0 ) {
2557c478bd9Sstevel@tonic-gate 		lm->lm_chain = NULL;
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 	lm->lm_next = NULL;
2587c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	*result = lm;
2617c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
2627c478bd9Sstevel@tonic-gate 	    "<= check_response_queue returning msgid %d type %d\n",
2637c478bd9Sstevel@tonic-gate 	    lm->lm_msgid, lm->lm_msgtype, 0 );
2647c478bd9Sstevel@tonic-gate 	return( 1 );	/* a message was found and returned in *result */
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate static int
wait4msg(LDAP * ld,int msgid,int all,int unlock_permitted,struct timeval * timeout,LDAPMessage ** result)2697c478bd9Sstevel@tonic-gate wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
2707c478bd9Sstevel@tonic-gate 	struct timeval *timeout, LDAPMessage **result )
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	int		rc;
2737c478bd9Sstevel@tonic-gate 	struct timeval	tv, *tvp;
2747c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
2757c478bd9Sstevel@tonic-gate 	hrtime_t	start_time = 0, tmp_time, tv_time;
2767c478bd9Sstevel@tonic-gate #else
2777c478bd9Sstevel@tonic-gate 	long		start_time = 0, tmp_time;
2787c478bd9Sstevel@tonic-gate #endif
2797c478bd9Sstevel@tonic-gate 	LDAPConn	*lc, *nextlc;
2807c478bd9Sstevel@tonic-gate 	LDAPRequest	*lr;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate #ifdef LDAP_DEBUG
2837c478bd9Sstevel@tonic-gate 	if ( timeout == NULL ) {
2847c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",
2857c478bd9Sstevel@tonic-gate 		    0, 0, 0 );
2867c478bd9Sstevel@tonic-gate 	} else {
2877c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",
2887c478bd9Sstevel@tonic-gate 		    timeout->tv_sec, timeout->tv_usec, 0 );
2897c478bd9Sstevel@tonic-gate 	}
2907c478bd9Sstevel@tonic-gate #endif /* LDAP_DEBUG */
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/* check the cache */
2937c478bd9Sstevel@tonic-gate 	if ( ld->ld_cache_on && ld->ld_cache_result != NULL ) {
2947c478bd9Sstevel@tonic-gate 		/* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */
2957c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
2967c478bd9Sstevel@tonic-gate 		rc = (ld->ld_cache_result)( ld, msgid, all, timeout, result );
2977c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
2987c478bd9Sstevel@tonic-gate 		/* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
2997c478bd9Sstevel@tonic-gate 		if ( rc != 0 ) {
3007c478bd9Sstevel@tonic-gate 			return( rc );
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 		if ( ld->ld_cache_strategy == LDAP_CACHE_LOCALDB ) {
3037c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL );
3047c478bd9Sstevel@tonic-gate 			return( 0 );	/* timeout */
3057c478bd9Sstevel@tonic-gate 		}
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	/*
3097c478bd9Sstevel@tonic-gate 	 * if we are looking for a specific msgid, check to see if it is
3107c478bd9Sstevel@tonic-gate 	 * associated with a dead connection and return an error if so.
3117c478bd9Sstevel@tonic-gate 	 */
3127c478bd9Sstevel@tonic-gate 	if ( msgid != LDAP_RES_ANY && msgid != LDAP_RES_UNSOLICITED ) {
3137c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
3147c478bd9Sstevel@tonic-gate 		if (( lr = nsldapi_find_request_by_msgid( ld, msgid ))
3157c478bd9Sstevel@tonic-gate 		    == NULL ) {
3167c478bd9Sstevel@tonic-gate 			LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
3177c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL,
3187c478bd9Sstevel@tonic-gate 				nsldapi_strdup( dgettext(TEXT_DOMAIN,
3197c478bd9Sstevel@tonic-gate 					"unknown message id") ));
3207c478bd9Sstevel@tonic-gate 			return( -1 );	/* could not find request for msgid */
3217c478bd9Sstevel@tonic-gate 		}
3227c478bd9Sstevel@tonic-gate 		if ( lr->lr_conn != NULL &&
3237c478bd9Sstevel@tonic-gate 		    lr->lr_conn->lconn_status == LDAP_CONNST_DEAD ) {
3247c478bd9Sstevel@tonic-gate 			nsldapi_free_request( ld, lr, 1 );
3257c478bd9Sstevel@tonic-gate 			LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
3267c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
3277c478bd9Sstevel@tonic-gate 			return( -1 );	/* connection dead */
3287c478bd9Sstevel@tonic-gate 		}
3297c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	if ( timeout == NULL ) {
3337c478bd9Sstevel@tonic-gate 		tvp = NULL;
3347c478bd9Sstevel@tonic-gate 	} else {
3357c478bd9Sstevel@tonic-gate 		tv = *timeout;
3367c478bd9Sstevel@tonic-gate 		tvp = &tv;
3377c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
3387c478bd9Sstevel@tonic-gate 		start_time = gethrtime();
3397c478bd9Sstevel@tonic-gate 		tv_time = ((hrtime_t)tv.tv_sec * NANOSEC +
3407c478bd9Sstevel@tonic-gate 			(hrtime_t)tv.tv_usec * (NANOSEC / MICROSEC));
3417c478bd9Sstevel@tonic-gate #else
3427c478bd9Sstevel@tonic-gate 		start_time = (long)time( NULL );
3437c478bd9Sstevel@tonic-gate #endif
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	rc = -2;
3477c478bd9Sstevel@tonic-gate 	while ( rc == -2 ) {
3487c478bd9Sstevel@tonic-gate #ifdef LDAP_DEBUG
3497c478bd9Sstevel@tonic-gate 		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
3507c478bd9Sstevel@tonic-gate 			nsldapi_dump_connection( ld, ld->ld_conns, 1 );
3517c478bd9Sstevel@tonic-gate 			nsldapi_dump_requests_and_responses( ld );
3527c478bd9Sstevel@tonic-gate 		}
3537c478bd9Sstevel@tonic-gate #endif /* LDAP_DEBUG */
3547c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
3557c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
3567c478bd9Sstevel@tonic-gate 		for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
3577c478bd9Sstevel@tonic-gate 			if ( lc->lconn_sb->sb_ber.ber_ptr <
3587c478bd9Sstevel@tonic-gate 			    lc->lconn_sb->sb_ber.ber_end ) {
3597c478bd9Sstevel@tonic-gate 				rc = read1msg( ld, msgid, all, lc->lconn_sb,
3607c478bd9Sstevel@tonic-gate 				    lc, result );
3617c478bd9Sstevel@tonic-gate 				break;
3627c478bd9Sstevel@tonic-gate 			}
3637c478bd9Sstevel@tonic-gate 		}
3647c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
3657c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 		if ( lc == NULL ) {
3687c478bd9Sstevel@tonic-gate 			rc = nsldapi_iostatus_poll( ld, tvp );
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate #if defined( LDAP_DEBUG ) && !defined( macintosh ) && !defined( DOS )
3717c478bd9Sstevel@tonic-gate 			if ( rc == -1 ) {
3727c478bd9Sstevel@tonic-gate 			    LDAPDebug( LDAP_DEBUG_TRACE,
3737c478bd9Sstevel@tonic-gate 				    "nsldapi_iostatus_poll returned -1: errno %d\n",
3747c478bd9Sstevel@tonic-gate 				    LDAP_GET_ERRNO( ld ), 0, 0 );
3757c478bd9Sstevel@tonic-gate 			}
3767c478bd9Sstevel@tonic-gate #endif
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate #if !defined( macintosh ) && !defined( DOS )
3797c478bd9Sstevel@tonic-gate 			if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
3807c478bd9Sstevel@tonic-gate 			    LDAP_BITOPT_RESTART ) == 0 ||
3817c478bd9Sstevel@tonic-gate 			    LDAP_GET_ERRNO( ld ) != EINTR ))) {
3827c478bd9Sstevel@tonic-gate #else
3837c478bd9Sstevel@tonic-gate 			if ( rc == -1 || rc == 0 ) {
3847c478bd9Sstevel@tonic-gate #endif
3857c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, (rc == -1 ?
3867c478bd9Sstevel@tonic-gate 				    LDAP_SERVER_DOWN : LDAP_TIMEOUT), NULL,
3877c478bd9Sstevel@tonic-gate 				    NULL );
3887c478bd9Sstevel@tonic-gate 				if ( rc == -1 ) {
3897c478bd9Sstevel@tonic-gate 					LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
3907c478bd9Sstevel@tonic-gate 					nsldapi_connection_lost_nolock( ld,
3917c478bd9Sstevel@tonic-gate 						NULL );
3927c478bd9Sstevel@tonic-gate 					LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
3937c478bd9Sstevel@tonic-gate 				}
3947c478bd9Sstevel@tonic-gate 				return( rc );
3957c478bd9Sstevel@tonic-gate 			}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 			if ( rc == -1 ) {
3987c478bd9Sstevel@tonic-gate 				rc = -2;	/* select interrupted: loop */
3997c478bd9Sstevel@tonic-gate 			} else {
4007c478bd9Sstevel@tonic-gate 				rc = -2;
4017c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
4027c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
4037c478bd9Sstevel@tonic-gate 				for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
4047c478bd9Sstevel@tonic-gate 				    lc = nextlc ) {
4057c478bd9Sstevel@tonic-gate 					nextlc = lc->lconn_next;
4067c478bd9Sstevel@tonic-gate 					if ( lc->lconn_status ==
4077c478bd9Sstevel@tonic-gate 					    LDAP_CONNST_CONNECTED &&
4087c478bd9Sstevel@tonic-gate 					    nsldapi_iostatus_is_read_ready( ld,
4097c478bd9Sstevel@tonic-gate 					    lc->lconn_sb )) {
4107c478bd9Sstevel@tonic-gate 						rc = read1msg( ld, msgid, all,
4117c478bd9Sstevel@tonic-gate 						    lc->lconn_sb, lc, result );
4127c478bd9Sstevel@tonic-gate 					}
4137c478bd9Sstevel@tonic-gate 					else if (ld->ld_options & LDAP_BITOPT_ASYNC) {
4147c478bd9Sstevel@tonic-gate                         if ( lr
4157c478bd9Sstevel@tonic-gate                               && lc->lconn_status == LDAP_CONNST_CONNECTING
4167c478bd9Sstevel@tonic-gate                               && nsldapi_iostatus_is_write_ready( ld,
4177c478bd9Sstevel@tonic-gate 			      lc->lconn_sb ) ) {
4187c478bd9Sstevel@tonic-gate                             rc = nsldapi_ber_flush( ld, lc->lconn_sb, lr->lr_ber, 0, 1 );
4197c478bd9Sstevel@tonic-gate                             if ( rc == 0 ) {
4207c478bd9Sstevel@tonic-gate                                 rc = LDAP_RES_BIND;
4217c478bd9Sstevel@tonic-gate                                 lc->lconn_status = LDAP_CONNST_CONNECTED;
422*1da57d55SToomas Soome 
4237c478bd9Sstevel@tonic-gate                                 lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
4247c478bd9Sstevel@tonic-gate                                 lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
4257c478bd9Sstevel@tonic-gate                                 nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
4267c478bd9Sstevel@tonic-gate                             }
4277c478bd9Sstevel@tonic-gate                             else if ( rc == -1 ) {
4287c478bd9Sstevel@tonic-gate                                 LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
4297c478bd9Sstevel@tonic-gate                                 nsldapi_free_request( ld, lr, 0 );
4307c478bd9Sstevel@tonic-gate                                 nsldapi_free_connection( ld, lc, NULL, NULL,
4317c478bd9Sstevel@tonic-gate 				    0, 0 );
4327c478bd9Sstevel@tonic-gate                             }
4337c478bd9Sstevel@tonic-gate                         }
434*1da57d55SToomas Soome 
4357c478bd9Sstevel@tonic-gate 					}
4367c478bd9Sstevel@tonic-gate 				}
4377c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
4387c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
4397c478bd9Sstevel@tonic-gate 			}
4407c478bd9Sstevel@tonic-gate 		}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 		/*
4437c478bd9Sstevel@tonic-gate 		 * It is possible that recursion occurred while chasing
4447c478bd9Sstevel@tonic-gate 		 * referrals and as a result the message we are looking
4457c478bd9Sstevel@tonic-gate 		 * for may have been placed on the response queue.  Look
4467c478bd9Sstevel@tonic-gate 		 * for it there before continuing so we don't end up
4477c478bd9Sstevel@tonic-gate 		 * waiting on the network for a message that we already
4487c478bd9Sstevel@tonic-gate 		 * received!
4497c478bd9Sstevel@tonic-gate 		 */
4507c478bd9Sstevel@tonic-gate 		if ( rc == -2 &&
4517c478bd9Sstevel@tonic-gate 		    check_response_queue( ld, msgid, all, 0, result ) != 0 ) {
4527c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
4537c478bd9Sstevel@tonic-gate 			rc = (*result)->lm_msgtype;
4547c478bd9Sstevel@tonic-gate 		}
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 		/*
4577c478bd9Sstevel@tonic-gate 		 * honor the timeout if specified
4587c478bd9Sstevel@tonic-gate 		 */
4597c478bd9Sstevel@tonic-gate 		if ( rc == -2 && tvp != NULL ) {
4607c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
4617c478bd9Sstevel@tonic-gate 			tmp_time = gethrtime();
4627c478bd9Sstevel@tonic-gate 			if ((tv_time -=  (tmp_time - start_time)) <= 0) {
4637c478bd9Sstevel@tonic-gate #else
4647c478bd9Sstevel@tonic-gate 			tmp_time = (long)time( NULL );
4657c478bd9Sstevel@tonic-gate 			if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
4667c478bd9Sstevel@tonic-gate #endif
4677c478bd9Sstevel@tonic-gate 				rc = 0;	/* timed out */
4687c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL,
4697c478bd9Sstevel@tonic-gate 				    NULL );
4707c478bd9Sstevel@tonic-gate 				break;
4717c478bd9Sstevel@tonic-gate 			}
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
4747c478bd9Sstevel@tonic-gate 			tv.tv_sec = tv_time / NANOSEC;
4757c478bd9Sstevel@tonic-gate 			tv.tv_usec = (tv_time % NANOSEC) / (NANOSEC / MICROSEC);
4767c478bd9Sstevel@tonic-gate #endif
4777c478bd9Sstevel@tonic-gate 			LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
4787c478bd9Sstevel@tonic-gate 				tv.tv_sec, 0, 0 );
4797c478bd9Sstevel@tonic-gate 			start_time = tmp_time;
4807c478bd9Sstevel@tonic-gate 		}
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	return( rc );
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate /*
4887c478bd9Sstevel@tonic-gate  * read1msg() should be called with LDAP_CONN_LOCK and LDAP_REQ_LOCK locked.
4897c478bd9Sstevel@tonic-gate  */
4907c478bd9Sstevel@tonic-gate static int
4917c478bd9Sstevel@tonic-gate read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
4927c478bd9Sstevel@tonic-gate     LDAPMessage **result )
4937c478bd9Sstevel@tonic-gate {
4947c478bd9Sstevel@tonic-gate 	BerElement	*ber;
4957c478bd9Sstevel@tonic-gate 	LDAPMessage	*new, *l, *prev, *chainprev, *tmp;
4967c478bd9Sstevel@tonic-gate 	ber_int_t	id;
4977c478bd9Sstevel@tonic-gate 	ber_tag_t	tag;
4987c478bd9Sstevel@tonic-gate 	ber_len_t	len;
4997c478bd9Sstevel@tonic-gate 	int		terrno, lderr, foundit = 0;
5007c478bd9Sstevel@tonic-gate 	LDAPRequest	*lr;
5017c478bd9Sstevel@tonic-gate 	int		rc, has_parent, message_can_be_returned;
5027c478bd9Sstevel@tonic-gate 	int		manufactured_result = 0;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	message_can_be_returned = 1;	/* the usual case... */
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	/*
5097c478bd9Sstevel@tonic-gate 	 * if we are not already in the midst of reading a message, allocate
5107c478bd9Sstevel@tonic-gate 	 * a ber that is associated with this connection
5117c478bd9Sstevel@tonic-gate 	 */
5127c478bd9Sstevel@tonic-gate 	if ( lc->lconn_ber == NULLBER && nsldapi_alloc_ber_with_options( ld,
5137c478bd9Sstevel@tonic-gate 	    &lc->lconn_ber ) != LDAP_SUCCESS ) {
5147c478bd9Sstevel@tonic-gate 		return( -1 );
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	/*
5187c478bd9Sstevel@tonic-gate 	 * ber_get_next() doesn't set errno on EOF, so we pre-set it to
5197c478bd9Sstevel@tonic-gate 	 * zero to avoid getting tricked by leftover "EAGAIN" errors
5207c478bd9Sstevel@tonic-gate 	 */
5217c478bd9Sstevel@tonic-gate 	LDAP_SET_ERRNO( ld, 0 );
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	/* get the next message */
5247c478bd9Sstevel@tonic-gate 	if ( (tag = ber_get_next( sb, &len, lc->lconn_ber ))
5257c478bd9Sstevel@tonic-gate 	    != LDAP_TAG_MESSAGE ) {
5267c478bd9Sstevel@tonic-gate 		terrno = LDAP_GET_ERRNO( ld );
5277c478bd9Sstevel@tonic-gate 		if ( terrno == EWOULDBLOCK || terrno == EAGAIN ) {
5287c478bd9Sstevel@tonic-gate 		    return( -2 );	/* try again */
5297c478bd9Sstevel@tonic-gate 		}
5307c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
5317c478bd9Sstevel@tonic-gate                     LDAP_LOCAL_ERROR), NULL, NULL );
5327c478bd9Sstevel@tonic-gate 		if ( tag == LBER_DEFAULT ) {
5337c478bd9Sstevel@tonic-gate 			nsldapi_connection_lost_nolock( ld, sb );
5347c478bd9Sstevel@tonic-gate 		}
5357c478bd9Sstevel@tonic-gate 		return( -1 );
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	/*
5397c478bd9Sstevel@tonic-gate 	 * Since we have received a complete message now, we pull this ber
5407c478bd9Sstevel@tonic-gate 	 * out of the connection structure and never read into it again.
5417c478bd9Sstevel@tonic-gate 	 */
5427c478bd9Sstevel@tonic-gate 	ber = lc->lconn_ber;
5437c478bd9Sstevel@tonic-gate 	lc->lconn_ber = NULLBER;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/* message id */
5467c478bd9Sstevel@tonic-gate 	if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
5477c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
5487c478bd9Sstevel@tonic-gate 		return( -1 );
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	/* if it's been abandoned, toss it */
5527c478bd9Sstevel@tonic-gate 	if ( ldap_abandoned( ld, (int)id ) ) {
5537c478bd9Sstevel@tonic-gate 		ber_free( ber, 1 );
5547c478bd9Sstevel@tonic-gate 		return( -2 );	/* continue looking */
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	if ( id == LDAP_RES_UNSOLICITED ) {
5587c478bd9Sstevel@tonic-gate 		lr = NULL;
5597c478bd9Sstevel@tonic-gate 	} else if (( lr = nsldapi_find_request_by_msgid( ld, id )) == NULL ) {
5607c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_ANY,
5617c478bd9Sstevel@tonic-gate 		    "no request for response with msgid %ld (tossing)\n",
5627c478bd9Sstevel@tonic-gate 		    id, 0, 0 );
5637c478bd9Sstevel@tonic-gate 		ber_free( ber, 1 );
5647c478bd9Sstevel@tonic-gate 		return( -2 );	/* continue looking */
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	/* the message type */
5687c478bd9Sstevel@tonic-gate 	if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
5697c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
5707c478bd9Sstevel@tonic-gate 		return( -1 );
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n",
5737c478bd9Sstevel@tonic-gate 	    ( tag == LDAP_RES_SEARCH_ENTRY ) ? "ENTRY" :
5747c478bd9Sstevel@tonic-gate 	    ( tag == LDAP_RES_SEARCH_REFERENCE ) ? "REFERENCE" : "RESULT", id,
5757c478bd9Sstevel@tonic-gate 	    ( lr == NULL ) ? id : lr->lr_origid );
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	if ( lr != NULL ) {
5787c478bd9Sstevel@tonic-gate 		id = lr->lr_origid;
5797c478bd9Sstevel@tonic-gate 		lr->lr_res_msgtype = tag;
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 	rc = -2;	/* default is to keep looking (no response found) */
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	if ( id != LDAP_RES_UNSOLICITED && ( tag == LDAP_RES_SEARCH_REFERENCE ||
5847c478bd9Sstevel@tonic-gate 	    tag != LDAP_RES_SEARCH_ENTRY )) {
5857c478bd9Sstevel@tonic-gate 		int		refchasing, reftotal, simple_request = 0;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 		check_for_refs( ld, lr, ber, lc->lconn_version, &reftotal,
5887c478bd9Sstevel@tonic-gate 		    &refchasing );
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 		if ( refchasing > 0 || lr->lr_outrefcnt > 0 ) {
5917c478bd9Sstevel@tonic-gate 			/*
5927c478bd9Sstevel@tonic-gate 			 * we're chasing one or more new refs...
5937c478bd9Sstevel@tonic-gate 			 */
5947c478bd9Sstevel@tonic-gate 			ber_free( ber, 1 );
5957c478bd9Sstevel@tonic-gate 			ber = NULLBER;
5967c478bd9Sstevel@tonic-gate 			lr->lr_status = LDAP_REQST_CHASINGREFS;
5977c478bd9Sstevel@tonic-gate 			message_can_be_returned = 0;
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 		} else if ( tag != LDAP_RES_SEARCH_REFERENCE ) {
6007c478bd9Sstevel@tonic-gate 			/*
6017c478bd9Sstevel@tonic-gate 			 * this request is complete...
6027c478bd9Sstevel@tonic-gate 			 */
6037c478bd9Sstevel@tonic-gate 			has_parent = ( lr->lr_parent != NULL );
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 			if ( lr->lr_outrefcnt <= 0 && !has_parent ) {
6067c478bd9Sstevel@tonic-gate 				/* request without any refs */
6077c478bd9Sstevel@tonic-gate 				simple_request = ( reftotal == 0 );
6087c478bd9Sstevel@tonic-gate 			}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 			/*
6117c478bd9Sstevel@tonic-gate 			 * If this is not a child request and it is a bind
6127c478bd9Sstevel@tonic-gate 			 * request, reset the connection's bind DN and
6137c478bd9Sstevel@tonic-gate 			 * status based on the result of the operation.
6147c478bd9Sstevel@tonic-gate 			 */
6157c478bd9Sstevel@tonic-gate 			if ( !has_parent &&
6167c478bd9Sstevel@tonic-gate 			    LDAP_RES_BIND == lr->lr_res_msgtype &&
6177c478bd9Sstevel@tonic-gate 			    lr->lr_conn != NULL ) {
6187c478bd9Sstevel@tonic-gate 				if ( lr->lr_conn->lconn_binddn != NULL ) {
6197c478bd9Sstevel@tonic-gate 					NSLDAPI_FREE(
6207c478bd9Sstevel@tonic-gate 					    lr->lr_conn->lconn_binddn );
6217c478bd9Sstevel@tonic-gate 				}
6227c478bd9Sstevel@tonic-gate 				if ( LDAP_SUCCESS == nsldapi_parse_result( ld,
6237c478bd9Sstevel@tonic-gate 				    lr->lr_res_msgtype, ber, &lderr, NULL,
6247c478bd9Sstevel@tonic-gate 				    NULL, NULL, NULL )
6257c478bd9Sstevel@tonic-gate 				    && LDAP_SUCCESS == lderr ) {
6267c478bd9Sstevel@tonic-gate 					lr->lr_conn->lconn_bound = 1;
6277c478bd9Sstevel@tonic-gate 					lr->lr_conn->lconn_binddn =
6287c478bd9Sstevel@tonic-gate 					    lr->lr_binddn;
6297c478bd9Sstevel@tonic-gate 					lr->lr_binddn = NULL;
6307c478bd9Sstevel@tonic-gate 				} else {
6317c478bd9Sstevel@tonic-gate 					lr->lr_conn->lconn_bound = 0;
6327c478bd9Sstevel@tonic-gate 					lr->lr_conn->lconn_binddn = NULL;
6337c478bd9Sstevel@tonic-gate 				}
6347c478bd9Sstevel@tonic-gate 			}
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 			/*
6377c478bd9Sstevel@tonic-gate 			 * if this response is to a child request, we toss
6387c478bd9Sstevel@tonic-gate 			 * the message contents and just merge error info.
6397c478bd9Sstevel@tonic-gate 			 * into the parent.
6407c478bd9Sstevel@tonic-gate 			 */
6417c478bd9Sstevel@tonic-gate 			if ( has_parent ) {
6427c478bd9Sstevel@tonic-gate 				ber_free( ber, 1 );
6437c478bd9Sstevel@tonic-gate 				ber = NULLBER;
6447c478bd9Sstevel@tonic-gate 			}
6457c478bd9Sstevel@tonic-gate 			while ( lr->lr_parent != NULL ) {
6467c478bd9Sstevel@tonic-gate 				merge_error_info( ld, lr->lr_parent, lr );
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 				lr = lr->lr_parent;
6497c478bd9Sstevel@tonic-gate 				if ( --lr->lr_outrefcnt > 0 ) {
6507c478bd9Sstevel@tonic-gate 					break;	/* not completely done yet */
6517c478bd9Sstevel@tonic-gate 				}
6527c478bd9Sstevel@tonic-gate 			}
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 			/*
6557c478bd9Sstevel@tonic-gate 			 * we recognize a request as complete when:
6567c478bd9Sstevel@tonic-gate 			 *  1) it has no outstanding referrals
6577c478bd9Sstevel@tonic-gate 			 *  2) it is not a child request
6587c478bd9Sstevel@tonic-gate 			 *  3) we have received a result for the request (i.e.,
6597c478bd9Sstevel@tonic-gate 			 *     something other than an entry or a reference).
6607c478bd9Sstevel@tonic-gate 			 */
6617c478bd9Sstevel@tonic-gate 			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL &&
6627c478bd9Sstevel@tonic-gate 			    lr->lr_res_msgtype != LDAP_RES_SEARCH_ENTRY &&
6637c478bd9Sstevel@tonic-gate 			    lr->lr_res_msgtype != LDAP_RES_SEARCH_REFERENCE ) {
6647c478bd9Sstevel@tonic-gate 				id = lr->lr_msgid;
6657c478bd9Sstevel@tonic-gate 				tag = lr->lr_res_msgtype;
6667c478bd9Sstevel@tonic-gate 				LDAPDebug( LDAP_DEBUG_TRACE,
6677c478bd9Sstevel@tonic-gate 				    "request %ld done\n", id, 0, 0 );
6687c478bd9Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
6697c478bd9Sstevel@tonic-gate "res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
6707c478bd9Sstevel@tonic-gate lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
6717c478bd9Sstevel@tonic-gate lr->lr_res_matched ? lr->lr_res_matched : "" );
6727c478bd9Sstevel@tonic-gate 				if ( !simple_request ) {
6737c478bd9Sstevel@tonic-gate 					if ( ber != NULLBER ) {
6747c478bd9Sstevel@tonic-gate 						ber_free( ber, 1 );
6757c478bd9Sstevel@tonic-gate 						ber = NULLBER;
6767c478bd9Sstevel@tonic-gate 					}
6777c478bd9Sstevel@tonic-gate 					if ( build_result_ber( ld, &ber, lr )
6787c478bd9Sstevel@tonic-gate 					    != LDAP_SUCCESS ) {
6797c478bd9Sstevel@tonic-gate 						rc = -1; /* fatal error */
6807c478bd9Sstevel@tonic-gate 					} else {
6817c478bd9Sstevel@tonic-gate 						manufactured_result = 1;
6827c478bd9Sstevel@tonic-gate 					}
6837c478bd9Sstevel@tonic-gate 				}
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 				nsldapi_free_request( ld, lr, 1 );
6867c478bd9Sstevel@tonic-gate 			} else {
6877c478bd9Sstevel@tonic-gate 				message_can_be_returned = 0;
6887c478bd9Sstevel@tonic-gate 			}
6897c478bd9Sstevel@tonic-gate 		}
6907c478bd9Sstevel@tonic-gate 	}
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	if ( ber == NULLBER ) {
6937c478bd9Sstevel@tonic-gate 		return( rc );
6947c478bd9Sstevel@tonic-gate 	}
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	/* make a new ldap message */
6977c478bd9Sstevel@tonic-gate 	if ( (new = (LDAPMessage*)NSLDAPI_CALLOC( 1, sizeof(struct ldapmsg) ))
6987c478bd9Sstevel@tonic-gate 	    == NULL ) {
6997c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
7007c478bd9Sstevel@tonic-gate 		return( -1 );
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 	new->lm_msgid = (int)id;
7037c478bd9Sstevel@tonic-gate 	new->lm_msgtype = tag;
7047c478bd9Sstevel@tonic-gate 	new->lm_ber = ber;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	/*
7077c478bd9Sstevel@tonic-gate 	 * if this is a search entry or if this request is complete (i.e.,
7087c478bd9Sstevel@tonic-gate 	 * there are no outstanding referrals) then add to cache and check
7097c478bd9Sstevel@tonic-gate 	 * to see if we should return this to the caller right away or not.
7107c478bd9Sstevel@tonic-gate 	 */
7117c478bd9Sstevel@tonic-gate 	if ( message_can_be_returned ) {
7127c478bd9Sstevel@tonic-gate 		if ( ld->ld_cache_on ) {
7137c478bd9Sstevel@tonic-gate 			nsldapi_add_result_to_cache( ld, new );
7147c478bd9Sstevel@tonic-gate 		}
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		if ( msgid == LDAP_RES_ANY || id == msgid ) {
7177c478bd9Sstevel@tonic-gate 			if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
7187c478bd9Sstevel@tonic-gate 				/*
7197c478bd9Sstevel@tonic-gate 				 * return the first response we have for this
7207c478bd9Sstevel@tonic-gate 				 * search request later (possibly an entire
7217c478bd9Sstevel@tonic-gate 				 * chain of messages).
7227c478bd9Sstevel@tonic-gate 				 */
7237c478bd9Sstevel@tonic-gate 				foundit = 1;
7247c478bd9Sstevel@tonic-gate 			} else if ( all == 0
7257c478bd9Sstevel@tonic-gate 			    || (new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
7267c478bd9Sstevel@tonic-gate 			    && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {
7277c478bd9Sstevel@tonic-gate 				*result = new;
7287c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL,
7297c478bd9Sstevel@tonic-gate 				    NULL );
7307c478bd9Sstevel@tonic-gate 				return( tag );
7317c478bd9Sstevel@tonic-gate 			}
7327c478bd9Sstevel@tonic-gate 		}
7337c478bd9Sstevel@tonic-gate 	}
7347c478bd9Sstevel@tonic-gate 
735*1da57d55SToomas Soome 	/*
7367c478bd9Sstevel@tonic-gate 	 * if not, we must add it to the list of responses.  if
7377c478bd9Sstevel@tonic-gate 	 * the msgid is already there, it must be part of an existing
7387c478bd9Sstevel@tonic-gate 	 * search response.
7397c478bd9Sstevel@tonic-gate 	 */
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	prev = NULL;
7427c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
7437c478bd9Sstevel@tonic-gate 	for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
7447c478bd9Sstevel@tonic-gate 		if ( l->lm_msgid == new->lm_msgid )
7457c478bd9Sstevel@tonic-gate 			break;
7467c478bd9Sstevel@tonic-gate 		prev = l;
7477c478bd9Sstevel@tonic-gate 	}
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	/* not part of an existing search response */
7507c478bd9Sstevel@tonic-gate 	if ( l == NULL ) {
7517c478bd9Sstevel@tonic-gate 		if ( foundit ) {
7527c478bd9Sstevel@tonic-gate 			LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
7537c478bd9Sstevel@tonic-gate 			*result = new;
7547c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
7557c478bd9Sstevel@tonic-gate 			return( tag );
7567c478bd9Sstevel@tonic-gate 		}
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 		new->lm_next = ld->ld_responses;
7597c478bd9Sstevel@tonic-gate 		ld->ld_responses = new;
7607c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_TRACE,
7617c478bd9Sstevel@tonic-gate 		    "adding new response id %d type %d (looking for id %d)\n",
7627c478bd9Sstevel@tonic-gate 		    new->lm_msgid, new->lm_msgtype, msgid );
7637c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
7647c478bd9Sstevel@tonic-gate 		if( message_can_be_returned )
7657c478bd9Sstevel@tonic-gate 			POST( ld, new->lm_msgid, new );
7667c478bd9Sstevel@tonic-gate 		return( -2 );	/* continue looking */
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
7707c478bd9Sstevel@tonic-gate 	    "adding response id %d type %d (looking for id %d)\n",
7717c478bd9Sstevel@tonic-gate 	    new->lm_msgid, new->lm_msgtype, msgid );
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	/*
7747c478bd9Sstevel@tonic-gate 	 * part of a search response - add to end of list of entries
7757c478bd9Sstevel@tonic-gate 	 *
7767c478bd9Sstevel@tonic-gate 	 * the first step is to find the end of the list of entries and
7777c478bd9Sstevel@tonic-gate 	 * references.  after the following loop is executed, tmp points to
7787c478bd9Sstevel@tonic-gate 	 * the last entry or reference in the chain.  If there are none,
7797c478bd9Sstevel@tonic-gate 	 * tmp points to the search result.
7807c478bd9Sstevel@tonic-gate 	 */
7817c478bd9Sstevel@tonic-gate 	chainprev = NULL;
7827c478bd9Sstevel@tonic-gate 	for ( tmp = l; tmp->lm_chain != NULL &&
7837c478bd9Sstevel@tonic-gate 	    ( tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY
7847c478bd9Sstevel@tonic-gate 	    || tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE );
7857c478bd9Sstevel@tonic-gate 	    tmp = tmp->lm_chain ) {
7867c478bd9Sstevel@tonic-gate 		chainprev = tmp;
7877c478bd9Sstevel@tonic-gate 	}
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	/*
7907c478bd9Sstevel@tonic-gate 	 * If this is a manufactured result message and a result is already
7917c478bd9Sstevel@tonic-gate 	 * queued we throw away the one that is queued and replace it with
7927c478bd9Sstevel@tonic-gate 	 * our new result.  This is necessary so we don't end up returning
7937c478bd9Sstevel@tonic-gate 	 * more than one result.
7947c478bd9Sstevel@tonic-gate 	 */
7957c478bd9Sstevel@tonic-gate 	if ( manufactured_result &&
7967c478bd9Sstevel@tonic-gate 	    tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
7977c478bd9Sstevel@tonic-gate 		/*
7987c478bd9Sstevel@tonic-gate 		 * the result is the only thing in the chain... replace it.
7997c478bd9Sstevel@tonic-gate 		 */
8007c478bd9Sstevel@tonic-gate 		new->lm_chain = tmp->lm_chain;
8017c478bd9Sstevel@tonic-gate 		new->lm_next = tmp->lm_next;
8027c478bd9Sstevel@tonic-gate 		if ( chainprev == NULL ) {
8037c478bd9Sstevel@tonic-gate 			if ( prev == NULL ) {
8047c478bd9Sstevel@tonic-gate 				ld->ld_responses = new;
8057c478bd9Sstevel@tonic-gate 			} else {
8067c478bd9Sstevel@tonic-gate 				prev->lm_next = new;
8077c478bd9Sstevel@tonic-gate 			}
8087c478bd9Sstevel@tonic-gate 		} else {
8097c478bd9Sstevel@tonic-gate 		    chainprev->lm_chain = new;
8107c478bd9Sstevel@tonic-gate 		}
8117c478bd9Sstevel@tonic-gate 		if ( l == tmp ) {
8127c478bd9Sstevel@tonic-gate 			l = new;
8137c478bd9Sstevel@tonic-gate 		}
8147c478bd9Sstevel@tonic-gate 		ldap_msgfree( tmp );
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	} else if ( manufactured_result && tmp->lm_chain != NULL
8177c478bd9Sstevel@tonic-gate 	    && tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
8187c478bd9Sstevel@tonic-gate 		/*
8197c478bd9Sstevel@tonic-gate 		 * entries or references are also present, so the result
8207c478bd9Sstevel@tonic-gate 		 * is the next entry after tmp.  replace it.
8217c478bd9Sstevel@tonic-gate 		 */
8227c478bd9Sstevel@tonic-gate 		new->lm_chain = tmp->lm_chain->lm_chain;
8237c478bd9Sstevel@tonic-gate 		new->lm_next = tmp->lm_chain->lm_next;
8247c478bd9Sstevel@tonic-gate 		ldap_msgfree( tmp->lm_chain );
8257c478bd9Sstevel@tonic-gate 		tmp->lm_chain = new;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	} else if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
8287c478bd9Sstevel@tonic-gate 		/*
8297c478bd9Sstevel@tonic-gate 		 * the result is the only thing in the chain... add before it.
8307c478bd9Sstevel@tonic-gate 		 */
8317c478bd9Sstevel@tonic-gate 		new->lm_chain = tmp;
8327c478bd9Sstevel@tonic-gate 		if ( chainprev == NULL ) {
8337c478bd9Sstevel@tonic-gate 			if ( prev == NULL ) {
8347c478bd9Sstevel@tonic-gate 				ld->ld_responses = new;
8357c478bd9Sstevel@tonic-gate 			} else {
8367c478bd9Sstevel@tonic-gate 				prev->lm_next = new;
8377c478bd9Sstevel@tonic-gate 			}
8387c478bd9Sstevel@tonic-gate 		} else {
8397c478bd9Sstevel@tonic-gate 		    chainprev->lm_chain = new;
8407c478bd9Sstevel@tonic-gate 		}
8417c478bd9Sstevel@tonic-gate 		if ( l == tmp ) {
8427c478bd9Sstevel@tonic-gate 			l = new;
8437c478bd9Sstevel@tonic-gate 		}
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	} else {
8467c478bd9Sstevel@tonic-gate 		/*
8477c478bd9Sstevel@tonic-gate 		 * entries and/or references are present... add to the end
8487c478bd9Sstevel@tonic-gate 		 * of the entry/reference part of the chain.
8497c478bd9Sstevel@tonic-gate 		 */
8507c478bd9Sstevel@tonic-gate 		new->lm_chain = tmp->lm_chain;
8517c478bd9Sstevel@tonic-gate 		tmp->lm_chain = new;
8527c478bd9Sstevel@tonic-gate 	}
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	/*
8557c478bd9Sstevel@tonic-gate 	 * return the first response or the whole chain if that's what
8567c478bd9Sstevel@tonic-gate 	 * we were looking for....
8577c478bd9Sstevel@tonic-gate 	 */
8587c478bd9Sstevel@tonic-gate 	if ( foundit ) {
8597c478bd9Sstevel@tonic-gate 		if ( all == 0 && l->lm_chain != NULL ) {
8607c478bd9Sstevel@tonic-gate 			/*
8617c478bd9Sstevel@tonic-gate 			 * only return the first response in the chain
8627c478bd9Sstevel@tonic-gate 			 */
8637c478bd9Sstevel@tonic-gate 			if ( prev == NULL ) {
8647c478bd9Sstevel@tonic-gate 				ld->ld_responses = l->lm_chain;
8657c478bd9Sstevel@tonic-gate 			} else {
8667c478bd9Sstevel@tonic-gate 				prev->lm_next = l->lm_chain;
8677c478bd9Sstevel@tonic-gate 			}
8687c478bd9Sstevel@tonic-gate 			l->lm_chain = NULL;
8697c478bd9Sstevel@tonic-gate 			tag = l->lm_msgtype;
8707c478bd9Sstevel@tonic-gate 		} else {
8717c478bd9Sstevel@tonic-gate 			/*
8727c478bd9Sstevel@tonic-gate 			 * return all of the responses (may be a chain)
8737c478bd9Sstevel@tonic-gate 			 */
8747c478bd9Sstevel@tonic-gate 			if ( prev == NULL ) {
8757c478bd9Sstevel@tonic-gate 				ld->ld_responses = l->lm_next;
8767c478bd9Sstevel@tonic-gate 			} else {
8777c478bd9Sstevel@tonic-gate 				prev->lm_next = l->lm_next;
8787c478bd9Sstevel@tonic-gate 			}
8797c478bd9Sstevel@tonic-gate 		}
8807c478bd9Sstevel@tonic-gate 		*result = l;
8817c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
8827c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
8837c478bd9Sstevel@tonic-gate 		return( tag );
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
8867c478bd9Sstevel@tonic-gate 	return( -2 );	/* continue looking */
8877c478bd9Sstevel@tonic-gate }
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate /*
8917c478bd9Sstevel@tonic-gate  * check for LDAPv2+ (UMich extension) or LDAPv3 referrals or references
8927c478bd9Sstevel@tonic-gate  * errors are merged in "lr".
8937c478bd9Sstevel@tonic-gate  */
8947c478bd9Sstevel@tonic-gate static void
8957c478bd9Sstevel@tonic-gate check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
8967c478bd9Sstevel@tonic-gate     int ldapversion, int *totalcountp, int *chasingcountp )
8977c478bd9Sstevel@tonic-gate {
8987c478bd9Sstevel@tonic-gate 	int		err, origerr;
8997c478bd9Sstevel@tonic-gate 	char		*errstr, *matcheddn, **v3refs;
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "check_for_refs\n", 0, 0, 0 );
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	*chasingcountp = *totalcountp = 0;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	if ( ldapversion < LDAP_VERSION2 || ( lr->lr_parent == NULL
9067c478bd9Sstevel@tonic-gate 	    && ( ld->ld_options & LDAP_BITOPT_REFERRALS ) == 0 )) {
9077c478bd9Sstevel@tonic-gate 		/* referrals are not supported or are disabled */
9087c478bd9Sstevel@tonic-gate 		return;
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	if ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
9127c478bd9Sstevel@tonic-gate 		err = nsldapi_parse_reference( ld, ber, &v3refs, NULL );
9137c478bd9Sstevel@tonic-gate 		origerr = LDAP_REFERRAL;	/* a small lie... */
9147c478bd9Sstevel@tonic-gate 		matcheddn = errstr = NULL;
9157c478bd9Sstevel@tonic-gate 	} else {
9167c478bd9Sstevel@tonic-gate 		err = nsldapi_parse_result( ld, lr->lr_res_msgtype, ber,
9177c478bd9Sstevel@tonic-gate 		    &origerr, &matcheddn, &errstr, &v3refs, NULL );
9187c478bd9Sstevel@tonic-gate 	}
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	if ( err != LDAP_SUCCESS ) {
9217c478bd9Sstevel@tonic-gate 		/* parse failed */
9227c478bd9Sstevel@tonic-gate 		return;
9237c478bd9Sstevel@tonic-gate 	}
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	if ( origerr == LDAP_REFERRAL ) {	/* ldapv3 */
9267c478bd9Sstevel@tonic-gate 		if ( v3refs != NULL ) {
9277c478bd9Sstevel@tonic-gate 			err = nsldapi_chase_v3_refs( ld, lr, v3refs,
9287c478bd9Sstevel@tonic-gate 			    ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ),
9297c478bd9Sstevel@tonic-gate 			    totalcountp, chasingcountp );
9307c478bd9Sstevel@tonic-gate 			ldap_value_free( v3refs );
9317c478bd9Sstevel@tonic-gate 		}
9327c478bd9Sstevel@tonic-gate 	} else if ( ldapversion == LDAP_VERSION2
9337c478bd9Sstevel@tonic-gate 	    && origerr != LDAP_SUCCESS ) {
9347c478bd9Sstevel@tonic-gate 		/* referrals may be present in the error string */
9357c478bd9Sstevel@tonic-gate 		err = nsldapi_chase_v2_referrals( ld, lr, &errstr,
9367c478bd9Sstevel@tonic-gate 		    totalcountp, chasingcountp );
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	/* set LDAP errno, message, and matched string appropriately */
9407c478bd9Sstevel@tonic-gate 	if ( lr->lr_res_error != NULL ) {
9417c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( lr->lr_res_error );
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate 	lr->lr_res_error = errstr;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	if ( lr->lr_res_matched != NULL ) {
9467c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( lr->lr_res_matched );
9477c478bd9Sstevel@tonic-gate 	}
9487c478bd9Sstevel@tonic-gate 	lr->lr_res_matched = matcheddn;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	if ( err == LDAP_SUCCESS && ( *chasingcountp == *totalcountp )) {
9517c478bd9Sstevel@tonic-gate 		if ( *totalcountp > 0 && ( origerr == LDAP_PARTIAL_RESULTS
9527c478bd9Sstevel@tonic-gate 		    || origerr == LDAP_REFERRAL )) {
9537c478bd9Sstevel@tonic-gate 			/* substitute success for referral error codes */
9547c478bd9Sstevel@tonic-gate 			lr->lr_res_errno = LDAP_SUCCESS;
9557c478bd9Sstevel@tonic-gate 		} else {
9567c478bd9Sstevel@tonic-gate 			/* preserve existing non-referral error code */
9577c478bd9Sstevel@tonic-gate 			lr->lr_res_errno = origerr;
9587c478bd9Sstevel@tonic-gate 		}
9597c478bd9Sstevel@tonic-gate 	} else if ( err != LDAP_SUCCESS ) {
9607c478bd9Sstevel@tonic-gate 		/* error occurred while trying to chase referrals */
9617c478bd9Sstevel@tonic-gate 		lr->lr_res_errno = err;
9627c478bd9Sstevel@tonic-gate 	} else {
9637c478bd9Sstevel@tonic-gate 		/* some referrals were not recognized */
9647c478bd9Sstevel@tonic-gate 		lr->lr_res_errno = ( ldapversion == LDAP_VERSION2 )
9657c478bd9Sstevel@tonic-gate 		    ? LDAP_PARTIAL_RESULTS : LDAP_REFERRAL;
9667c478bd9Sstevel@tonic-gate 	}
967*1da57d55SToomas Soome 
9687c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
9697c478bd9Sstevel@tonic-gate 	    "check_for_refs: new result: msgid %d, res_errno %d, ",
9707c478bd9Sstevel@tonic-gate 	    lr->lr_msgid, lr->lr_res_errno, 0 );
9717c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, " res_error <%s>, res_matched <%s>\n",
9727c478bd9Sstevel@tonic-gate 	    lr->lr_res_error ? lr->lr_res_error : "",
9737c478bd9Sstevel@tonic-gate 	    lr->lr_res_matched ? lr->lr_res_matched : "", 0 );
9747c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
9757c478bd9Sstevel@tonic-gate 	    "check_for_refs: %d new refs(s); chasing %d of them\n",
9767c478bd9Sstevel@tonic-gate 	    *totalcountp, *chasingcountp, 0 );
9777c478bd9Sstevel@tonic-gate }
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate /* returns an LDAP error code and also sets it in LDAP * */
9817c478bd9Sstevel@tonic-gate static int
9827c478bd9Sstevel@tonic-gate build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr )
9837c478bd9Sstevel@tonic-gate {
9847c478bd9Sstevel@tonic-gate 	ber_len_t	len;
9857c478bd9Sstevel@tonic-gate 	ber_int_t	along;
9867c478bd9Sstevel@tonic-gate 	BerElement	*ber;
9877c478bd9Sstevel@tonic-gate 	int		err;
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
9907c478bd9Sstevel@tonic-gate 	    != LDAP_SUCCESS ) {
9917c478bd9Sstevel@tonic-gate 		return( err );
9927c478bd9Sstevel@tonic-gate 	}
9937c478bd9Sstevel@tonic-gate 	*berp = ber;
9947c478bd9Sstevel@tonic-gate 	if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
9957c478bd9Sstevel@tonic-gate 	    (long)lr->lr_res_msgtype, lr->lr_res_errno,
9967c478bd9Sstevel@tonic-gate 	    lr->lr_res_matched ? lr->lr_res_matched : "",
9977c478bd9Sstevel@tonic-gate 	    lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {
9987c478bd9Sstevel@tonic-gate 		return( LDAP_ENCODING_ERROR );
9997c478bd9Sstevel@tonic-gate 	}
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	ber_reset( ber, 1 );
10027c478bd9Sstevel@tonic-gate 	if ( ber_skip_tag( ber, &len ) == LBER_ERROR ||
10037c478bd9Sstevel@tonic-gate 	    ber_get_int( ber, &along ) == LBER_ERROR ||
10047c478bd9Sstevel@tonic-gate 	    ber_peek_tag( ber, &len ) == LBER_ERROR ) {
10057c478bd9Sstevel@tonic-gate 		return( LDAP_DECODING_ERROR );
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate static void
10137c478bd9Sstevel@tonic-gate merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
10147c478bd9Sstevel@tonic-gate {
10157c478bd9Sstevel@tonic-gate /*
10167c478bd9Sstevel@tonic-gate  * Merge error information in "lr" with "parentr" error code and string.
10177c478bd9Sstevel@tonic-gate  */
10187c478bd9Sstevel@tonic-gate 	if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
10197c478bd9Sstevel@tonic-gate 		parentr->lr_res_errno = lr->lr_res_errno;
10207c478bd9Sstevel@tonic-gate 		if ( lr->lr_res_error != NULL ) {
10217c478bd9Sstevel@tonic-gate 			(void)nsldapi_append_referral( ld, &parentr->lr_res_error,
10227c478bd9Sstevel@tonic-gate 			    lr->lr_res_error );
10237c478bd9Sstevel@tonic-gate 		}
10247c478bd9Sstevel@tonic-gate 	} else if ( lr->lr_res_errno != LDAP_SUCCESS &&
10257c478bd9Sstevel@tonic-gate 	    parentr->lr_res_errno == LDAP_SUCCESS ) {
10267c478bd9Sstevel@tonic-gate 		parentr->lr_res_errno = lr->lr_res_errno;
10277c478bd9Sstevel@tonic-gate 		if ( parentr->lr_res_error != NULL ) {
10287c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE( parentr->lr_res_error );
10297c478bd9Sstevel@tonic-gate 		}
10307c478bd9Sstevel@tonic-gate 		parentr->lr_res_error = lr->lr_res_error;
10317c478bd9Sstevel@tonic-gate 		lr->lr_res_error = NULL;
10327c478bd9Sstevel@tonic-gate 		if ( NAME_ERROR( lr->lr_res_errno )) {
10337c478bd9Sstevel@tonic-gate 			if ( parentr->lr_res_matched != NULL ) {
10347c478bd9Sstevel@tonic-gate 				NSLDAPI_FREE( parentr->lr_res_matched );
10357c478bd9Sstevel@tonic-gate 			}
10367c478bd9Sstevel@tonic-gate 			parentr->lr_res_matched = lr->lr_res_matched;
10377c478bd9Sstevel@tonic-gate 			lr->lr_res_matched = NULL;
10387c478bd9Sstevel@tonic-gate 		}
10397c478bd9Sstevel@tonic-gate 	}
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
10427c478bd9Sstevel@tonic-gate 	    parentr->lr_msgid, 0, 0 );
10437c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "result lderrno %d, error <%s>, matched <%s>\n",
10447c478bd9Sstevel@tonic-gate 	    parentr->lr_res_errno, parentr->lr_res_error ?
10457c478bd9Sstevel@tonic-gate 	    parentr->lr_res_error : "", parentr->lr_res_matched ?
10467c478bd9Sstevel@tonic-gate 	    parentr->lr_res_matched : "" );
10477c478bd9Sstevel@tonic-gate }
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate #if defined( CLDAP )
10507c478bd9Sstevel@tonic-gate #if !defined( macintosh ) && !defined( DOS ) && !defined( _WINDOWS ) && !defined(XP_OS2)
10517c478bd9Sstevel@tonic-gate /* XXXmcs: was revised to support extended I/O callbacks but never compiled! */
10527c478bd9Sstevel@tonic-gate static int
10537c478bd9Sstevel@tonic-gate cldap_select1( LDAP *ld, struct timeval *timeout )
10547c478bd9Sstevel@tonic-gate {
10557c478bd9Sstevel@tonic-gate 	int		rc;
10567c478bd9Sstevel@tonic-gate 	static int	tblsize = 0;
10577c478bd9Sstevel@tonic-gate 	NSLDAPIIOStatus	*iosp = ld->ld_iostatus;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	if ( tblsize == 0 ) {
10607c478bd9Sstevel@tonic-gate #ifdef USE_SYSCONF
10617c478bd9Sstevel@tonic-gate 		tblsize = sysconf( _SC_OPEN_MAX );
10627c478bd9Sstevel@tonic-gate #else /* USE_SYSCONF */
10637c478bd9Sstevel@tonic-gate 		tblsize = getdtablesize();
10647c478bd9Sstevel@tonic-gate #endif /* USE_SYSCONF */
10657c478bd9Sstevel@tonic-gate 	}
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	if ( tblsize >= FD_SETSIZE ) {
10687c478bd9Sstevel@tonic-gate 		/*
10697c478bd9Sstevel@tonic-gate 		 * clamp value so we don't overrun the fd_set structure
10707c478bd9Sstevel@tonic-gate 		 */
10717c478bd9Sstevel@tonic-gate 		tblsize = FD_SETSIZE - 1;
10727c478bd9Sstevel@tonic-gate 	}
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	if ( NSLDAPI_IOSTATUS_TYPE_OSNATIVE == iosp->ios_type ) {
10757c478bd9Sstevel@tonic-gate 		fd_set		readfds;
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 		FD_ZERO( &readfds );
10787c478bd9Sstevel@tonic-gate 		FD_SET( ld->ld_sbp->sb_sd, &readfds );
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 		/* XXXmcs: UNIX platforms should use poll() */
10817c478bd9Sstevel@tonic-gate 		rc = select( tblsize, &readfds, 0, 0, timeout ) );
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	} else if ( NSLDAPI_IOSTATUS_TYPE_CALLBACK == iosp->ios_type ) {
10847c478bd9Sstevel@tonic-gate 		LDAP_X_PollFD	pollfds[ 1 ];
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 		pollfds[0].lpoll_fd = ld->ld_sbp->sb_sd;
10877c478bd9Sstevel@tonic-gate 		pollfds[0].lpoll_arg = ld->ld_sbp->sb_arg;
10887c478bd9Sstevel@tonic-gate 		pollfds[0].lpoll_events = LDAP_X_POLLIN;
10897c478bd9Sstevel@tonic-gate 		pollfds[0].lpoll_revents = 0;
10907c478bd9Sstevel@tonic-gate 		rc = ld->ld_extpoll_fn( pollfds, 1, nsldapi_tv2ms( timeout ),
10917c478bd9Sstevel@tonic-gate 		    ld->ld_ext_session_arg );
10927c478bd9Sstevel@tonic-gate 	} else {
10937c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_ANY,
10947c478bd9Sstevel@tonic-gate 		    "nsldapi_iostatus_poll: unknown I/O type %d\n",
10957c478bd9Sstevel@tonic-gate 		rc = 0; /* simulate a timeout (what else to do?) */
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	return( rc );
10997c478bd9Sstevel@tonic-gate }
11007c478bd9Sstevel@tonic-gate #endif /* !macintosh */
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate #ifdef macintosh
11047c478bd9Sstevel@tonic-gate static int
11057c478bd9Sstevel@tonic-gate cldap_select1( LDAP *ld, struct timeval *timeout )
11067c478bd9Sstevel@tonic-gate {
11077c478bd9Sstevel@tonic-gate 	/* XXXmcs: needs to be revised to support I/O callbacks */
11087c478bd9Sstevel@tonic-gate 	return( tcpselect( ld->ld_sbp->sb_sd, timeout ));
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate #endif /* macintosh */
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate #if (defined( DOS ) && defined( WINSOCK )) || defined( _WINDOWS ) || defined(XP_OS2)
11147c478bd9Sstevel@tonic-gate /* XXXmcs: needs to be revised to support extended I/O callbacks */
11157c478bd9Sstevel@tonic-gate static int
11167c478bd9Sstevel@tonic-gate cldap_select1( LDAP *ld, struct timeval *timeout )
11177c478bd9Sstevel@tonic-gate {
11187c478bd9Sstevel@tonic-gate     fd_set          readfds;
11197c478bd9Sstevel@tonic-gate     int             rc;
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate     FD_ZERO( &readfds );
11227c478bd9Sstevel@tonic-gate     FD_SET( ld->ld_sbp->sb_sd, &readfds );
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate     if ( NSLDAPI_IO_TYPE_STANDARD == ld->ldiou_type &&
11257c478bd9Sstevel@tonic-gate 	NULL != ld->ld_select_fn ) {
11267c478bd9Sstevel@tonic-gate 	    rc = ld->ld_select_fn( 1, &readfds, 0, 0, timeout );
11277c478bd9Sstevel@tonic-gate     } else if ( NSLDAPI_IO_TYPE_EXTENDED == ld->ldiou_type &&
11287c478bd9Sstevel@tonic-gate 	NULL != ld->ld_extselect_fn ) {
11297c478bd9Sstevel@tonic-gate 	    rc = ld->ld_extselect_fn( ld->ld_ext_session_arg, 1, &readfds, 0,
11307c478bd9Sstevel@tonic-gate 		0, timeout ) );
11317c478bd9Sstevel@tonic-gate     } else {
11327c478bd9Sstevel@tonic-gate 	    /* XXXmcs: UNIX platforms should use poll() */
11337c478bd9Sstevel@tonic-gate 	    rc = select( 1, &readfds, 0, 0, timeout ) );
11347c478bd9Sstevel@tonic-gate     }
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate     return( rc == SOCKET_ERROR ? -1 : rc );
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate #endif /* WINSOCK || _WINDOWS */
11397c478bd9Sstevel@tonic-gate #endif /* CLDAP */
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate int
11427c478bd9Sstevel@tonic-gate LDAP_CALL
11437c478bd9Sstevel@tonic-gate ldap_msgfree( LDAPMessage *lm )
11447c478bd9Sstevel@tonic-gate {
11457c478bd9Sstevel@tonic-gate 	LDAPMessage	*next;
11467c478bd9Sstevel@tonic-gate 	int		type = 0;
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	for ( ; lm != NULL; lm = next ) {
11517c478bd9Sstevel@tonic-gate 		next = lm->lm_chain;
11527c478bd9Sstevel@tonic-gate 		type = lm->lm_msgtype;
11537c478bd9Sstevel@tonic-gate 		ber_free( lm->lm_ber, 1 );
11547c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( (char *) lm );
11557c478bd9Sstevel@tonic-gate 	}
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	return( type );
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate /*
11617c478bd9Sstevel@tonic-gate  * ldap_msgdelete - delete a message.  It returns:
11627c478bd9Sstevel@tonic-gate  *	0	if the entire message was deleted
11637c478bd9Sstevel@tonic-gate  *	-1	if the message was not found, or only part of it was found
11647c478bd9Sstevel@tonic-gate  */
11657c478bd9Sstevel@tonic-gate int
11667c478bd9Sstevel@tonic-gate ldap_msgdelete( LDAP *ld, int msgid )
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate 	LDAPMessage	*lm, *prev;
11697c478bd9Sstevel@tonic-gate 	int		msgtype;
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
11747c478bd9Sstevel@tonic-gate 		return( -1 );	/* punt */
11757c478bd9Sstevel@tonic-gate 	}
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	prev = NULL;
11787c478bd9Sstevel@tonic-gate         LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
11797c478bd9Sstevel@tonic-gate 	for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
11807c478bd9Sstevel@tonic-gate 		if ( lm->lm_msgid == msgid )
11817c478bd9Sstevel@tonic-gate 			break;
11827c478bd9Sstevel@tonic-gate 		prev = lm;
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	if ( lm == NULL )
11867c478bd9Sstevel@tonic-gate 	{
11877c478bd9Sstevel@tonic-gate         	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
11887c478bd9Sstevel@tonic-gate 		return( -1 );
11897c478bd9Sstevel@tonic-gate 	}
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	if ( prev == NULL )
11927c478bd9Sstevel@tonic-gate 		ld->ld_responses = lm->lm_next;
11937c478bd9Sstevel@tonic-gate 	else
11947c478bd9Sstevel@tonic-gate 		prev->lm_next = lm->lm_next;
11957c478bd9Sstevel@tonic-gate         LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	msgtype = ldap_msgfree( lm );
11987c478bd9Sstevel@tonic-gate 	if ( msgtype == LDAP_RES_SEARCH_ENTRY
11997c478bd9Sstevel@tonic-gate 	    || msgtype == LDAP_RES_SEARCH_REFERENCE ) {
12007c478bd9Sstevel@tonic-gate 		return( -1 );
12017c478bd9Sstevel@tonic-gate 	}
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	return( 0 );
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate /*
12087c478bd9Sstevel@tonic-gate  * return 1 if message msgid is waiting to be abandoned, 0 otherwise
12097c478bd9Sstevel@tonic-gate  */
12107c478bd9Sstevel@tonic-gate static int
12117c478bd9Sstevel@tonic-gate ldap_abandoned( LDAP *ld, int msgid )
12127c478bd9Sstevel@tonic-gate {
12137c478bd9Sstevel@tonic-gate 	int	i;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
12167c478bd9Sstevel@tonic-gate 	if ( ld->ld_abandoned == NULL )
12177c478bd9Sstevel@tonic-gate 	{
12187c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
12197c478bd9Sstevel@tonic-gate 		return( 0 );
12207c478bd9Sstevel@tonic-gate 	}
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
12237c478bd9Sstevel@tonic-gate 		if ( ld->ld_abandoned[i] == msgid )
12247c478bd9Sstevel@tonic-gate 		{
12257c478bd9Sstevel@tonic-gate 			LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
12267c478bd9Sstevel@tonic-gate 			return( 1 );
12277c478bd9Sstevel@tonic-gate 		}
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
12307c478bd9Sstevel@tonic-gate 	return( 0 );
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate static int
12357c478bd9Sstevel@tonic-gate ldap_mark_abandoned( LDAP *ld, int msgid )
12367c478bd9Sstevel@tonic-gate {
12377c478bd9Sstevel@tonic-gate 	int	i;
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
12407c478bd9Sstevel@tonic-gate 	if ( ld->ld_abandoned == NULL )
12417c478bd9Sstevel@tonic-gate 	{
12427c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
12437c478bd9Sstevel@tonic-gate 		return( -1 );
12447c478bd9Sstevel@tonic-gate 	}
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
12477c478bd9Sstevel@tonic-gate 		if ( ld->ld_abandoned[i] == msgid )
12487c478bd9Sstevel@tonic-gate 			break;
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	if ( ld->ld_abandoned[i] == -1 )
12517c478bd9Sstevel@tonic-gate 	{
12527c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
12537c478bd9Sstevel@tonic-gate 		return( -1 );
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	for ( ; ld->ld_abandoned[i] != -1; i++ ) {
12577c478bd9Sstevel@tonic-gate 		ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
12587c478bd9Sstevel@tonic-gate 	}
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
12617c478bd9Sstevel@tonic-gate 	return( 0 );
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate #ifdef CLDAP
12667c478bd9Sstevel@tonic-gate int
12677c478bd9Sstevel@tonic-gate cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement **ber )
12687c478bd9Sstevel@tonic-gate {
12697c478bd9Sstevel@tonic-gate 	int		rc;
12707c478bd9Sstevel@tonic-gate 	ber_tag_t	tag;
12717c478bd9Sstevel@tonic-gate 	ber_len_t	len;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	if ( ld->ld_sbp->sb_ber.ber_ptr >= ld->ld_sbp->sb_ber.ber_end ) {
12747c478bd9Sstevel@tonic-gate 		rc = cldap_select1( ld, timeout );
12757c478bd9Sstevel@tonic-gate 		if ( rc == -1 || rc == 0 ) {
12767c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, (rc == -1 ? LDAP_SERVER_DOWN :
12777c478bd9Sstevel@tonic-gate 			    LDAP_TIMEOUT), NULL, NULL );
12787c478bd9Sstevel@tonic-gate 			return( rc );
12797c478bd9Sstevel@tonic-gate 		}
12807c478bd9Sstevel@tonic-gate 	}
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	/* get the next message */
12837c478bd9Sstevel@tonic-gate 	if ( (tag = ber_get_next( ld->ld_sbp, &len, ber ))
12847c478bd9Sstevel@tonic-gate 	    != LDAP_TAG_MESSAGE ) {
12857c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
12867c478bd9Sstevel@tonic-gate 		    LDAP_LOCAL_ERROR), NULL, NULL );
12877c478bd9Sstevel@tonic-gate 		return( -1 );
12887c478bd9Sstevel@tonic-gate 	}
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 	return( tag );
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate #endif /* CLDAP */
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate int
12957c478bd9Sstevel@tonic-gate nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result )
12967c478bd9Sstevel@tonic-gate {
12977c478bd9Sstevel@tonic-gate 	LDAPPend	*lp;
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
13007c478bd9Sstevel@tonic-gate 	    "nsldapi_post_result(ld=0x%x, msgid=%d, result=0x%x)\n",
13017c478bd9Sstevel@tonic-gate 	    ld, msgid, result );
13027c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_PEND_LOCK );
13037c478bd9Sstevel@tonic-gate 	if( msgid == LDAP_RES_ANY ) {
13047c478bd9Sstevel@tonic-gate 		/*
13057c478bd9Sstevel@tonic-gate 		 * Look for any pending request for which someone is waiting.
13067c478bd9Sstevel@tonic-gate 		 */
13077c478bd9Sstevel@tonic-gate 		for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
13087c478bd9Sstevel@tonic-gate 		{
13097c478bd9Sstevel@tonic-gate 			if ( lp->lp_sema != NULL ) {
13107c478bd9Sstevel@tonic-gate 				break;
1311*1da57d55SToomas Soome 			}
13127c478bd9Sstevel@tonic-gate 		}
13137c478bd9Sstevel@tonic-gate 		/*
13147c478bd9Sstevel@tonic-gate 		 * If we did't find a pending request, lp is NULL at this
13157c478bd9Sstevel@tonic-gate 		 * point, and we will leave this function without doing
13167c478bd9Sstevel@tonic-gate 		 * anything more -- which is exactly what we want to do.
13177c478bd9Sstevel@tonic-gate 		 */
13187c478bd9Sstevel@tonic-gate 	}
13197c478bd9Sstevel@tonic-gate 	else
13207c478bd9Sstevel@tonic-gate 	{
13217c478bd9Sstevel@tonic-gate 		/*
13227c478bd9Sstevel@tonic-gate 		 * Look for a pending request specific to this message id
13237c478bd9Sstevel@tonic-gate 		 */
13247c478bd9Sstevel@tonic-gate 		for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
13257c478bd9Sstevel@tonic-gate 		{
13267c478bd9Sstevel@tonic-gate 			if( lp->lp_msgid == msgid )
13277c478bd9Sstevel@tonic-gate 				break;
13287c478bd9Sstevel@tonic-gate 		}
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 		if( lp == NULL )
13317c478bd9Sstevel@tonic-gate 		{
13327c478bd9Sstevel@tonic-gate 			/*
13337c478bd9Sstevel@tonic-gate 			 * No pending requests for this response... append to
13347c478bd9Sstevel@tonic-gate 			 * our pending result list.
13357c478bd9Sstevel@tonic-gate 			 */
13367c478bd9Sstevel@tonic-gate 			LDAPPend	*newlp;
13377c478bd9Sstevel@tonic-gate 			newlp = (LDAPPend *)NSLDAPI_CALLOC( 1,
13387c478bd9Sstevel@tonic-gate 			    sizeof( LDAPPend ));
13397c478bd9Sstevel@tonic-gate 			if( newlp == NULL )
13407c478bd9Sstevel@tonic-gate 			{
13417c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
13427c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL,
13437c478bd9Sstevel@tonic-gate 				    NULL );
13447c478bd9Sstevel@tonic-gate 				return (-1);
13457c478bd9Sstevel@tonic-gate 			}
13467c478bd9Sstevel@tonic-gate 			newlp->lp_msgid = msgid;
13477c478bd9Sstevel@tonic-gate 			newlp->lp_result = result;
13487c478bd9Sstevel@tonic-gate 			link_pend( ld, newlp );
13497c478bd9Sstevel@tonic-gate 		}
13507c478bd9Sstevel@tonic-gate 	}
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	if( lp != NULL )
13547c478bd9Sstevel@tonic-gate 	{
13557c478bd9Sstevel@tonic-gate 		/*
13567c478bd9Sstevel@tonic-gate 		 * Wake up a thread that is waiting for this result.
13577c478bd9Sstevel@tonic-gate 		 */
13587c478bd9Sstevel@tonic-gate 		lp->lp_msgid = msgid;
13597c478bd9Sstevel@tonic-gate 		lp->lp_result = result;
13607c478bd9Sstevel@tonic-gate 		LDAP_SEMA_POST( ld, lp );
13617c478bd9Sstevel@tonic-gate 	}
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
13647c478bd9Sstevel@tonic-gate 	return (0);
13657c478bd9Sstevel@tonic-gate }
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate static void
13687c478bd9Sstevel@tonic-gate link_pend( LDAP *ld, LDAPPend *lp )
13697c478bd9Sstevel@tonic-gate {
13707c478bd9Sstevel@tonic-gate 	if (( lp->lp_next = ld->ld_pend ) != NULL )
13717c478bd9Sstevel@tonic-gate 	{
1372*1da57d55SToomas Soome 		lp->lp_next->lp_prev = lp;
1373*1da57d55SToomas Soome 	}
1374*1da57d55SToomas Soome 	ld->ld_pend = lp;
1375*1da57d55SToomas Soome 	lp->lp_prev = NULL;
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate #if 0 /* these functions are no longer used */
13797c478bd9Sstevel@tonic-gate static void
13807c478bd9Sstevel@tonic-gate unlink_pend( LDAP *ld, LDAPPend *lp )
13817c478bd9Sstevel@tonic-gate {
13827c478bd9Sstevel@tonic-gate         if ( lp->lp_prev == NULL ) {
13837c478bd9Sstevel@tonic-gate                 ld->ld_pend = lp->lp_next;
1384*1da57d55SToomas Soome         } else {
13857c478bd9Sstevel@tonic-gate                 lp->lp_prev->lp_next = lp->lp_next;
13867c478bd9Sstevel@tonic-gate         }
1387*1da57d55SToomas Soome 
13887c478bd9Sstevel@tonic-gate         if ( lp->lp_next != NULL ) {
13897c478bd9Sstevel@tonic-gate                 lp->lp_next->lp_prev = lp->lp_prev;
13907c478bd9Sstevel@tonic-gate         }
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate static int
13947c478bd9Sstevel@tonic-gate unlink_msg( LDAP *ld, int msgid, int all )
13957c478bd9Sstevel@tonic-gate {
13967c478bd9Sstevel@tonic-gate 	int rc;
13977c478bd9Sstevel@tonic-gate 	LDAPMessage	*lm, *lastlm, *nextlm;
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	lastlm = NULL;
14007c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
14017c478bd9Sstevel@tonic-gate 	for ( lm = ld->ld_responses; lm != NULL; lm = nextlm )
14027c478bd9Sstevel@tonic-gate 	{
14037c478bd9Sstevel@tonic-gate 		nextlm = lm->lm_next;
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		if ( lm->lm_msgid == msgid )
14067c478bd9Sstevel@tonic-gate 		{
14077c478bd9Sstevel@tonic-gate 			LDAPMessage	*tmp;
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 			if ( all == 0
14107c478bd9Sstevel@tonic-gate 			    || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
14117c478bd9Sstevel@tonic-gate 			    && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
14127c478bd9Sstevel@tonic-gate 			    && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
14137c478bd9Sstevel@tonic-gate 				break;
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 			for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
14167c478bd9Sstevel@tonic-gate 				if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
14177c478bd9Sstevel@tonic-gate 					break;
14187c478bd9Sstevel@tonic-gate 			}
14197c478bd9Sstevel@tonic-gate 			if( tmp != NULL )
14207c478bd9Sstevel@tonic-gate 				break;
14217c478bd9Sstevel@tonic-gate 		}
14227c478bd9Sstevel@tonic-gate 		lastlm = lm;
14237c478bd9Sstevel@tonic-gate 	}
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	if( lm != NULL )
14267c478bd9Sstevel@tonic-gate 	{
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 		if ( all == 0 )
14297c478bd9Sstevel@tonic-gate 		{
14307c478bd9Sstevel@tonic-gate 			if ( lm->lm_chain == NULL )
14317c478bd9Sstevel@tonic-gate 			{
14327c478bd9Sstevel@tonic-gate 				if ( lastlm == NULL )
14337c478bd9Sstevel@tonic-gate 					ld->ld_responses = lm->lm_next;
14347c478bd9Sstevel@tonic-gate 				else
14357c478bd9Sstevel@tonic-gate 					lastlm->lm_next = lm->lm_next;
14367c478bd9Sstevel@tonic-gate 			}
14377c478bd9Sstevel@tonic-gate 			else
14387c478bd9Sstevel@tonic-gate 			{
14397c478bd9Sstevel@tonic-gate 				if ( lastlm == NULL )
14407c478bd9Sstevel@tonic-gate 				{
14417c478bd9Sstevel@tonic-gate 					ld->ld_responses = lm->lm_chain;
14427c478bd9Sstevel@tonic-gate 					ld->ld_responses->lm_next = lm->lm_next;
14437c478bd9Sstevel@tonic-gate 				}
14447c478bd9Sstevel@tonic-gate 				else
14457c478bd9Sstevel@tonic-gate 				{
14467c478bd9Sstevel@tonic-gate 					lastlm->lm_next = lm->lm_chain;
14477c478bd9Sstevel@tonic-gate 					lastlm->lm_next->lm_next = lm->lm_next;
14487c478bd9Sstevel@tonic-gate 				}
14497c478bd9Sstevel@tonic-gate 			}
14507c478bd9Sstevel@tonic-gate 		}
14517c478bd9Sstevel@tonic-gate 		else
14527c478bd9Sstevel@tonic-gate 		{
14537c478bd9Sstevel@tonic-gate 			if ( lastlm == NULL )
14547c478bd9Sstevel@tonic-gate 				ld->ld_responses = lm->lm_next;
14557c478bd9Sstevel@tonic-gate 			else
14567c478bd9Sstevel@tonic-gate 				lastlm->lm_next = lm->lm_next;
14577c478bd9Sstevel@tonic-gate 		}
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 		if ( all == 0 )
14607c478bd9Sstevel@tonic-gate 			lm->lm_chain = NULL;
14617c478bd9Sstevel@tonic-gate 		lm->lm_next = NULL;
14627c478bd9Sstevel@tonic-gate 		rc = lm->lm_msgtype;
14637c478bd9Sstevel@tonic-gate 	}
14647c478bd9Sstevel@tonic-gate 	else
14657c478bd9Sstevel@tonic-gate 	{
14667c478bd9Sstevel@tonic-gate 		rc = -2;
14677c478bd9Sstevel@tonic-gate 	}
14687c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
14697c478bd9Sstevel@tonic-gate 	return ( rc );
14707c478bd9Sstevel@tonic-gate }
14717c478bd9Sstevel@tonic-gate #endif /* 0 */
1472