xref: /titanic_44/usr/src/lib/libldap5/sources/ldap/common/result.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
9*7c478bd9Sstevel@tonic-gate  *
10*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public License
11*7c478bd9Sstevel@tonic-gate  * Version 1.0 (the "NPL"); you may not use this file except in
12*7c478bd9Sstevel@tonic-gate  * compliance with the NPL.  You may obtain a copy of the NPL at
13*7c478bd9Sstevel@tonic-gate  * http://www.mozilla.org/NPL/
14*7c478bd9Sstevel@tonic-gate  *
15*7c478bd9Sstevel@tonic-gate  * Software distributed under the NPL is distributed on an "AS IS" basis,
16*7c478bd9Sstevel@tonic-gate  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
17*7c478bd9Sstevel@tonic-gate  * for the specific language governing rights and limitations under the
18*7c478bd9Sstevel@tonic-gate  * NPL.
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * The Initial Developer of this code under the NPL is Netscape
21*7c478bd9Sstevel@tonic-gate  * Communications Corporation.  Portions created by Netscape are
22*7c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
23*7c478bd9Sstevel@tonic-gate  * Reserved.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate /*
26*7c478bd9Sstevel@tonic-gate  *  Copyright (c) 1990 Regents of the University of Michigan.
27*7c478bd9Sstevel@tonic-gate  *  All rights reserved.
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  *  result.c - wait for an ldap result
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #if 0
34*7c478bd9Sstevel@tonic-gate #ifndef lint
35*7c478bd9Sstevel@tonic-gate static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
36*7c478bd9Sstevel@tonic-gate #endif
37*7c478bd9Sstevel@tonic-gate #endif
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include "ldap-int.h"
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
42*7c478bd9Sstevel@tonic-gate /* high resolution timer usage */
43*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
44*7c478bd9Sstevel@tonic-gate #endif
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate static int check_response_queue( LDAP *ld, int msgid, int all,
47*7c478bd9Sstevel@tonic-gate 	int do_abandon_check, LDAPMessage **result );
48*7c478bd9Sstevel@tonic-gate static int ldap_abandoned( LDAP *ld, int msgid );
49*7c478bd9Sstevel@tonic-gate static int ldap_mark_abandoned( LDAP *ld, int msgid );
50*7c478bd9Sstevel@tonic-gate static int wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
51*7c478bd9Sstevel@tonic-gate 	struct timeval *timeout, LDAPMessage **result );
52*7c478bd9Sstevel@tonic-gate static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
53*7c478bd9Sstevel@tonic-gate 	LDAPMessage **result );
54*7c478bd9Sstevel@tonic-gate static void check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
55*7c478bd9Sstevel@tonic-gate 	int ldapversion, int *totalcountp, int *chasingcountp );
56*7c478bd9Sstevel@tonic-gate static int build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr );
57*7c478bd9Sstevel@tonic-gate static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
58*7c478bd9Sstevel@tonic-gate #if defined( CLDAP )
59*7c478bd9Sstevel@tonic-gate static int cldap_select1( LDAP *ld, struct timeval *timeout );
60*7c478bd9Sstevel@tonic-gate #endif
61*7c478bd9Sstevel@tonic-gate static void link_pend( LDAP *ld, LDAPPend *lp );
62*7c478bd9Sstevel@tonic-gate #if 0 /* these functions are no longer used */
63*7c478bd9Sstevel@tonic-gate static void unlink_pend( LDAP *ld, LDAPPend *lp );
64*7c478bd9Sstevel@tonic-gate static int unlink_msg( LDAP *ld, int msgid, int all );
65*7c478bd9Sstevel@tonic-gate #endif /* 0 */
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate /*
68*7c478bd9Sstevel@tonic-gate  * ldap_result - wait for an ldap result response to a message from the
69*7c478bd9Sstevel@tonic-gate  * ldap server.  If msgid is -1, any message will be accepted, otherwise
70*7c478bd9Sstevel@tonic-gate  * ldap_result will wait for a response with msgid.  If all is 0 the
71*7c478bd9Sstevel@tonic-gate  * first message with id msgid will be accepted, otherwise, ldap_result
72*7c478bd9Sstevel@tonic-gate  * will wait for all responses with id msgid and then return a pointer to
73*7c478bd9Sstevel@tonic-gate  * the entire list of messages.  This is only useful for search responses,
74*7c478bd9Sstevel@tonic-gate  * which can be of two message types (zero or more entries, followed by an
75*7c478bd9Sstevel@tonic-gate  * ldap result).  The type of the first message received is returned.
76*7c478bd9Sstevel@tonic-gate  * When waiting, any messages that have been abandoned are discarded.
77*7c478bd9Sstevel@tonic-gate  *
78*7c478bd9Sstevel@tonic-gate  * Example:
79*7c478bd9Sstevel@tonic-gate  *	ldap_result( s, msgid, all, timeout, result )
80*7c478bd9Sstevel@tonic-gate  */
81*7c478bd9Sstevel@tonic-gate int
82*7c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_result(LDAP * ld,int msgid,int all,struct timeval * timeout,LDAPMessage ** result)83*7c478bd9Sstevel@tonic-gate ldap_result(
84*7c478bd9Sstevel@tonic-gate     LDAP 		*ld,
85*7c478bd9Sstevel@tonic-gate     int 		msgid,
86*7c478bd9Sstevel@tonic-gate     int 		all,
87*7c478bd9Sstevel@tonic-gate     struct timeval	*timeout,
88*7c478bd9Sstevel@tonic-gate     LDAPMessage		**result
89*7c478bd9Sstevel@tonic-gate )
90*7c478bd9Sstevel@tonic-gate {
91*7c478bd9Sstevel@tonic-gate 	int		rc;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
96*7c478bd9Sstevel@tonic-gate 		return( -1 );	/* punt */
97*7c478bd9Sstevel@tonic-gate 	}
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK );
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	rc = nsldapi_result_nolock(ld, msgid, all, 1, timeout, result);
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK );
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	return( rc );
106*7c478bd9Sstevel@tonic-gate }
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate int
nsldapi_result_nolock(LDAP * ld,int msgid,int all,int unlock_permitted,struct timeval * timeout,LDAPMessage ** result)110*7c478bd9Sstevel@tonic-gate nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted,
111*7c478bd9Sstevel@tonic-gate     struct timeval *timeout, LDAPMessage **result )
112*7c478bd9Sstevel@tonic-gate {
113*7c478bd9Sstevel@tonic-gate 	int		rc;
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
116*7c478bd9Sstevel@tonic-gate 		"nsldapi_result_nolock (msgid=%d, all=%d)\n", msgid, all, 0 );
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	/*
119*7c478bd9Sstevel@tonic-gate 	 * First, look through the list of responses we have received on
120*7c478bd9Sstevel@tonic-gate 	 * this association and see if the response we're interested in
121*7c478bd9Sstevel@tonic-gate 	 * is there.  If it is, return it.  If not, call wait4msg() to
122*7c478bd9Sstevel@tonic-gate 	 * wait until it arrives or timeout occurs.
123*7c478bd9Sstevel@tonic-gate 	 */
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	if ( result == NULL ) {
126*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
127*7c478bd9Sstevel@tonic-gate 		return( -1 );
128*7c478bd9Sstevel@tonic-gate 	}
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	if ( check_response_queue( ld, msgid, all, 1, result ) != 0 ) {
131*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
132*7c478bd9Sstevel@tonic-gate 		rc = (*result)->lm_msgtype;
133*7c478bd9Sstevel@tonic-gate 	} else {
134*7c478bd9Sstevel@tonic-gate 		rc = wait4msg( ld, msgid, all, unlock_permitted, timeout,
135*7c478bd9Sstevel@tonic-gate 		    result );
136*7c478bd9Sstevel@tonic-gate 	}
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	/*
139*7c478bd9Sstevel@tonic-gate 	 * XXXmcs should use cache function pointers to hook in memcache
140*7c478bd9Sstevel@tonic-gate 	 */
141*7c478bd9Sstevel@tonic-gate 	if ( ld->ld_memcache != NULL && NSLDAPI_SEARCH_RELATED_RESULT( rc ) &&
142*7c478bd9Sstevel@tonic-gate 	     !((*result)->lm_fromcache )) {
143*7c478bd9Sstevel@tonic-gate 		ldap_memcache_append( ld, (*result)->lm_msgid,
144*7c478bd9Sstevel@tonic-gate 		    (all || NSLDAPI_IS_SEARCH_RESULT( rc )), *result );
145*7c478bd9Sstevel@tonic-gate 	}
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	return( rc );
148*7c478bd9Sstevel@tonic-gate }
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate /*
152*7c478bd9Sstevel@tonic-gate  * Look through the list of queued responses for a message that matches the
153*7c478bd9Sstevel@tonic-gate  * criteria in the msgid and all parameters.  msgid == LDAP_RES_ANY matches
154*7c478bd9Sstevel@tonic-gate  * all ids.
155*7c478bd9Sstevel@tonic-gate  *
156*7c478bd9Sstevel@tonic-gate  * If an appropriate message is found, a non-zero value is returned and the
157*7c478bd9Sstevel@tonic-gate  * message is dequeued and assigned to *result.
158*7c478bd9Sstevel@tonic-gate  *
159*7c478bd9Sstevel@tonic-gate  * If not, *result is set to NULL and this function returns 0.
160*7c478bd9Sstevel@tonic-gate  */
161*7c478bd9Sstevel@tonic-gate static int
check_response_queue(LDAP * ld,int msgid,int all,int do_abandon_check,LDAPMessage ** result)162*7c478bd9Sstevel@tonic-gate check_response_queue( LDAP *ld, int msgid, int all, int do_abandon_check,
163*7c478bd9Sstevel@tonic-gate     LDAPMessage **result )
164*7c478bd9Sstevel@tonic-gate {
165*7c478bd9Sstevel@tonic-gate 	LDAPMessage	*lm, *lastlm, *nextlm;
166*7c478bd9Sstevel@tonic-gate 	LDAPRequest	*lr;
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
169*7c478bd9Sstevel@tonic-gate 	    "=> check_response_queue (msgid=%d, all=%d)\n", msgid, all, 0 );
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	*result = NULL;
172*7c478bd9Sstevel@tonic-gate 	lastlm = NULL;
173*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
174*7c478bd9Sstevel@tonic-gate 	for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
175*7c478bd9Sstevel@tonic-gate 		nextlm = lm->lm_next;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 		if ( do_abandon_check && ldap_abandoned( ld, lm->lm_msgid ) ) {
178*7c478bd9Sstevel@tonic-gate 			ldap_mark_abandoned( ld, lm->lm_msgid );
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 			if ( lastlm == NULL ) {
181*7c478bd9Sstevel@tonic-gate 				ld->ld_responses = lm->lm_next;
182*7c478bd9Sstevel@tonic-gate 			} else {
183*7c478bd9Sstevel@tonic-gate 				lastlm->lm_next = nextlm;
184*7c478bd9Sstevel@tonic-gate 			}
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 			ldap_msgfree( lm );
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 			continue;
189*7c478bd9Sstevel@tonic-gate 		}
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 		if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
192*7c478bd9Sstevel@tonic-gate 			LDAPMessage	*tmp;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 			if ( all == 0
195*7c478bd9Sstevel@tonic-gate 			    || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
196*7c478bd9Sstevel@tonic-gate 			    && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
197*7c478bd9Sstevel@tonic-gate 			    && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
198*7c478bd9Sstevel@tonic-gate 				break;
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 			for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
201*7c478bd9Sstevel@tonic-gate 				if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
202*7c478bd9Sstevel@tonic-gate 					break;
203*7c478bd9Sstevel@tonic-gate 			}
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 			if ( tmp == NULL ) {
206*7c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
207*7c478bd9Sstevel@tonic-gate 				LDAPDebug( LDAP_DEBUG_TRACE,
208*7c478bd9Sstevel@tonic-gate 				    "<= check_response_queue NOT FOUND\n",
209*7c478bd9Sstevel@tonic-gate 				    0, 0, 0 );
210*7c478bd9Sstevel@tonic-gate 				return( 0 );	/* no message to return */
211*7c478bd9Sstevel@tonic-gate 			}
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 			break;
214*7c478bd9Sstevel@tonic-gate 		}
215*7c478bd9Sstevel@tonic-gate 		lastlm = lm;
216*7c478bd9Sstevel@tonic-gate 	}
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	/*
219*7c478bd9Sstevel@tonic-gate 	 * if we did not find a message OR if the one we found is a result for
220*7c478bd9Sstevel@tonic-gate 	 * a request that is still pending, return failure.
221*7c478bd9Sstevel@tonic-gate 	 */
222*7c478bd9Sstevel@tonic-gate 	if ( lm == NULL
223*7c478bd9Sstevel@tonic-gate              || (( lr = nsldapi_find_request_by_msgid( ld, lm->lm_msgid ))
224*7c478bd9Sstevel@tonic-gate 		   != NULL && lr->lr_outrefcnt > 0 )) {
225*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
226*7c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_TRACE,
227*7c478bd9Sstevel@tonic-gate 		    "<= check_response_queue NOT FOUND\n",
228*7c478bd9Sstevel@tonic-gate 		    0, 0, 0 );
229*7c478bd9Sstevel@tonic-gate 		return( 0 );	/* no message to return */
230*7c478bd9Sstevel@tonic-gate 	}
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	if ( all == 0 ) {
233*7c478bd9Sstevel@tonic-gate 		if ( lm->lm_chain == NULL ) {
234*7c478bd9Sstevel@tonic-gate 			if ( lastlm == NULL ) {
235*7c478bd9Sstevel@tonic-gate 				ld->ld_responses = lm->lm_next;
236*7c478bd9Sstevel@tonic-gate 			} else {
237*7c478bd9Sstevel@tonic-gate 				lastlm->lm_next = lm->lm_next;
238*7c478bd9Sstevel@tonic-gate 			}
239*7c478bd9Sstevel@tonic-gate 		} else {
240*7c478bd9Sstevel@tonic-gate 			if ( lastlm == NULL ) {
241*7c478bd9Sstevel@tonic-gate 				ld->ld_responses = lm->lm_chain;
242*7c478bd9Sstevel@tonic-gate 				ld->ld_responses->lm_next = lm->lm_next;
243*7c478bd9Sstevel@tonic-gate 			} else {
244*7c478bd9Sstevel@tonic-gate 				lastlm->lm_next = lm->lm_chain;
245*7c478bd9Sstevel@tonic-gate 				lastlm->lm_next->lm_next = lm->lm_next;
246*7c478bd9Sstevel@tonic-gate 			}
247*7c478bd9Sstevel@tonic-gate 		}
248*7c478bd9Sstevel@tonic-gate 	} else {
249*7c478bd9Sstevel@tonic-gate 		if ( lastlm == NULL ) {
250*7c478bd9Sstevel@tonic-gate 			ld->ld_responses = lm->lm_next;
251*7c478bd9Sstevel@tonic-gate 		} else {
252*7c478bd9Sstevel@tonic-gate 			lastlm->lm_next = lm->lm_next;
253*7c478bd9Sstevel@tonic-gate 		}
254*7c478bd9Sstevel@tonic-gate 	}
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	if ( all == 0 ) {
257*7c478bd9Sstevel@tonic-gate 		lm->lm_chain = NULL;
258*7c478bd9Sstevel@tonic-gate 	}
259*7c478bd9Sstevel@tonic-gate 	lm->lm_next = NULL;
260*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	*result = lm;
263*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
264*7c478bd9Sstevel@tonic-gate 	    "<= check_response_queue returning msgid %d type %d\n",
265*7c478bd9Sstevel@tonic-gate 	    lm->lm_msgid, lm->lm_msgtype, 0 );
266*7c478bd9Sstevel@tonic-gate 	return( 1 );	/* a message was found and returned in *result */
267*7c478bd9Sstevel@tonic-gate }
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate static int
wait4msg(LDAP * ld,int msgid,int all,int unlock_permitted,struct timeval * timeout,LDAPMessage ** result)271*7c478bd9Sstevel@tonic-gate wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
272*7c478bd9Sstevel@tonic-gate 	struct timeval *timeout, LDAPMessage **result )
273*7c478bd9Sstevel@tonic-gate {
274*7c478bd9Sstevel@tonic-gate 	int		rc;
275*7c478bd9Sstevel@tonic-gate 	struct timeval	tv, *tvp;
276*7c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
277*7c478bd9Sstevel@tonic-gate 	hrtime_t	start_time = 0, tmp_time, tv_time;
278*7c478bd9Sstevel@tonic-gate #else
279*7c478bd9Sstevel@tonic-gate 	long		start_time = 0, tmp_time;
280*7c478bd9Sstevel@tonic-gate #endif
281*7c478bd9Sstevel@tonic-gate 	LDAPConn	*lc, *nextlc;
282*7c478bd9Sstevel@tonic-gate 	LDAPRequest	*lr;
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate #ifdef LDAP_DEBUG
285*7c478bd9Sstevel@tonic-gate 	if ( timeout == NULL ) {
286*7c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",
287*7c478bd9Sstevel@tonic-gate 		    0, 0, 0 );
288*7c478bd9Sstevel@tonic-gate 	} else {
289*7c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",
290*7c478bd9Sstevel@tonic-gate 		    timeout->tv_sec, timeout->tv_usec, 0 );
291*7c478bd9Sstevel@tonic-gate 	}
292*7c478bd9Sstevel@tonic-gate #endif /* LDAP_DEBUG */
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	/* check the cache */
295*7c478bd9Sstevel@tonic-gate 	if ( ld->ld_cache_on && ld->ld_cache_result != NULL ) {
296*7c478bd9Sstevel@tonic-gate 		/* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */
297*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
298*7c478bd9Sstevel@tonic-gate 		rc = (ld->ld_cache_result)( ld, msgid, all, timeout, result );
299*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
300*7c478bd9Sstevel@tonic-gate 		/* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
301*7c478bd9Sstevel@tonic-gate 		if ( rc != 0 ) {
302*7c478bd9Sstevel@tonic-gate 			return( rc );
303*7c478bd9Sstevel@tonic-gate 		}
304*7c478bd9Sstevel@tonic-gate 		if ( ld->ld_cache_strategy == LDAP_CACHE_LOCALDB ) {
305*7c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL );
306*7c478bd9Sstevel@tonic-gate 			return( 0 );	/* timeout */
307*7c478bd9Sstevel@tonic-gate 		}
308*7c478bd9Sstevel@tonic-gate 	}
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	/*
311*7c478bd9Sstevel@tonic-gate 	 * if we are looking for a specific msgid, check to see if it is
312*7c478bd9Sstevel@tonic-gate 	 * associated with a dead connection and return an error if so.
313*7c478bd9Sstevel@tonic-gate 	 */
314*7c478bd9Sstevel@tonic-gate 	if ( msgid != LDAP_RES_ANY && msgid != LDAP_RES_UNSOLICITED ) {
315*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
316*7c478bd9Sstevel@tonic-gate 		if (( lr = nsldapi_find_request_by_msgid( ld, msgid ))
317*7c478bd9Sstevel@tonic-gate 		    == NULL ) {
318*7c478bd9Sstevel@tonic-gate 			LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
319*7c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL,
320*7c478bd9Sstevel@tonic-gate 				nsldapi_strdup( dgettext(TEXT_DOMAIN,
321*7c478bd9Sstevel@tonic-gate 					"unknown message id") ));
322*7c478bd9Sstevel@tonic-gate 			return( -1 );	/* could not find request for msgid */
323*7c478bd9Sstevel@tonic-gate 		}
324*7c478bd9Sstevel@tonic-gate 		if ( lr->lr_conn != NULL &&
325*7c478bd9Sstevel@tonic-gate 		    lr->lr_conn->lconn_status == LDAP_CONNST_DEAD ) {
326*7c478bd9Sstevel@tonic-gate 			nsldapi_free_request( ld, lr, 1 );
327*7c478bd9Sstevel@tonic-gate 			LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
328*7c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
329*7c478bd9Sstevel@tonic-gate 			return( -1 );	/* connection dead */
330*7c478bd9Sstevel@tonic-gate 		}
331*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
332*7c478bd9Sstevel@tonic-gate 	}
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	if ( timeout == NULL ) {
335*7c478bd9Sstevel@tonic-gate 		tvp = NULL;
336*7c478bd9Sstevel@tonic-gate 	} else {
337*7c478bd9Sstevel@tonic-gate 		tv = *timeout;
338*7c478bd9Sstevel@tonic-gate 		tvp = &tv;
339*7c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
340*7c478bd9Sstevel@tonic-gate 		start_time = gethrtime();
341*7c478bd9Sstevel@tonic-gate 		tv_time = ((hrtime_t)tv.tv_sec * NANOSEC +
342*7c478bd9Sstevel@tonic-gate 			(hrtime_t)tv.tv_usec * (NANOSEC / MICROSEC));
343*7c478bd9Sstevel@tonic-gate #else
344*7c478bd9Sstevel@tonic-gate 		start_time = (long)time( NULL );
345*7c478bd9Sstevel@tonic-gate #endif
346*7c478bd9Sstevel@tonic-gate 	}
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	rc = -2;
349*7c478bd9Sstevel@tonic-gate 	while ( rc == -2 ) {
350*7c478bd9Sstevel@tonic-gate #ifdef LDAP_DEBUG
351*7c478bd9Sstevel@tonic-gate 		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
352*7c478bd9Sstevel@tonic-gate 			nsldapi_dump_connection( ld, ld->ld_conns, 1 );
353*7c478bd9Sstevel@tonic-gate 			nsldapi_dump_requests_and_responses( ld );
354*7c478bd9Sstevel@tonic-gate 		}
355*7c478bd9Sstevel@tonic-gate #endif /* LDAP_DEBUG */
356*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
357*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
358*7c478bd9Sstevel@tonic-gate 		for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
359*7c478bd9Sstevel@tonic-gate 			if ( lc->lconn_sb->sb_ber.ber_ptr <
360*7c478bd9Sstevel@tonic-gate 			    lc->lconn_sb->sb_ber.ber_end ) {
361*7c478bd9Sstevel@tonic-gate 				rc = read1msg( ld, msgid, all, lc->lconn_sb,
362*7c478bd9Sstevel@tonic-gate 				    lc, result );
363*7c478bd9Sstevel@tonic-gate 				break;
364*7c478bd9Sstevel@tonic-gate 			}
365*7c478bd9Sstevel@tonic-gate 		}
366*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
367*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 		if ( lc == NULL ) {
370*7c478bd9Sstevel@tonic-gate 			rc = nsldapi_iostatus_poll( ld, tvp );
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate #if defined( LDAP_DEBUG ) && !defined( macintosh ) && !defined( DOS )
373*7c478bd9Sstevel@tonic-gate 			if ( rc == -1 ) {
374*7c478bd9Sstevel@tonic-gate 			    LDAPDebug( LDAP_DEBUG_TRACE,
375*7c478bd9Sstevel@tonic-gate 				    "nsldapi_iostatus_poll returned -1: errno %d\n",
376*7c478bd9Sstevel@tonic-gate 				    LDAP_GET_ERRNO( ld ), 0, 0 );
377*7c478bd9Sstevel@tonic-gate 			}
378*7c478bd9Sstevel@tonic-gate #endif
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate #if !defined( macintosh ) && !defined( DOS )
381*7c478bd9Sstevel@tonic-gate 			if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
382*7c478bd9Sstevel@tonic-gate 			    LDAP_BITOPT_RESTART ) == 0 ||
383*7c478bd9Sstevel@tonic-gate 			    LDAP_GET_ERRNO( ld ) != EINTR ))) {
384*7c478bd9Sstevel@tonic-gate #else
385*7c478bd9Sstevel@tonic-gate 			if ( rc == -1 || rc == 0 ) {
386*7c478bd9Sstevel@tonic-gate #endif
387*7c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, (rc == -1 ?
388*7c478bd9Sstevel@tonic-gate 				    LDAP_SERVER_DOWN : LDAP_TIMEOUT), NULL,
389*7c478bd9Sstevel@tonic-gate 				    NULL );
390*7c478bd9Sstevel@tonic-gate 				if ( rc == -1 ) {
391*7c478bd9Sstevel@tonic-gate 					LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
392*7c478bd9Sstevel@tonic-gate 					nsldapi_connection_lost_nolock( ld,
393*7c478bd9Sstevel@tonic-gate 						NULL );
394*7c478bd9Sstevel@tonic-gate 					LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
395*7c478bd9Sstevel@tonic-gate 				}
396*7c478bd9Sstevel@tonic-gate 				return( rc );
397*7c478bd9Sstevel@tonic-gate 			}
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 			if ( rc == -1 ) {
400*7c478bd9Sstevel@tonic-gate 				rc = -2;	/* select interrupted: loop */
401*7c478bd9Sstevel@tonic-gate 			} else {
402*7c478bd9Sstevel@tonic-gate 				rc = -2;
403*7c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
404*7c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
405*7c478bd9Sstevel@tonic-gate 				for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
406*7c478bd9Sstevel@tonic-gate 				    lc = nextlc ) {
407*7c478bd9Sstevel@tonic-gate 					nextlc = lc->lconn_next;
408*7c478bd9Sstevel@tonic-gate 					if ( lc->lconn_status ==
409*7c478bd9Sstevel@tonic-gate 					    LDAP_CONNST_CONNECTED &&
410*7c478bd9Sstevel@tonic-gate 					    nsldapi_iostatus_is_read_ready( ld,
411*7c478bd9Sstevel@tonic-gate 					    lc->lconn_sb )) {
412*7c478bd9Sstevel@tonic-gate 						rc = read1msg( ld, msgid, all,
413*7c478bd9Sstevel@tonic-gate 						    lc->lconn_sb, lc, result );
414*7c478bd9Sstevel@tonic-gate 					}
415*7c478bd9Sstevel@tonic-gate 					else if (ld->ld_options & LDAP_BITOPT_ASYNC) {
416*7c478bd9Sstevel@tonic-gate                         if ( lr
417*7c478bd9Sstevel@tonic-gate                               && lc->lconn_status == LDAP_CONNST_CONNECTING
418*7c478bd9Sstevel@tonic-gate                               && nsldapi_iostatus_is_write_ready( ld,
419*7c478bd9Sstevel@tonic-gate 			      lc->lconn_sb ) ) {
420*7c478bd9Sstevel@tonic-gate                             rc = nsldapi_ber_flush( ld, lc->lconn_sb, lr->lr_ber, 0, 1 );
421*7c478bd9Sstevel@tonic-gate                             if ( rc == 0 ) {
422*7c478bd9Sstevel@tonic-gate                                 rc = LDAP_RES_BIND;
423*7c478bd9Sstevel@tonic-gate                                 lc->lconn_status = LDAP_CONNST_CONNECTED;
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate                                 lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
426*7c478bd9Sstevel@tonic-gate                                 lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
427*7c478bd9Sstevel@tonic-gate                                 nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
428*7c478bd9Sstevel@tonic-gate                             }
429*7c478bd9Sstevel@tonic-gate                             else if ( rc == -1 ) {
430*7c478bd9Sstevel@tonic-gate                                 LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
431*7c478bd9Sstevel@tonic-gate                                 nsldapi_free_request( ld, lr, 0 );
432*7c478bd9Sstevel@tonic-gate                                 nsldapi_free_connection( ld, lc, NULL, NULL,
433*7c478bd9Sstevel@tonic-gate 				    0, 0 );
434*7c478bd9Sstevel@tonic-gate                             }
435*7c478bd9Sstevel@tonic-gate                         }
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 					}
438*7c478bd9Sstevel@tonic-gate 				}
439*7c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
440*7c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
441*7c478bd9Sstevel@tonic-gate 			}
442*7c478bd9Sstevel@tonic-gate 		}
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 		/*
445*7c478bd9Sstevel@tonic-gate 		 * It is possible that recursion occurred while chasing
446*7c478bd9Sstevel@tonic-gate 		 * referrals and as a result the message we are looking
447*7c478bd9Sstevel@tonic-gate 		 * for may have been placed on the response queue.  Look
448*7c478bd9Sstevel@tonic-gate 		 * for it there before continuing so we don't end up
449*7c478bd9Sstevel@tonic-gate 		 * waiting on the network for a message that we already
450*7c478bd9Sstevel@tonic-gate 		 * received!
451*7c478bd9Sstevel@tonic-gate 		 */
452*7c478bd9Sstevel@tonic-gate 		if ( rc == -2 &&
453*7c478bd9Sstevel@tonic-gate 		    check_response_queue( ld, msgid, all, 0, result ) != 0 ) {
454*7c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
455*7c478bd9Sstevel@tonic-gate 			rc = (*result)->lm_msgtype;
456*7c478bd9Sstevel@tonic-gate 		}
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 		/*
459*7c478bd9Sstevel@tonic-gate 		 * honor the timeout if specified
460*7c478bd9Sstevel@tonic-gate 		 */
461*7c478bd9Sstevel@tonic-gate 		if ( rc == -2 && tvp != NULL ) {
462*7c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
463*7c478bd9Sstevel@tonic-gate 			tmp_time = gethrtime();
464*7c478bd9Sstevel@tonic-gate 			if ((tv_time -=  (tmp_time - start_time)) <= 0) {
465*7c478bd9Sstevel@tonic-gate #else
466*7c478bd9Sstevel@tonic-gate 			tmp_time = (long)time( NULL );
467*7c478bd9Sstevel@tonic-gate 			if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
468*7c478bd9Sstevel@tonic-gate #endif
469*7c478bd9Sstevel@tonic-gate 				rc = 0;	/* timed out */
470*7c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL,
471*7c478bd9Sstevel@tonic-gate 				    NULL );
472*7c478bd9Sstevel@tonic-gate 				break;
473*7c478bd9Sstevel@tonic-gate 			}
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
476*7c478bd9Sstevel@tonic-gate 			tv.tv_sec = tv_time / NANOSEC;
477*7c478bd9Sstevel@tonic-gate 			tv.tv_usec = (tv_time % NANOSEC) / (NANOSEC / MICROSEC);
478*7c478bd9Sstevel@tonic-gate #endif
479*7c478bd9Sstevel@tonic-gate 			LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
480*7c478bd9Sstevel@tonic-gate 				tv.tv_sec, 0, 0 );
481*7c478bd9Sstevel@tonic-gate 			start_time = tmp_time;
482*7c478bd9Sstevel@tonic-gate 		}
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	return( rc );
486*7c478bd9Sstevel@tonic-gate }
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate /*
490*7c478bd9Sstevel@tonic-gate  * read1msg() should be called with LDAP_CONN_LOCK and LDAP_REQ_LOCK locked.
491*7c478bd9Sstevel@tonic-gate  */
492*7c478bd9Sstevel@tonic-gate static int
493*7c478bd9Sstevel@tonic-gate read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
494*7c478bd9Sstevel@tonic-gate     LDAPMessage **result )
495*7c478bd9Sstevel@tonic-gate {
496*7c478bd9Sstevel@tonic-gate 	BerElement	*ber;
497*7c478bd9Sstevel@tonic-gate 	LDAPMessage	*new, *l, *prev, *chainprev, *tmp;
498*7c478bd9Sstevel@tonic-gate 	ber_int_t	id;
499*7c478bd9Sstevel@tonic-gate 	ber_tag_t	tag;
500*7c478bd9Sstevel@tonic-gate 	ber_len_t	len;
501*7c478bd9Sstevel@tonic-gate 	int		terrno, lderr, foundit = 0;
502*7c478bd9Sstevel@tonic-gate 	LDAPRequest	*lr;
503*7c478bd9Sstevel@tonic-gate 	int		rc, has_parent, message_can_be_returned;
504*7c478bd9Sstevel@tonic-gate 	int		manufactured_result = 0;
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	message_can_be_returned = 1;	/* the usual case... */
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	/*
511*7c478bd9Sstevel@tonic-gate 	 * if we are not already in the midst of reading a message, allocate
512*7c478bd9Sstevel@tonic-gate 	 * a ber that is associated with this connection
513*7c478bd9Sstevel@tonic-gate 	 */
514*7c478bd9Sstevel@tonic-gate 	if ( lc->lconn_ber == NULLBER && nsldapi_alloc_ber_with_options( ld,
515*7c478bd9Sstevel@tonic-gate 	    &lc->lconn_ber ) != LDAP_SUCCESS ) {
516*7c478bd9Sstevel@tonic-gate 		return( -1 );
517*7c478bd9Sstevel@tonic-gate 	}
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	/*
520*7c478bd9Sstevel@tonic-gate 	 * ber_get_next() doesn't set errno on EOF, so we pre-set it to
521*7c478bd9Sstevel@tonic-gate 	 * zero to avoid getting tricked by leftover "EAGAIN" errors
522*7c478bd9Sstevel@tonic-gate 	 */
523*7c478bd9Sstevel@tonic-gate 	LDAP_SET_ERRNO( ld, 0 );
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	/* get the next message */
526*7c478bd9Sstevel@tonic-gate 	if ( (tag = ber_get_next( sb, &len, lc->lconn_ber ))
527*7c478bd9Sstevel@tonic-gate 	    != LDAP_TAG_MESSAGE ) {
528*7c478bd9Sstevel@tonic-gate 		terrno = LDAP_GET_ERRNO( ld );
529*7c478bd9Sstevel@tonic-gate 		if ( terrno == EWOULDBLOCK || terrno == EAGAIN ) {
530*7c478bd9Sstevel@tonic-gate 		    return( -2 );	/* try again */
531*7c478bd9Sstevel@tonic-gate 		}
532*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
533*7c478bd9Sstevel@tonic-gate                     LDAP_LOCAL_ERROR), NULL, NULL );
534*7c478bd9Sstevel@tonic-gate 		if ( tag == LBER_DEFAULT ) {
535*7c478bd9Sstevel@tonic-gate 			nsldapi_connection_lost_nolock( ld, sb );
536*7c478bd9Sstevel@tonic-gate 		}
537*7c478bd9Sstevel@tonic-gate 		return( -1 );
538*7c478bd9Sstevel@tonic-gate 	}
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	/*
541*7c478bd9Sstevel@tonic-gate 	 * Since we have received a complete message now, we pull this ber
542*7c478bd9Sstevel@tonic-gate 	 * out of the connection structure and never read into it again.
543*7c478bd9Sstevel@tonic-gate 	 */
544*7c478bd9Sstevel@tonic-gate 	ber = lc->lconn_ber;
545*7c478bd9Sstevel@tonic-gate 	lc->lconn_ber = NULLBER;
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	/* message id */
548*7c478bd9Sstevel@tonic-gate 	if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
549*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
550*7c478bd9Sstevel@tonic-gate 		return( -1 );
551*7c478bd9Sstevel@tonic-gate 	}
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	/* if it's been abandoned, toss it */
554*7c478bd9Sstevel@tonic-gate 	if ( ldap_abandoned( ld, (int)id ) ) {
555*7c478bd9Sstevel@tonic-gate 		ber_free( ber, 1 );
556*7c478bd9Sstevel@tonic-gate 		return( -2 );	/* continue looking */
557*7c478bd9Sstevel@tonic-gate 	}
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 	if ( id == LDAP_RES_UNSOLICITED ) {
560*7c478bd9Sstevel@tonic-gate 		lr = NULL;
561*7c478bd9Sstevel@tonic-gate 	} else if (( lr = nsldapi_find_request_by_msgid( ld, id )) == NULL ) {
562*7c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_ANY,
563*7c478bd9Sstevel@tonic-gate 		    "no request for response with msgid %ld (tossing)\n",
564*7c478bd9Sstevel@tonic-gate 		    id, 0, 0 );
565*7c478bd9Sstevel@tonic-gate 		ber_free( ber, 1 );
566*7c478bd9Sstevel@tonic-gate 		return( -2 );	/* continue looking */
567*7c478bd9Sstevel@tonic-gate 	}
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	/* the message type */
570*7c478bd9Sstevel@tonic-gate 	if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
571*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
572*7c478bd9Sstevel@tonic-gate 		return( -1 );
573*7c478bd9Sstevel@tonic-gate 	}
574*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n",
575*7c478bd9Sstevel@tonic-gate 	    ( tag == LDAP_RES_SEARCH_ENTRY ) ? "ENTRY" :
576*7c478bd9Sstevel@tonic-gate 	    ( tag == LDAP_RES_SEARCH_REFERENCE ) ? "REFERENCE" : "RESULT", id,
577*7c478bd9Sstevel@tonic-gate 	    ( lr == NULL ) ? id : lr->lr_origid );
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 	if ( lr != NULL ) {
580*7c478bd9Sstevel@tonic-gate 		id = lr->lr_origid;
581*7c478bd9Sstevel@tonic-gate 		lr->lr_res_msgtype = tag;
582*7c478bd9Sstevel@tonic-gate 	}
583*7c478bd9Sstevel@tonic-gate 	rc = -2;	/* default is to keep looking (no response found) */
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	if ( id != LDAP_RES_UNSOLICITED && ( tag == LDAP_RES_SEARCH_REFERENCE ||
586*7c478bd9Sstevel@tonic-gate 	    tag != LDAP_RES_SEARCH_ENTRY )) {
587*7c478bd9Sstevel@tonic-gate 		int		refchasing, reftotal, simple_request = 0;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 		check_for_refs( ld, lr, ber, lc->lconn_version, &reftotal,
590*7c478bd9Sstevel@tonic-gate 		    &refchasing );
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 		if ( refchasing > 0 || lr->lr_outrefcnt > 0 ) {
593*7c478bd9Sstevel@tonic-gate 			/*
594*7c478bd9Sstevel@tonic-gate 			 * we're chasing one or more new refs...
595*7c478bd9Sstevel@tonic-gate 			 */
596*7c478bd9Sstevel@tonic-gate 			ber_free( ber, 1 );
597*7c478bd9Sstevel@tonic-gate 			ber = NULLBER;
598*7c478bd9Sstevel@tonic-gate 			lr->lr_status = LDAP_REQST_CHASINGREFS;
599*7c478bd9Sstevel@tonic-gate 			message_can_be_returned = 0;
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 		} else if ( tag != LDAP_RES_SEARCH_REFERENCE ) {
602*7c478bd9Sstevel@tonic-gate 			/*
603*7c478bd9Sstevel@tonic-gate 			 * this request is complete...
604*7c478bd9Sstevel@tonic-gate 			 */
605*7c478bd9Sstevel@tonic-gate 			has_parent = ( lr->lr_parent != NULL );
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 			if ( lr->lr_outrefcnt <= 0 && !has_parent ) {
608*7c478bd9Sstevel@tonic-gate 				/* request without any refs */
609*7c478bd9Sstevel@tonic-gate 				simple_request = ( reftotal == 0 );
610*7c478bd9Sstevel@tonic-gate 			}
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 			/*
613*7c478bd9Sstevel@tonic-gate 			 * If this is not a child request and it is a bind
614*7c478bd9Sstevel@tonic-gate 			 * request, reset the connection's bind DN and
615*7c478bd9Sstevel@tonic-gate 			 * status based on the result of the operation.
616*7c478bd9Sstevel@tonic-gate 			 */
617*7c478bd9Sstevel@tonic-gate 			if ( !has_parent &&
618*7c478bd9Sstevel@tonic-gate 			    LDAP_RES_BIND == lr->lr_res_msgtype &&
619*7c478bd9Sstevel@tonic-gate 			    lr->lr_conn != NULL ) {
620*7c478bd9Sstevel@tonic-gate 				if ( lr->lr_conn->lconn_binddn != NULL ) {
621*7c478bd9Sstevel@tonic-gate 					NSLDAPI_FREE(
622*7c478bd9Sstevel@tonic-gate 					    lr->lr_conn->lconn_binddn );
623*7c478bd9Sstevel@tonic-gate 				}
624*7c478bd9Sstevel@tonic-gate 				if ( LDAP_SUCCESS == nsldapi_parse_result( ld,
625*7c478bd9Sstevel@tonic-gate 				    lr->lr_res_msgtype, ber, &lderr, NULL,
626*7c478bd9Sstevel@tonic-gate 				    NULL, NULL, NULL )
627*7c478bd9Sstevel@tonic-gate 				    && LDAP_SUCCESS == lderr ) {
628*7c478bd9Sstevel@tonic-gate 					lr->lr_conn->lconn_bound = 1;
629*7c478bd9Sstevel@tonic-gate 					lr->lr_conn->lconn_binddn =
630*7c478bd9Sstevel@tonic-gate 					    lr->lr_binddn;
631*7c478bd9Sstevel@tonic-gate 					lr->lr_binddn = NULL;
632*7c478bd9Sstevel@tonic-gate 				} else {
633*7c478bd9Sstevel@tonic-gate 					lr->lr_conn->lconn_bound = 0;
634*7c478bd9Sstevel@tonic-gate 					lr->lr_conn->lconn_binddn = NULL;
635*7c478bd9Sstevel@tonic-gate 				}
636*7c478bd9Sstevel@tonic-gate 			}
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 			/*
639*7c478bd9Sstevel@tonic-gate 			 * if this response is to a child request, we toss
640*7c478bd9Sstevel@tonic-gate 			 * the message contents and just merge error info.
641*7c478bd9Sstevel@tonic-gate 			 * into the parent.
642*7c478bd9Sstevel@tonic-gate 			 */
643*7c478bd9Sstevel@tonic-gate 			if ( has_parent ) {
644*7c478bd9Sstevel@tonic-gate 				ber_free( ber, 1 );
645*7c478bd9Sstevel@tonic-gate 				ber = NULLBER;
646*7c478bd9Sstevel@tonic-gate 			}
647*7c478bd9Sstevel@tonic-gate 			while ( lr->lr_parent != NULL ) {
648*7c478bd9Sstevel@tonic-gate 				merge_error_info( ld, lr->lr_parent, lr );
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 				lr = lr->lr_parent;
651*7c478bd9Sstevel@tonic-gate 				if ( --lr->lr_outrefcnt > 0 ) {
652*7c478bd9Sstevel@tonic-gate 					break;	/* not completely done yet */
653*7c478bd9Sstevel@tonic-gate 				}
654*7c478bd9Sstevel@tonic-gate 			}
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 			/*
657*7c478bd9Sstevel@tonic-gate 			 * we recognize a request as complete when:
658*7c478bd9Sstevel@tonic-gate 			 *  1) it has no outstanding referrals
659*7c478bd9Sstevel@tonic-gate 			 *  2) it is not a child request
660*7c478bd9Sstevel@tonic-gate 			 *  3) we have received a result for the request (i.e.,
661*7c478bd9Sstevel@tonic-gate 			 *     something other than an entry or a reference).
662*7c478bd9Sstevel@tonic-gate 			 */
663*7c478bd9Sstevel@tonic-gate 			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL &&
664*7c478bd9Sstevel@tonic-gate 			    lr->lr_res_msgtype != LDAP_RES_SEARCH_ENTRY &&
665*7c478bd9Sstevel@tonic-gate 			    lr->lr_res_msgtype != LDAP_RES_SEARCH_REFERENCE ) {
666*7c478bd9Sstevel@tonic-gate 				id = lr->lr_msgid;
667*7c478bd9Sstevel@tonic-gate 				tag = lr->lr_res_msgtype;
668*7c478bd9Sstevel@tonic-gate 				LDAPDebug( LDAP_DEBUG_TRACE,
669*7c478bd9Sstevel@tonic-gate 				    "request %ld done\n", id, 0, 0 );
670*7c478bd9Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
671*7c478bd9Sstevel@tonic-gate "res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
672*7c478bd9Sstevel@tonic-gate lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
673*7c478bd9Sstevel@tonic-gate lr->lr_res_matched ? lr->lr_res_matched : "" );
674*7c478bd9Sstevel@tonic-gate 				if ( !simple_request ) {
675*7c478bd9Sstevel@tonic-gate 					if ( ber != NULLBER ) {
676*7c478bd9Sstevel@tonic-gate 						ber_free( ber, 1 );
677*7c478bd9Sstevel@tonic-gate 						ber = NULLBER;
678*7c478bd9Sstevel@tonic-gate 					}
679*7c478bd9Sstevel@tonic-gate 					if ( build_result_ber( ld, &ber, lr )
680*7c478bd9Sstevel@tonic-gate 					    != LDAP_SUCCESS ) {
681*7c478bd9Sstevel@tonic-gate 						rc = -1; /* fatal error */
682*7c478bd9Sstevel@tonic-gate 					} else {
683*7c478bd9Sstevel@tonic-gate 						manufactured_result = 1;
684*7c478bd9Sstevel@tonic-gate 					}
685*7c478bd9Sstevel@tonic-gate 				}
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 				nsldapi_free_request( ld, lr, 1 );
688*7c478bd9Sstevel@tonic-gate 			} else {
689*7c478bd9Sstevel@tonic-gate 				message_can_be_returned = 0;
690*7c478bd9Sstevel@tonic-gate 			}
691*7c478bd9Sstevel@tonic-gate 		}
692*7c478bd9Sstevel@tonic-gate 	}
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	if ( ber == NULLBER ) {
695*7c478bd9Sstevel@tonic-gate 		return( rc );
696*7c478bd9Sstevel@tonic-gate 	}
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	/* make a new ldap message */
699*7c478bd9Sstevel@tonic-gate 	if ( (new = (LDAPMessage*)NSLDAPI_CALLOC( 1, sizeof(struct ldapmsg) ))
700*7c478bd9Sstevel@tonic-gate 	    == NULL ) {
701*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
702*7c478bd9Sstevel@tonic-gate 		return( -1 );
703*7c478bd9Sstevel@tonic-gate 	}
704*7c478bd9Sstevel@tonic-gate 	new->lm_msgid = (int)id;
705*7c478bd9Sstevel@tonic-gate 	new->lm_msgtype = tag;
706*7c478bd9Sstevel@tonic-gate 	new->lm_ber = ber;
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	/*
709*7c478bd9Sstevel@tonic-gate 	 * if this is a search entry or if this request is complete (i.e.,
710*7c478bd9Sstevel@tonic-gate 	 * there are no outstanding referrals) then add to cache and check
711*7c478bd9Sstevel@tonic-gate 	 * to see if we should return this to the caller right away or not.
712*7c478bd9Sstevel@tonic-gate 	 */
713*7c478bd9Sstevel@tonic-gate 	if ( message_can_be_returned ) {
714*7c478bd9Sstevel@tonic-gate 		if ( ld->ld_cache_on ) {
715*7c478bd9Sstevel@tonic-gate 			nsldapi_add_result_to_cache( ld, new );
716*7c478bd9Sstevel@tonic-gate 		}
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 		if ( msgid == LDAP_RES_ANY || id == msgid ) {
719*7c478bd9Sstevel@tonic-gate 			if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
720*7c478bd9Sstevel@tonic-gate 				/*
721*7c478bd9Sstevel@tonic-gate 				 * return the first response we have for this
722*7c478bd9Sstevel@tonic-gate 				 * search request later (possibly an entire
723*7c478bd9Sstevel@tonic-gate 				 * chain of messages).
724*7c478bd9Sstevel@tonic-gate 				 */
725*7c478bd9Sstevel@tonic-gate 				foundit = 1;
726*7c478bd9Sstevel@tonic-gate 			} else if ( all == 0
727*7c478bd9Sstevel@tonic-gate 			    || (new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
728*7c478bd9Sstevel@tonic-gate 			    && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {
729*7c478bd9Sstevel@tonic-gate 				*result = new;
730*7c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL,
731*7c478bd9Sstevel@tonic-gate 				    NULL );
732*7c478bd9Sstevel@tonic-gate 				return( tag );
733*7c478bd9Sstevel@tonic-gate 			}
734*7c478bd9Sstevel@tonic-gate 		}
735*7c478bd9Sstevel@tonic-gate 	}
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 	/*
738*7c478bd9Sstevel@tonic-gate 	 * if not, we must add it to the list of responses.  if
739*7c478bd9Sstevel@tonic-gate 	 * the msgid is already there, it must be part of an existing
740*7c478bd9Sstevel@tonic-gate 	 * search response.
741*7c478bd9Sstevel@tonic-gate 	 */
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	prev = NULL;
744*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
745*7c478bd9Sstevel@tonic-gate 	for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
746*7c478bd9Sstevel@tonic-gate 		if ( l->lm_msgid == new->lm_msgid )
747*7c478bd9Sstevel@tonic-gate 			break;
748*7c478bd9Sstevel@tonic-gate 		prev = l;
749*7c478bd9Sstevel@tonic-gate 	}
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 	/* not part of an existing search response */
752*7c478bd9Sstevel@tonic-gate 	if ( l == NULL ) {
753*7c478bd9Sstevel@tonic-gate 		if ( foundit ) {
754*7c478bd9Sstevel@tonic-gate 			LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
755*7c478bd9Sstevel@tonic-gate 			*result = new;
756*7c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
757*7c478bd9Sstevel@tonic-gate 			return( tag );
758*7c478bd9Sstevel@tonic-gate 		}
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 		new->lm_next = ld->ld_responses;
761*7c478bd9Sstevel@tonic-gate 		ld->ld_responses = new;
762*7c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_TRACE,
763*7c478bd9Sstevel@tonic-gate 		    "adding new response id %d type %d (looking for id %d)\n",
764*7c478bd9Sstevel@tonic-gate 		    new->lm_msgid, new->lm_msgtype, msgid );
765*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
766*7c478bd9Sstevel@tonic-gate 		if( message_can_be_returned )
767*7c478bd9Sstevel@tonic-gate 			POST( ld, new->lm_msgid, new );
768*7c478bd9Sstevel@tonic-gate 		return( -2 );	/* continue looking */
769*7c478bd9Sstevel@tonic-gate 	}
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
772*7c478bd9Sstevel@tonic-gate 	    "adding response id %d type %d (looking for id %d)\n",
773*7c478bd9Sstevel@tonic-gate 	    new->lm_msgid, new->lm_msgtype, msgid );
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 	/*
776*7c478bd9Sstevel@tonic-gate 	 * part of a search response - add to end of list of entries
777*7c478bd9Sstevel@tonic-gate 	 *
778*7c478bd9Sstevel@tonic-gate 	 * the first step is to find the end of the list of entries and
779*7c478bd9Sstevel@tonic-gate 	 * references.  after the following loop is executed, tmp points to
780*7c478bd9Sstevel@tonic-gate 	 * the last entry or reference in the chain.  If there are none,
781*7c478bd9Sstevel@tonic-gate 	 * tmp points to the search result.
782*7c478bd9Sstevel@tonic-gate 	 */
783*7c478bd9Sstevel@tonic-gate 	chainprev = NULL;
784*7c478bd9Sstevel@tonic-gate 	for ( tmp = l; tmp->lm_chain != NULL &&
785*7c478bd9Sstevel@tonic-gate 	    ( tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY
786*7c478bd9Sstevel@tonic-gate 	    || tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE );
787*7c478bd9Sstevel@tonic-gate 	    tmp = tmp->lm_chain ) {
788*7c478bd9Sstevel@tonic-gate 		chainprev = tmp;
789*7c478bd9Sstevel@tonic-gate 	}
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 	/*
792*7c478bd9Sstevel@tonic-gate 	 * If this is a manufactured result message and a result is already
793*7c478bd9Sstevel@tonic-gate 	 * queued we throw away the one that is queued and replace it with
794*7c478bd9Sstevel@tonic-gate 	 * our new result.  This is necessary so we don't end up returning
795*7c478bd9Sstevel@tonic-gate 	 * more than one result.
796*7c478bd9Sstevel@tonic-gate 	 */
797*7c478bd9Sstevel@tonic-gate 	if ( manufactured_result &&
798*7c478bd9Sstevel@tonic-gate 	    tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
799*7c478bd9Sstevel@tonic-gate 		/*
800*7c478bd9Sstevel@tonic-gate 		 * the result is the only thing in the chain... replace it.
801*7c478bd9Sstevel@tonic-gate 		 */
802*7c478bd9Sstevel@tonic-gate 		new->lm_chain = tmp->lm_chain;
803*7c478bd9Sstevel@tonic-gate 		new->lm_next = tmp->lm_next;
804*7c478bd9Sstevel@tonic-gate 		if ( chainprev == NULL ) {
805*7c478bd9Sstevel@tonic-gate 			if ( prev == NULL ) {
806*7c478bd9Sstevel@tonic-gate 				ld->ld_responses = new;
807*7c478bd9Sstevel@tonic-gate 			} else {
808*7c478bd9Sstevel@tonic-gate 				prev->lm_next = new;
809*7c478bd9Sstevel@tonic-gate 			}
810*7c478bd9Sstevel@tonic-gate 		} else {
811*7c478bd9Sstevel@tonic-gate 		    chainprev->lm_chain = new;
812*7c478bd9Sstevel@tonic-gate 		}
813*7c478bd9Sstevel@tonic-gate 		if ( l == tmp ) {
814*7c478bd9Sstevel@tonic-gate 			l = new;
815*7c478bd9Sstevel@tonic-gate 		}
816*7c478bd9Sstevel@tonic-gate 		ldap_msgfree( tmp );
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 	} else if ( manufactured_result && tmp->lm_chain != NULL
819*7c478bd9Sstevel@tonic-gate 	    && tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
820*7c478bd9Sstevel@tonic-gate 		/*
821*7c478bd9Sstevel@tonic-gate 		 * entries or references are also present, so the result
822*7c478bd9Sstevel@tonic-gate 		 * is the next entry after tmp.  replace it.
823*7c478bd9Sstevel@tonic-gate 		 */
824*7c478bd9Sstevel@tonic-gate 		new->lm_chain = tmp->lm_chain->lm_chain;
825*7c478bd9Sstevel@tonic-gate 		new->lm_next = tmp->lm_chain->lm_next;
826*7c478bd9Sstevel@tonic-gate 		ldap_msgfree( tmp->lm_chain );
827*7c478bd9Sstevel@tonic-gate 		tmp->lm_chain = new;
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	} else if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
830*7c478bd9Sstevel@tonic-gate 		/*
831*7c478bd9Sstevel@tonic-gate 		 * the result is the only thing in the chain... add before it.
832*7c478bd9Sstevel@tonic-gate 		 */
833*7c478bd9Sstevel@tonic-gate 		new->lm_chain = tmp;
834*7c478bd9Sstevel@tonic-gate 		if ( chainprev == NULL ) {
835*7c478bd9Sstevel@tonic-gate 			if ( prev == NULL ) {
836*7c478bd9Sstevel@tonic-gate 				ld->ld_responses = new;
837*7c478bd9Sstevel@tonic-gate 			} else {
838*7c478bd9Sstevel@tonic-gate 				prev->lm_next = new;
839*7c478bd9Sstevel@tonic-gate 			}
840*7c478bd9Sstevel@tonic-gate 		} else {
841*7c478bd9Sstevel@tonic-gate 		    chainprev->lm_chain = new;
842*7c478bd9Sstevel@tonic-gate 		}
843*7c478bd9Sstevel@tonic-gate 		if ( l == tmp ) {
844*7c478bd9Sstevel@tonic-gate 			l = new;
845*7c478bd9Sstevel@tonic-gate 		}
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	} else {
848*7c478bd9Sstevel@tonic-gate 		/*
849*7c478bd9Sstevel@tonic-gate 		 * entries and/or references are present... add to the end
850*7c478bd9Sstevel@tonic-gate 		 * of the entry/reference part of the chain.
851*7c478bd9Sstevel@tonic-gate 		 */
852*7c478bd9Sstevel@tonic-gate 		new->lm_chain = tmp->lm_chain;
853*7c478bd9Sstevel@tonic-gate 		tmp->lm_chain = new;
854*7c478bd9Sstevel@tonic-gate 	}
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 	/*
857*7c478bd9Sstevel@tonic-gate 	 * return the first response or the whole chain if that's what
858*7c478bd9Sstevel@tonic-gate 	 * we were looking for....
859*7c478bd9Sstevel@tonic-gate 	 */
860*7c478bd9Sstevel@tonic-gate 	if ( foundit ) {
861*7c478bd9Sstevel@tonic-gate 		if ( all == 0 && l->lm_chain != NULL ) {
862*7c478bd9Sstevel@tonic-gate 			/*
863*7c478bd9Sstevel@tonic-gate 			 * only return the first response in the chain
864*7c478bd9Sstevel@tonic-gate 			 */
865*7c478bd9Sstevel@tonic-gate 			if ( prev == NULL ) {
866*7c478bd9Sstevel@tonic-gate 				ld->ld_responses = l->lm_chain;
867*7c478bd9Sstevel@tonic-gate 			} else {
868*7c478bd9Sstevel@tonic-gate 				prev->lm_next = l->lm_chain;
869*7c478bd9Sstevel@tonic-gate 			}
870*7c478bd9Sstevel@tonic-gate 			l->lm_chain = NULL;
871*7c478bd9Sstevel@tonic-gate 			tag = l->lm_msgtype;
872*7c478bd9Sstevel@tonic-gate 		} else {
873*7c478bd9Sstevel@tonic-gate 			/*
874*7c478bd9Sstevel@tonic-gate 			 * return all of the responses (may be a chain)
875*7c478bd9Sstevel@tonic-gate 			 */
876*7c478bd9Sstevel@tonic-gate 			if ( prev == NULL ) {
877*7c478bd9Sstevel@tonic-gate 				ld->ld_responses = l->lm_next;
878*7c478bd9Sstevel@tonic-gate 			} else {
879*7c478bd9Sstevel@tonic-gate 				prev->lm_next = l->lm_next;
880*7c478bd9Sstevel@tonic-gate 			}
881*7c478bd9Sstevel@tonic-gate 		}
882*7c478bd9Sstevel@tonic-gate 		*result = l;
883*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
884*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
885*7c478bd9Sstevel@tonic-gate 		return( tag );
886*7c478bd9Sstevel@tonic-gate 	}
887*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
888*7c478bd9Sstevel@tonic-gate 	return( -2 );	/* continue looking */
889*7c478bd9Sstevel@tonic-gate }
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate /*
893*7c478bd9Sstevel@tonic-gate  * check for LDAPv2+ (UMich extension) or LDAPv3 referrals or references
894*7c478bd9Sstevel@tonic-gate  * errors are merged in "lr".
895*7c478bd9Sstevel@tonic-gate  */
896*7c478bd9Sstevel@tonic-gate static void
897*7c478bd9Sstevel@tonic-gate check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
898*7c478bd9Sstevel@tonic-gate     int ldapversion, int *totalcountp, int *chasingcountp )
899*7c478bd9Sstevel@tonic-gate {
900*7c478bd9Sstevel@tonic-gate 	int		err, origerr;
901*7c478bd9Sstevel@tonic-gate 	char		*errstr, *matcheddn, **v3refs;
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "check_for_refs\n", 0, 0, 0 );
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	*chasingcountp = *totalcountp = 0;
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 	if ( ldapversion < LDAP_VERSION2 || ( lr->lr_parent == NULL
908*7c478bd9Sstevel@tonic-gate 	    && ( ld->ld_options & LDAP_BITOPT_REFERRALS ) == 0 )) {
909*7c478bd9Sstevel@tonic-gate 		/* referrals are not supported or are disabled */
910*7c478bd9Sstevel@tonic-gate 		return;
911*7c478bd9Sstevel@tonic-gate 	}
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 	if ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
914*7c478bd9Sstevel@tonic-gate 		err = nsldapi_parse_reference( ld, ber, &v3refs, NULL );
915*7c478bd9Sstevel@tonic-gate 		origerr = LDAP_REFERRAL;	/* a small lie... */
916*7c478bd9Sstevel@tonic-gate 		matcheddn = errstr = NULL;
917*7c478bd9Sstevel@tonic-gate 	} else {
918*7c478bd9Sstevel@tonic-gate 		err = nsldapi_parse_result( ld, lr->lr_res_msgtype, ber,
919*7c478bd9Sstevel@tonic-gate 		    &origerr, &matcheddn, &errstr, &v3refs, NULL );
920*7c478bd9Sstevel@tonic-gate 	}
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	if ( err != LDAP_SUCCESS ) {
923*7c478bd9Sstevel@tonic-gate 		/* parse failed */
924*7c478bd9Sstevel@tonic-gate 		return;
925*7c478bd9Sstevel@tonic-gate 	}
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate 	if ( origerr == LDAP_REFERRAL ) {	/* ldapv3 */
928*7c478bd9Sstevel@tonic-gate 		if ( v3refs != NULL ) {
929*7c478bd9Sstevel@tonic-gate 			err = nsldapi_chase_v3_refs( ld, lr, v3refs,
930*7c478bd9Sstevel@tonic-gate 			    ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ),
931*7c478bd9Sstevel@tonic-gate 			    totalcountp, chasingcountp );
932*7c478bd9Sstevel@tonic-gate 			ldap_value_free( v3refs );
933*7c478bd9Sstevel@tonic-gate 		}
934*7c478bd9Sstevel@tonic-gate 	} else if ( ldapversion == LDAP_VERSION2
935*7c478bd9Sstevel@tonic-gate 	    && origerr != LDAP_SUCCESS ) {
936*7c478bd9Sstevel@tonic-gate 		/* referrals may be present in the error string */
937*7c478bd9Sstevel@tonic-gate 		err = nsldapi_chase_v2_referrals( ld, lr, &errstr,
938*7c478bd9Sstevel@tonic-gate 		    totalcountp, chasingcountp );
939*7c478bd9Sstevel@tonic-gate 	}
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 	/* set LDAP errno, message, and matched string appropriately */
942*7c478bd9Sstevel@tonic-gate 	if ( lr->lr_res_error != NULL ) {
943*7c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( lr->lr_res_error );
944*7c478bd9Sstevel@tonic-gate 	}
945*7c478bd9Sstevel@tonic-gate 	lr->lr_res_error = errstr;
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	if ( lr->lr_res_matched != NULL ) {
948*7c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( lr->lr_res_matched );
949*7c478bd9Sstevel@tonic-gate 	}
950*7c478bd9Sstevel@tonic-gate 	lr->lr_res_matched = matcheddn;
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate 	if ( err == LDAP_SUCCESS && ( *chasingcountp == *totalcountp )) {
953*7c478bd9Sstevel@tonic-gate 		if ( *totalcountp > 0 && ( origerr == LDAP_PARTIAL_RESULTS
954*7c478bd9Sstevel@tonic-gate 		    || origerr == LDAP_REFERRAL )) {
955*7c478bd9Sstevel@tonic-gate 			/* substitute success for referral error codes */
956*7c478bd9Sstevel@tonic-gate 			lr->lr_res_errno = LDAP_SUCCESS;
957*7c478bd9Sstevel@tonic-gate 		} else {
958*7c478bd9Sstevel@tonic-gate 			/* preserve existing non-referral error code */
959*7c478bd9Sstevel@tonic-gate 			lr->lr_res_errno = origerr;
960*7c478bd9Sstevel@tonic-gate 		}
961*7c478bd9Sstevel@tonic-gate 	} else if ( err != LDAP_SUCCESS ) {
962*7c478bd9Sstevel@tonic-gate 		/* error occurred while trying to chase referrals */
963*7c478bd9Sstevel@tonic-gate 		lr->lr_res_errno = err;
964*7c478bd9Sstevel@tonic-gate 	} else {
965*7c478bd9Sstevel@tonic-gate 		/* some referrals were not recognized */
966*7c478bd9Sstevel@tonic-gate 		lr->lr_res_errno = ( ldapversion == LDAP_VERSION2 )
967*7c478bd9Sstevel@tonic-gate 		    ? LDAP_PARTIAL_RESULTS : LDAP_REFERRAL;
968*7c478bd9Sstevel@tonic-gate 	}
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
971*7c478bd9Sstevel@tonic-gate 	    "check_for_refs: new result: msgid %d, res_errno %d, ",
972*7c478bd9Sstevel@tonic-gate 	    lr->lr_msgid, lr->lr_res_errno, 0 );
973*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, " res_error <%s>, res_matched <%s>\n",
974*7c478bd9Sstevel@tonic-gate 	    lr->lr_res_error ? lr->lr_res_error : "",
975*7c478bd9Sstevel@tonic-gate 	    lr->lr_res_matched ? lr->lr_res_matched : "", 0 );
976*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
977*7c478bd9Sstevel@tonic-gate 	    "check_for_refs: %d new refs(s); chasing %d of them\n",
978*7c478bd9Sstevel@tonic-gate 	    *totalcountp, *chasingcountp, 0 );
979*7c478bd9Sstevel@tonic-gate }
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate /* returns an LDAP error code and also sets it in LDAP * */
983*7c478bd9Sstevel@tonic-gate static int
984*7c478bd9Sstevel@tonic-gate build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr )
985*7c478bd9Sstevel@tonic-gate {
986*7c478bd9Sstevel@tonic-gate 	ber_len_t	len;
987*7c478bd9Sstevel@tonic-gate 	ber_int_t	along;
988*7c478bd9Sstevel@tonic-gate 	BerElement	*ber;
989*7c478bd9Sstevel@tonic-gate 	int		err;
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 	if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
992*7c478bd9Sstevel@tonic-gate 	    != LDAP_SUCCESS ) {
993*7c478bd9Sstevel@tonic-gate 		return( err );
994*7c478bd9Sstevel@tonic-gate 	}
995*7c478bd9Sstevel@tonic-gate 	*berp = ber;
996*7c478bd9Sstevel@tonic-gate 	if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
997*7c478bd9Sstevel@tonic-gate 	    (long)lr->lr_res_msgtype, lr->lr_res_errno,
998*7c478bd9Sstevel@tonic-gate 	    lr->lr_res_matched ? lr->lr_res_matched : "",
999*7c478bd9Sstevel@tonic-gate 	    lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {
1000*7c478bd9Sstevel@tonic-gate 		return( LDAP_ENCODING_ERROR );
1001*7c478bd9Sstevel@tonic-gate 	}
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 	ber_reset( ber, 1 );
1004*7c478bd9Sstevel@tonic-gate 	if ( ber_skip_tag( ber, &len ) == LBER_ERROR ||
1005*7c478bd9Sstevel@tonic-gate 	    ber_get_int( ber, &along ) == LBER_ERROR ||
1006*7c478bd9Sstevel@tonic-gate 	    ber_peek_tag( ber, &len ) == LBER_ERROR ) {
1007*7c478bd9Sstevel@tonic-gate 		return( LDAP_DECODING_ERROR );
1008*7c478bd9Sstevel@tonic-gate 	}
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
1011*7c478bd9Sstevel@tonic-gate }
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate static void
1015*7c478bd9Sstevel@tonic-gate merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
1016*7c478bd9Sstevel@tonic-gate {
1017*7c478bd9Sstevel@tonic-gate /*
1018*7c478bd9Sstevel@tonic-gate  * Merge error information in "lr" with "parentr" error code and string.
1019*7c478bd9Sstevel@tonic-gate  */
1020*7c478bd9Sstevel@tonic-gate 	if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
1021*7c478bd9Sstevel@tonic-gate 		parentr->lr_res_errno = lr->lr_res_errno;
1022*7c478bd9Sstevel@tonic-gate 		if ( lr->lr_res_error != NULL ) {
1023*7c478bd9Sstevel@tonic-gate 			(void)nsldapi_append_referral( ld, &parentr->lr_res_error,
1024*7c478bd9Sstevel@tonic-gate 			    lr->lr_res_error );
1025*7c478bd9Sstevel@tonic-gate 		}
1026*7c478bd9Sstevel@tonic-gate 	} else if ( lr->lr_res_errno != LDAP_SUCCESS &&
1027*7c478bd9Sstevel@tonic-gate 	    parentr->lr_res_errno == LDAP_SUCCESS ) {
1028*7c478bd9Sstevel@tonic-gate 		parentr->lr_res_errno = lr->lr_res_errno;
1029*7c478bd9Sstevel@tonic-gate 		if ( parentr->lr_res_error != NULL ) {
1030*7c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE( parentr->lr_res_error );
1031*7c478bd9Sstevel@tonic-gate 		}
1032*7c478bd9Sstevel@tonic-gate 		parentr->lr_res_error = lr->lr_res_error;
1033*7c478bd9Sstevel@tonic-gate 		lr->lr_res_error = NULL;
1034*7c478bd9Sstevel@tonic-gate 		if ( NAME_ERROR( lr->lr_res_errno )) {
1035*7c478bd9Sstevel@tonic-gate 			if ( parentr->lr_res_matched != NULL ) {
1036*7c478bd9Sstevel@tonic-gate 				NSLDAPI_FREE( parentr->lr_res_matched );
1037*7c478bd9Sstevel@tonic-gate 			}
1038*7c478bd9Sstevel@tonic-gate 			parentr->lr_res_matched = lr->lr_res_matched;
1039*7c478bd9Sstevel@tonic-gate 			lr->lr_res_matched = NULL;
1040*7c478bd9Sstevel@tonic-gate 		}
1041*7c478bd9Sstevel@tonic-gate 	}
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
1044*7c478bd9Sstevel@tonic-gate 	    parentr->lr_msgid, 0, 0 );
1045*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "result lderrno %d, error <%s>, matched <%s>\n",
1046*7c478bd9Sstevel@tonic-gate 	    parentr->lr_res_errno, parentr->lr_res_error ?
1047*7c478bd9Sstevel@tonic-gate 	    parentr->lr_res_error : "", parentr->lr_res_matched ?
1048*7c478bd9Sstevel@tonic-gate 	    parentr->lr_res_matched : "" );
1049*7c478bd9Sstevel@tonic-gate }
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate #if defined( CLDAP )
1052*7c478bd9Sstevel@tonic-gate #if !defined( macintosh ) && !defined( DOS ) && !defined( _WINDOWS ) && !defined(XP_OS2)
1053*7c478bd9Sstevel@tonic-gate /* XXXmcs: was revised to support extended I/O callbacks but never compiled! */
1054*7c478bd9Sstevel@tonic-gate static int
1055*7c478bd9Sstevel@tonic-gate cldap_select1( LDAP *ld, struct timeval *timeout )
1056*7c478bd9Sstevel@tonic-gate {
1057*7c478bd9Sstevel@tonic-gate 	int		rc;
1058*7c478bd9Sstevel@tonic-gate 	static int	tblsize = 0;
1059*7c478bd9Sstevel@tonic-gate 	NSLDAPIIOStatus	*iosp = ld->ld_iostatus;
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	if ( tblsize == 0 ) {
1062*7c478bd9Sstevel@tonic-gate #ifdef USE_SYSCONF
1063*7c478bd9Sstevel@tonic-gate 		tblsize = sysconf( _SC_OPEN_MAX );
1064*7c478bd9Sstevel@tonic-gate #else /* USE_SYSCONF */
1065*7c478bd9Sstevel@tonic-gate 		tblsize = getdtablesize();
1066*7c478bd9Sstevel@tonic-gate #endif /* USE_SYSCONF */
1067*7c478bd9Sstevel@tonic-gate 	}
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	if ( tblsize >= FD_SETSIZE ) {
1070*7c478bd9Sstevel@tonic-gate 		/*
1071*7c478bd9Sstevel@tonic-gate 		 * clamp value so we don't overrun the fd_set structure
1072*7c478bd9Sstevel@tonic-gate 		 */
1073*7c478bd9Sstevel@tonic-gate 		tblsize = FD_SETSIZE - 1;
1074*7c478bd9Sstevel@tonic-gate 	}
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate 	if ( NSLDAPI_IOSTATUS_TYPE_OSNATIVE == iosp->ios_type ) {
1077*7c478bd9Sstevel@tonic-gate 		fd_set		readfds;
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 		FD_ZERO( &readfds );
1080*7c478bd9Sstevel@tonic-gate 		FD_SET( ld->ld_sbp->sb_sd, &readfds );
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 		/* XXXmcs: UNIX platforms should use poll() */
1083*7c478bd9Sstevel@tonic-gate 		rc = select( tblsize, &readfds, 0, 0, timeout ) );
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	} else if ( NSLDAPI_IOSTATUS_TYPE_CALLBACK == iosp->ios_type ) {
1086*7c478bd9Sstevel@tonic-gate 		LDAP_X_PollFD	pollfds[ 1 ];
1087*7c478bd9Sstevel@tonic-gate 
1088*7c478bd9Sstevel@tonic-gate 		pollfds[0].lpoll_fd = ld->ld_sbp->sb_sd;
1089*7c478bd9Sstevel@tonic-gate 		pollfds[0].lpoll_arg = ld->ld_sbp->sb_arg;
1090*7c478bd9Sstevel@tonic-gate 		pollfds[0].lpoll_events = LDAP_X_POLLIN;
1091*7c478bd9Sstevel@tonic-gate 		pollfds[0].lpoll_revents = 0;
1092*7c478bd9Sstevel@tonic-gate 		rc = ld->ld_extpoll_fn( pollfds, 1, nsldapi_tv2ms( timeout ),
1093*7c478bd9Sstevel@tonic-gate 		    ld->ld_ext_session_arg );
1094*7c478bd9Sstevel@tonic-gate 	} else {
1095*7c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_ANY,
1096*7c478bd9Sstevel@tonic-gate 		    "nsldapi_iostatus_poll: unknown I/O type %d\n",
1097*7c478bd9Sstevel@tonic-gate 		rc = 0; /* simulate a timeout (what else to do?) */
1098*7c478bd9Sstevel@tonic-gate 	}
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate 	return( rc );
1101*7c478bd9Sstevel@tonic-gate }
1102*7c478bd9Sstevel@tonic-gate #endif /* !macintosh */
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate #ifdef macintosh
1106*7c478bd9Sstevel@tonic-gate static int
1107*7c478bd9Sstevel@tonic-gate cldap_select1( LDAP *ld, struct timeval *timeout )
1108*7c478bd9Sstevel@tonic-gate {
1109*7c478bd9Sstevel@tonic-gate 	/* XXXmcs: needs to be revised to support I/O callbacks */
1110*7c478bd9Sstevel@tonic-gate 	return( tcpselect( ld->ld_sbp->sb_sd, timeout ));
1111*7c478bd9Sstevel@tonic-gate }
1112*7c478bd9Sstevel@tonic-gate #endif /* macintosh */
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate #if (defined( DOS ) && defined( WINSOCK )) || defined( _WINDOWS ) || defined(XP_OS2)
1116*7c478bd9Sstevel@tonic-gate /* XXXmcs: needs to be revised to support extended I/O callbacks */
1117*7c478bd9Sstevel@tonic-gate static int
1118*7c478bd9Sstevel@tonic-gate cldap_select1( LDAP *ld, struct timeval *timeout )
1119*7c478bd9Sstevel@tonic-gate {
1120*7c478bd9Sstevel@tonic-gate     fd_set          readfds;
1121*7c478bd9Sstevel@tonic-gate     int             rc;
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate     FD_ZERO( &readfds );
1124*7c478bd9Sstevel@tonic-gate     FD_SET( ld->ld_sbp->sb_sd, &readfds );
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate     if ( NSLDAPI_IO_TYPE_STANDARD == ld->ldiou_type &&
1127*7c478bd9Sstevel@tonic-gate 	NULL != ld->ld_select_fn ) {
1128*7c478bd9Sstevel@tonic-gate 	    rc = ld->ld_select_fn( 1, &readfds, 0, 0, timeout );
1129*7c478bd9Sstevel@tonic-gate     } else if ( NSLDAPI_IO_TYPE_EXTENDED == ld->ldiou_type &&
1130*7c478bd9Sstevel@tonic-gate 	NULL != ld->ld_extselect_fn ) {
1131*7c478bd9Sstevel@tonic-gate 	    rc = ld->ld_extselect_fn( ld->ld_ext_session_arg, 1, &readfds, 0,
1132*7c478bd9Sstevel@tonic-gate 		0, timeout ) );
1133*7c478bd9Sstevel@tonic-gate     } else {
1134*7c478bd9Sstevel@tonic-gate 	    /* XXXmcs: UNIX platforms should use poll() */
1135*7c478bd9Sstevel@tonic-gate 	    rc = select( 1, &readfds, 0, 0, timeout ) );
1136*7c478bd9Sstevel@tonic-gate     }
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate     return( rc == SOCKET_ERROR ? -1 : rc );
1139*7c478bd9Sstevel@tonic-gate }
1140*7c478bd9Sstevel@tonic-gate #endif /* WINSOCK || _WINDOWS */
1141*7c478bd9Sstevel@tonic-gate #endif /* CLDAP */
1142*7c478bd9Sstevel@tonic-gate 
1143*7c478bd9Sstevel@tonic-gate int
1144*7c478bd9Sstevel@tonic-gate LDAP_CALL
1145*7c478bd9Sstevel@tonic-gate ldap_msgfree( LDAPMessage *lm )
1146*7c478bd9Sstevel@tonic-gate {
1147*7c478bd9Sstevel@tonic-gate 	LDAPMessage	*next;
1148*7c478bd9Sstevel@tonic-gate 	int		type = 0;
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate 	for ( ; lm != NULL; lm = next ) {
1153*7c478bd9Sstevel@tonic-gate 		next = lm->lm_chain;
1154*7c478bd9Sstevel@tonic-gate 		type = lm->lm_msgtype;
1155*7c478bd9Sstevel@tonic-gate 		ber_free( lm->lm_ber, 1 );
1156*7c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( (char *) lm );
1157*7c478bd9Sstevel@tonic-gate 	}
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate 	return( type );
1160*7c478bd9Sstevel@tonic-gate }
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate /*
1163*7c478bd9Sstevel@tonic-gate  * ldap_msgdelete - delete a message.  It returns:
1164*7c478bd9Sstevel@tonic-gate  *	0	if the entire message was deleted
1165*7c478bd9Sstevel@tonic-gate  *	-1	if the message was not found, or only part of it was found
1166*7c478bd9Sstevel@tonic-gate  */
1167*7c478bd9Sstevel@tonic-gate int
1168*7c478bd9Sstevel@tonic-gate ldap_msgdelete( LDAP *ld, int msgid )
1169*7c478bd9Sstevel@tonic-gate {
1170*7c478bd9Sstevel@tonic-gate 	LDAPMessage	*lm, *prev;
1171*7c478bd9Sstevel@tonic-gate 	int		msgtype;
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
1174*7c478bd9Sstevel@tonic-gate 
1175*7c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
1176*7c478bd9Sstevel@tonic-gate 		return( -1 );	/* punt */
1177*7c478bd9Sstevel@tonic-gate 	}
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 	prev = NULL;
1180*7c478bd9Sstevel@tonic-gate         LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
1181*7c478bd9Sstevel@tonic-gate 	for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
1182*7c478bd9Sstevel@tonic-gate 		if ( lm->lm_msgid == msgid )
1183*7c478bd9Sstevel@tonic-gate 			break;
1184*7c478bd9Sstevel@tonic-gate 		prev = lm;
1185*7c478bd9Sstevel@tonic-gate 	}
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate 	if ( lm == NULL )
1188*7c478bd9Sstevel@tonic-gate 	{
1189*7c478bd9Sstevel@tonic-gate         	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
1190*7c478bd9Sstevel@tonic-gate 		return( -1 );
1191*7c478bd9Sstevel@tonic-gate 	}
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate 	if ( prev == NULL )
1194*7c478bd9Sstevel@tonic-gate 		ld->ld_responses = lm->lm_next;
1195*7c478bd9Sstevel@tonic-gate 	else
1196*7c478bd9Sstevel@tonic-gate 		prev->lm_next = lm->lm_next;
1197*7c478bd9Sstevel@tonic-gate         LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 	msgtype = ldap_msgfree( lm );
1200*7c478bd9Sstevel@tonic-gate 	if ( msgtype == LDAP_RES_SEARCH_ENTRY
1201*7c478bd9Sstevel@tonic-gate 	    || msgtype == LDAP_RES_SEARCH_REFERENCE ) {
1202*7c478bd9Sstevel@tonic-gate 		return( -1 );
1203*7c478bd9Sstevel@tonic-gate 	}
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate 	return( 0 );
1206*7c478bd9Sstevel@tonic-gate }
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate /*
1210*7c478bd9Sstevel@tonic-gate  * return 1 if message msgid is waiting to be abandoned, 0 otherwise
1211*7c478bd9Sstevel@tonic-gate  */
1212*7c478bd9Sstevel@tonic-gate static int
1213*7c478bd9Sstevel@tonic-gate ldap_abandoned( LDAP *ld, int msgid )
1214*7c478bd9Sstevel@tonic-gate {
1215*7c478bd9Sstevel@tonic-gate 	int	i;
1216*7c478bd9Sstevel@tonic-gate 
1217*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
1218*7c478bd9Sstevel@tonic-gate 	if ( ld->ld_abandoned == NULL )
1219*7c478bd9Sstevel@tonic-gate 	{
1220*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1221*7c478bd9Sstevel@tonic-gate 		return( 0 );
1222*7c478bd9Sstevel@tonic-gate 	}
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
1225*7c478bd9Sstevel@tonic-gate 		if ( ld->ld_abandoned[i] == msgid )
1226*7c478bd9Sstevel@tonic-gate 		{
1227*7c478bd9Sstevel@tonic-gate 			LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1228*7c478bd9Sstevel@tonic-gate 			return( 1 );
1229*7c478bd9Sstevel@tonic-gate 		}
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1232*7c478bd9Sstevel@tonic-gate 	return( 0 );
1233*7c478bd9Sstevel@tonic-gate }
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate static int
1237*7c478bd9Sstevel@tonic-gate ldap_mark_abandoned( LDAP *ld, int msgid )
1238*7c478bd9Sstevel@tonic-gate {
1239*7c478bd9Sstevel@tonic-gate 	int	i;
1240*7c478bd9Sstevel@tonic-gate 
1241*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
1242*7c478bd9Sstevel@tonic-gate 	if ( ld->ld_abandoned == NULL )
1243*7c478bd9Sstevel@tonic-gate 	{
1244*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1245*7c478bd9Sstevel@tonic-gate 		return( -1 );
1246*7c478bd9Sstevel@tonic-gate 	}
1247*7c478bd9Sstevel@tonic-gate 
1248*7c478bd9Sstevel@tonic-gate 	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
1249*7c478bd9Sstevel@tonic-gate 		if ( ld->ld_abandoned[i] == msgid )
1250*7c478bd9Sstevel@tonic-gate 			break;
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	if ( ld->ld_abandoned[i] == -1 )
1253*7c478bd9Sstevel@tonic-gate 	{
1254*7c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1255*7c478bd9Sstevel@tonic-gate 		return( -1 );
1256*7c478bd9Sstevel@tonic-gate 	}
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 	for ( ; ld->ld_abandoned[i] != -1; i++ ) {
1259*7c478bd9Sstevel@tonic-gate 		ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
1260*7c478bd9Sstevel@tonic-gate 	}
1261*7c478bd9Sstevel@tonic-gate 
1262*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1263*7c478bd9Sstevel@tonic-gate 	return( 0 );
1264*7c478bd9Sstevel@tonic-gate }
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate #ifdef CLDAP
1268*7c478bd9Sstevel@tonic-gate int
1269*7c478bd9Sstevel@tonic-gate cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement **ber )
1270*7c478bd9Sstevel@tonic-gate {
1271*7c478bd9Sstevel@tonic-gate 	int		rc;
1272*7c478bd9Sstevel@tonic-gate 	ber_tag_t	tag;
1273*7c478bd9Sstevel@tonic-gate 	ber_len_t	len;
1274*7c478bd9Sstevel@tonic-gate 
1275*7c478bd9Sstevel@tonic-gate 	if ( ld->ld_sbp->sb_ber.ber_ptr >= ld->ld_sbp->sb_ber.ber_end ) {
1276*7c478bd9Sstevel@tonic-gate 		rc = cldap_select1( ld, timeout );
1277*7c478bd9Sstevel@tonic-gate 		if ( rc == -1 || rc == 0 ) {
1278*7c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, (rc == -1 ? LDAP_SERVER_DOWN :
1279*7c478bd9Sstevel@tonic-gate 			    LDAP_TIMEOUT), NULL, NULL );
1280*7c478bd9Sstevel@tonic-gate 			return( rc );
1281*7c478bd9Sstevel@tonic-gate 		}
1282*7c478bd9Sstevel@tonic-gate 	}
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate 	/* get the next message */
1285*7c478bd9Sstevel@tonic-gate 	if ( (tag = ber_get_next( ld->ld_sbp, &len, ber ))
1286*7c478bd9Sstevel@tonic-gate 	    != LDAP_TAG_MESSAGE ) {
1287*7c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
1288*7c478bd9Sstevel@tonic-gate 		    LDAP_LOCAL_ERROR), NULL, NULL );
1289*7c478bd9Sstevel@tonic-gate 		return( -1 );
1290*7c478bd9Sstevel@tonic-gate 	}
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	return( tag );
1293*7c478bd9Sstevel@tonic-gate }
1294*7c478bd9Sstevel@tonic-gate #endif /* CLDAP */
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate int
1297*7c478bd9Sstevel@tonic-gate nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result )
1298*7c478bd9Sstevel@tonic-gate {
1299*7c478bd9Sstevel@tonic-gate 	LDAPPend	*lp;
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
1302*7c478bd9Sstevel@tonic-gate 	    "nsldapi_post_result(ld=0x%x, msgid=%d, result=0x%x)\n",
1303*7c478bd9Sstevel@tonic-gate 	    ld, msgid, result );
1304*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_PEND_LOCK );
1305*7c478bd9Sstevel@tonic-gate 	if( msgid == LDAP_RES_ANY ) {
1306*7c478bd9Sstevel@tonic-gate 		/*
1307*7c478bd9Sstevel@tonic-gate 		 * Look for any pending request for which someone is waiting.
1308*7c478bd9Sstevel@tonic-gate 		 */
1309*7c478bd9Sstevel@tonic-gate 		for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
1310*7c478bd9Sstevel@tonic-gate 		{
1311*7c478bd9Sstevel@tonic-gate 			if ( lp->lp_sema != NULL ) {
1312*7c478bd9Sstevel@tonic-gate 				break;
1313*7c478bd9Sstevel@tonic-gate 			}
1314*7c478bd9Sstevel@tonic-gate 		}
1315*7c478bd9Sstevel@tonic-gate 		/*
1316*7c478bd9Sstevel@tonic-gate 		 * If we did't find a pending request, lp is NULL at this
1317*7c478bd9Sstevel@tonic-gate 		 * point, and we will leave this function without doing
1318*7c478bd9Sstevel@tonic-gate 		 * anything more -- which is exactly what we want to do.
1319*7c478bd9Sstevel@tonic-gate 		 */
1320*7c478bd9Sstevel@tonic-gate 	}
1321*7c478bd9Sstevel@tonic-gate 	else
1322*7c478bd9Sstevel@tonic-gate 	{
1323*7c478bd9Sstevel@tonic-gate 		/*
1324*7c478bd9Sstevel@tonic-gate 		 * Look for a pending request specific to this message id
1325*7c478bd9Sstevel@tonic-gate 		 */
1326*7c478bd9Sstevel@tonic-gate 		for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
1327*7c478bd9Sstevel@tonic-gate 		{
1328*7c478bd9Sstevel@tonic-gate 			if( lp->lp_msgid == msgid )
1329*7c478bd9Sstevel@tonic-gate 				break;
1330*7c478bd9Sstevel@tonic-gate 		}
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 		if( lp == NULL )
1333*7c478bd9Sstevel@tonic-gate 		{
1334*7c478bd9Sstevel@tonic-gate 			/*
1335*7c478bd9Sstevel@tonic-gate 			 * No pending requests for this response... append to
1336*7c478bd9Sstevel@tonic-gate 			 * our pending result list.
1337*7c478bd9Sstevel@tonic-gate 			 */
1338*7c478bd9Sstevel@tonic-gate 			LDAPPend	*newlp;
1339*7c478bd9Sstevel@tonic-gate 			newlp = (LDAPPend *)NSLDAPI_CALLOC( 1,
1340*7c478bd9Sstevel@tonic-gate 			    sizeof( LDAPPend ));
1341*7c478bd9Sstevel@tonic-gate 			if( newlp == NULL )
1342*7c478bd9Sstevel@tonic-gate 			{
1343*7c478bd9Sstevel@tonic-gate 				LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
1344*7c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL,
1345*7c478bd9Sstevel@tonic-gate 				    NULL );
1346*7c478bd9Sstevel@tonic-gate 				return (-1);
1347*7c478bd9Sstevel@tonic-gate 			}
1348*7c478bd9Sstevel@tonic-gate 			newlp->lp_msgid = msgid;
1349*7c478bd9Sstevel@tonic-gate 			newlp->lp_result = result;
1350*7c478bd9Sstevel@tonic-gate 			link_pend( ld, newlp );
1351*7c478bd9Sstevel@tonic-gate 		}
1352*7c478bd9Sstevel@tonic-gate 	}
1353*7c478bd9Sstevel@tonic-gate 
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 	if( lp != NULL )
1356*7c478bd9Sstevel@tonic-gate 	{
1357*7c478bd9Sstevel@tonic-gate 		/*
1358*7c478bd9Sstevel@tonic-gate 		 * Wake up a thread that is waiting for this result.
1359*7c478bd9Sstevel@tonic-gate 		 */
1360*7c478bd9Sstevel@tonic-gate 		lp->lp_msgid = msgid;
1361*7c478bd9Sstevel@tonic-gate 		lp->lp_result = result;
1362*7c478bd9Sstevel@tonic-gate 		LDAP_SEMA_POST( ld, lp );
1363*7c478bd9Sstevel@tonic-gate 	}
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
1366*7c478bd9Sstevel@tonic-gate 	return (0);
1367*7c478bd9Sstevel@tonic-gate }
1368*7c478bd9Sstevel@tonic-gate 
1369*7c478bd9Sstevel@tonic-gate static void
1370*7c478bd9Sstevel@tonic-gate link_pend( LDAP *ld, LDAPPend *lp )
1371*7c478bd9Sstevel@tonic-gate {
1372*7c478bd9Sstevel@tonic-gate 	if (( lp->lp_next = ld->ld_pend ) != NULL )
1373*7c478bd9Sstevel@tonic-gate 	{
1374*7c478bd9Sstevel@tonic-gate 		lp->lp_next->lp_prev = lp;
1375*7c478bd9Sstevel@tonic-gate 	}
1376*7c478bd9Sstevel@tonic-gate 	ld->ld_pend = lp;
1377*7c478bd9Sstevel@tonic-gate 	lp->lp_prev = NULL;
1378*7c478bd9Sstevel@tonic-gate }
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate #if 0 /* these functions are no longer used */
1381*7c478bd9Sstevel@tonic-gate static void
1382*7c478bd9Sstevel@tonic-gate unlink_pend( LDAP *ld, LDAPPend *lp )
1383*7c478bd9Sstevel@tonic-gate {
1384*7c478bd9Sstevel@tonic-gate         if ( lp->lp_prev == NULL ) {
1385*7c478bd9Sstevel@tonic-gate                 ld->ld_pend = lp->lp_next;
1386*7c478bd9Sstevel@tonic-gate         } else {
1387*7c478bd9Sstevel@tonic-gate                 lp->lp_prev->lp_next = lp->lp_next;
1388*7c478bd9Sstevel@tonic-gate         }
1389*7c478bd9Sstevel@tonic-gate 
1390*7c478bd9Sstevel@tonic-gate         if ( lp->lp_next != NULL ) {
1391*7c478bd9Sstevel@tonic-gate                 lp->lp_next->lp_prev = lp->lp_prev;
1392*7c478bd9Sstevel@tonic-gate         }
1393*7c478bd9Sstevel@tonic-gate }
1394*7c478bd9Sstevel@tonic-gate 
1395*7c478bd9Sstevel@tonic-gate static int
1396*7c478bd9Sstevel@tonic-gate unlink_msg( LDAP *ld, int msgid, int all )
1397*7c478bd9Sstevel@tonic-gate {
1398*7c478bd9Sstevel@tonic-gate 	int rc;
1399*7c478bd9Sstevel@tonic-gate 	LDAPMessage	*lm, *lastlm, *nextlm;
1400*7c478bd9Sstevel@tonic-gate 
1401*7c478bd9Sstevel@tonic-gate 	lastlm = NULL;
1402*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
1403*7c478bd9Sstevel@tonic-gate 	for ( lm = ld->ld_responses; lm != NULL; lm = nextlm )
1404*7c478bd9Sstevel@tonic-gate 	{
1405*7c478bd9Sstevel@tonic-gate 		nextlm = lm->lm_next;
1406*7c478bd9Sstevel@tonic-gate 
1407*7c478bd9Sstevel@tonic-gate 		if ( lm->lm_msgid == msgid )
1408*7c478bd9Sstevel@tonic-gate 		{
1409*7c478bd9Sstevel@tonic-gate 			LDAPMessage	*tmp;
1410*7c478bd9Sstevel@tonic-gate 
1411*7c478bd9Sstevel@tonic-gate 			if ( all == 0
1412*7c478bd9Sstevel@tonic-gate 			    || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
1413*7c478bd9Sstevel@tonic-gate 			    && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
1414*7c478bd9Sstevel@tonic-gate 			    && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
1415*7c478bd9Sstevel@tonic-gate 				break;
1416*7c478bd9Sstevel@tonic-gate 
1417*7c478bd9Sstevel@tonic-gate 			for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
1418*7c478bd9Sstevel@tonic-gate 				if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
1419*7c478bd9Sstevel@tonic-gate 					break;
1420*7c478bd9Sstevel@tonic-gate 			}
1421*7c478bd9Sstevel@tonic-gate 			if( tmp != NULL )
1422*7c478bd9Sstevel@tonic-gate 				break;
1423*7c478bd9Sstevel@tonic-gate 		}
1424*7c478bd9Sstevel@tonic-gate 		lastlm = lm;
1425*7c478bd9Sstevel@tonic-gate 	}
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate 	if( lm != NULL )
1428*7c478bd9Sstevel@tonic-gate 	{
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate 		if ( all == 0 )
1431*7c478bd9Sstevel@tonic-gate 		{
1432*7c478bd9Sstevel@tonic-gate 			if ( lm->lm_chain == NULL )
1433*7c478bd9Sstevel@tonic-gate 			{
1434*7c478bd9Sstevel@tonic-gate 				if ( lastlm == NULL )
1435*7c478bd9Sstevel@tonic-gate 					ld->ld_responses = lm->lm_next;
1436*7c478bd9Sstevel@tonic-gate 				else
1437*7c478bd9Sstevel@tonic-gate 					lastlm->lm_next = lm->lm_next;
1438*7c478bd9Sstevel@tonic-gate 			}
1439*7c478bd9Sstevel@tonic-gate 			else
1440*7c478bd9Sstevel@tonic-gate 			{
1441*7c478bd9Sstevel@tonic-gate 				if ( lastlm == NULL )
1442*7c478bd9Sstevel@tonic-gate 				{
1443*7c478bd9Sstevel@tonic-gate 					ld->ld_responses = lm->lm_chain;
1444*7c478bd9Sstevel@tonic-gate 					ld->ld_responses->lm_next = lm->lm_next;
1445*7c478bd9Sstevel@tonic-gate 				}
1446*7c478bd9Sstevel@tonic-gate 				else
1447*7c478bd9Sstevel@tonic-gate 				{
1448*7c478bd9Sstevel@tonic-gate 					lastlm->lm_next = lm->lm_chain;
1449*7c478bd9Sstevel@tonic-gate 					lastlm->lm_next->lm_next = lm->lm_next;
1450*7c478bd9Sstevel@tonic-gate 				}
1451*7c478bd9Sstevel@tonic-gate 			}
1452*7c478bd9Sstevel@tonic-gate 		}
1453*7c478bd9Sstevel@tonic-gate 		else
1454*7c478bd9Sstevel@tonic-gate 		{
1455*7c478bd9Sstevel@tonic-gate 			if ( lastlm == NULL )
1456*7c478bd9Sstevel@tonic-gate 				ld->ld_responses = lm->lm_next;
1457*7c478bd9Sstevel@tonic-gate 			else
1458*7c478bd9Sstevel@tonic-gate 				lastlm->lm_next = lm->lm_next;
1459*7c478bd9Sstevel@tonic-gate 		}
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 		if ( all == 0 )
1462*7c478bd9Sstevel@tonic-gate 			lm->lm_chain = NULL;
1463*7c478bd9Sstevel@tonic-gate 		lm->lm_next = NULL;
1464*7c478bd9Sstevel@tonic-gate 		rc = lm->lm_msgtype;
1465*7c478bd9Sstevel@tonic-gate 	}
1466*7c478bd9Sstevel@tonic-gate 	else
1467*7c478bd9Sstevel@tonic-gate 	{
1468*7c478bd9Sstevel@tonic-gate 		rc = -2;
1469*7c478bd9Sstevel@tonic-gate 	}
1470*7c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
1471*7c478bd9Sstevel@tonic-gate 	return ( rc );
1472*7c478bd9Sstevel@tonic-gate }
1473*7c478bd9Sstevel@tonic-gate #endif /* 0 */
1474