1*0Sstevel@tonic-gate  /*
2*0Sstevel@tonic-gate  *
3*0Sstevel@tonic-gate  * Portions Copyright %G% Sun Microsystems, Inc.
4*0Sstevel@tonic-gate  * All Rights Reserved
5*0Sstevel@tonic-gate  *
6*0Sstevel@tonic-gate  */
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
9*0Sstevel@tonic-gate 
10*0Sstevel@tonic-gate /*
11*0Sstevel@tonic-gate  *  Copyright (c) 1990, 1994 Regents of the University of Michigan.
12*0Sstevel@tonic-gate  *  All rights reserved.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  *  cldap.c - synchronous, retrying interface to the cldap protocol
15*0Sstevel@tonic-gate  */
16*0Sstevel@tonic-gate 
17*0Sstevel@tonic-gate 
18*0Sstevel@tonic-gate #ifdef CLDAP
19*0Sstevel@tonic-gate 
20*0Sstevel@tonic-gate #ifndef lint
21*0Sstevel@tonic-gate static char copyright[] = "@(#) Copyright (c) 1990, 1994 Regents of the University of Michigan.\nAll rights reserved.\n";
22*0Sstevel@tonic-gate #endif
23*0Sstevel@tonic-gate 
24*0Sstevel@tonic-gate #include <stdio.h>
25*0Sstevel@tonic-gate #include <string.h>
26*0Sstevel@tonic-gate #include <errno.h>
27*0Sstevel@tonic-gate #ifdef MACOS
28*0Sstevel@tonic-gate #include <stdlib.h>
29*0Sstevel@tonic-gate #include "macos.h"
30*0Sstevel@tonic-gate #else /* MACOS */
31*0Sstevel@tonic-gate #ifdef DOS
32*0Sstevel@tonic-gate #include "msdos.h"
33*0Sstevel@tonic-gate #else /* DOS */
34*0Sstevel@tonic-gate #include <sys/time.h>
35*0Sstevel@tonic-gate #include <sys/types.h>
36*0Sstevel@tonic-gate #include <sys/socket.h>
37*0Sstevel@tonic-gate #include <netinet/in.h>
38*0Sstevel@tonic-gate #include <netdb.h>
39*0Sstevel@tonic-gate #endif /* DOS */
40*0Sstevel@tonic-gate #endif /* MACOS */
41*0Sstevel@tonic-gate #ifdef SUN
42*0Sstevel@tonic-gate #include <nss_dbdefs.h>
43*0Sstevel@tonic-gate #endif
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include "lber.h"
46*0Sstevel@tonic-gate #include "ldap.h"
47*0Sstevel@tonic-gate #include "ldap-private.h"
48*0Sstevel@tonic-gate #include "ldap-int.h"
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate #define DEF_CLDAP_TIMEOUT	3
51*0Sstevel@tonic-gate #define DEF_CLDAP_TRIES		4
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate #ifndef INADDR_LOOPBACK
54*0Sstevel@tonic-gate #define INADDR_LOOPBACK	((in_addr_t) 0x7f000001)
55*0Sstevel@tonic-gate #endif
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate struct cldap_retinfo {
59*0Sstevel@tonic-gate 	int		cri_maxtries;
60*0Sstevel@tonic-gate 	int		cri_try;
61*0Sstevel@tonic-gate 	int		cri_useaddr;
62*0Sstevel@tonic-gate 	time_t	cri_timeout;
63*0Sstevel@tonic-gate };
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #ifdef NEEDPROTOS
66*0Sstevel@tonic-gate static int add_addr( LDAP *ld, struct sockaddr *sap );
67*0Sstevel@tonic-gate static int cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
68*0Sstevel@tonic-gate 	struct cldap_retinfo *crip, char *base );
69*0Sstevel@tonic-gate static int cldap_parsemsg( LDAP *ld, int msgid, BerElement *ber,
70*0Sstevel@tonic-gate 	LDAPMessage **res, char *base );
71*0Sstevel@tonic-gate #else /* NEEDPROTOS */
72*0Sstevel@tonic-gate static int add_addr();
73*0Sstevel@tonic-gate static int cldap_result();
74*0Sstevel@tonic-gate static int cldap_parsemsg();
75*0Sstevel@tonic-gate #endif /* NEEDPROTOS */
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate /*
78*0Sstevel@tonic-gate  * cldap_open - initialize and connect to an ldap server.  A magic cookie to
79*0Sstevel@tonic-gate  * be used for future communication is returned on success, NULL on failure.
80*0Sstevel@tonic-gate  *
81*0Sstevel@tonic-gate  * Example:
82*0Sstevel@tonic-gate  *	LDAP	*ld;
83*0Sstevel@tonic-gate  *	ld = cldap_open( hostname, port );
84*0Sstevel@tonic-gate  */
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate LDAP *
87*0Sstevel@tonic-gate cldap_open( char *host, int port )
88*0Sstevel@tonic-gate {
89*0Sstevel@tonic-gate     int 		s;
90*0Sstevel@tonic-gate     in_addr_t		address;
91*0Sstevel@tonic-gate     struct sockaddr_in 	sock;
92*0Sstevel@tonic-gate     struct hostent	*hp;
93*0Sstevel@tonic-gate     LDAP		*ld;
94*0Sstevel@tonic-gate     char		*p;
95*0Sstevel@tonic-gate     int		i;
96*0Sstevel@tonic-gate #ifdef SUN
97*0Sstevel@tonic-gate     struct hostent      hpret;
98*0Sstevel@tonic-gate     char                hpbuf[NSS_BUFLEN_HOSTS];
99*0Sstevel@tonic-gate     int                 hperrno;
100*0Sstevel@tonic-gate #endif
101*0Sstevel@tonic-gate     in_addr_t inet_addr(const char *);
102*0Sstevel@tonic-gate     int close(int);
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate     Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 113, "ldap_open\n"), 0, 0, 0 );
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate     if ( port == 0 ) {
107*0Sstevel@tonic-gate 	    port = LDAP_PORT;
108*0Sstevel@tonic-gate     }
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate     if ( (s = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) {
111*0Sstevel@tonic-gate 	return( NULL );
112*0Sstevel@tonic-gate     }
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate     sock.sin_addr.s_addr = 0;
115*0Sstevel@tonic-gate     sock.sin_family = AF_INET;
116*0Sstevel@tonic-gate     sock.sin_port = 0;
117*0Sstevel@tonic-gate     if ( bind(s, (struct sockaddr *) &sock, sizeof(sock)) < 0)  {
118*0Sstevel@tonic-gate 	close( s );
119*0Sstevel@tonic-gate 	return( NULL );
120*0Sstevel@tonic-gate     }
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate     if (( ld = ldap_init( host, port )) == NULL ) {
123*0Sstevel@tonic-gate 	close( s );
124*0Sstevel@tonic-gate 	return( NULL );
125*0Sstevel@tonic-gate     }
126*0Sstevel@tonic-gate     if ( (ld->ld_sb.sb_fromaddr = (void *) calloc( 1,
127*0Sstevel@tonic-gate 	    sizeof( struct sockaddr ))) == NULL ) {
128*0Sstevel@tonic-gate 	free( ld );
129*0Sstevel@tonic-gate 	close( s );
130*0Sstevel@tonic-gate 	return( NULL );
131*0Sstevel@tonic-gate     }
132*0Sstevel@tonic-gate     ld->ld_sb.sb_sd = s;
133*0Sstevel@tonic-gate     ld->ld_sb.sb_naddr = 0;
134*0Sstevel@tonic-gate     ld->ld_version = LDAP_VERSION;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate     sock.sin_family = AF_INET;
137*0Sstevel@tonic-gate     sock.sin_port = htons( port );
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate     /*
140*0Sstevel@tonic-gate      * 'host' may be a space-separated list.
141*0Sstevel@tonic-gate      */
142*0Sstevel@tonic-gate     if ( host != NULL ) {
143*0Sstevel@tonic-gate 	for ( ; host != NULL; host = p ) {
144*0Sstevel@tonic-gate 	    if (( p = strchr( host, ' ' )) != NULL ) {
145*0Sstevel@tonic-gate 		for (*p++ = '\0'; *p == ' '; p++) {
146*0Sstevel@tonic-gate 		    ;
147*0Sstevel@tonic-gate 		}
148*0Sstevel@tonic-gate 	    }
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	    if ( (address = inet_addr( host )) == -1 ) {
151*0Sstevel@tonic-gate #ifdef SUN
152*0Sstevel@tonic-gate 		if ( (hp = gethostbyname_r( host, &hpret, hpbuf, NSS_BUFLEN_HOSTS, &hperrno)) == NULL ) {
153*0Sstevel@tonic-gate 		    errno = EHOSTUNREACH;
154*0Sstevel@tonic-gate 		    continue;
155*0Sstevel@tonic-gate 		}
156*0Sstevel@tonic-gate #else
157*0Sstevel@tonic-gate 		if ( (hp = gethostbyname( host )) == NULL ) {
158*0Sstevel@tonic-gate 		    errno = EHOSTUNREACH;
159*0Sstevel@tonic-gate 		    continue;
160*0Sstevel@tonic-gate 		}
161*0Sstevel@tonic-gate #endif
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 		for ( i = 0; hp->h_addr_list[ i ] != 0; ++i ) {
164*0Sstevel@tonic-gate 		    SAFEMEMCPY( (char *)&sock.sin_addr.s_addr,
165*0Sstevel@tonic-gate 			    (char *)hp->h_addr_list[ i ],
166*0Sstevel@tonic-gate 			    sizeof(sock.sin_addr.s_addr));
167*0Sstevel@tonic-gate 		    if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
168*0Sstevel@tonic-gate 			close( s );
169*0Sstevel@tonic-gate 			free( ld );
170*0Sstevel@tonic-gate 			return( NULL );
171*0Sstevel@tonic-gate 		    }
172*0Sstevel@tonic-gate 		}
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	    } else {
175*0Sstevel@tonic-gate 		sock.sin_addr.s_addr = address;
176*0Sstevel@tonic-gate 		if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
177*0Sstevel@tonic-gate 		    close( s );
178*0Sstevel@tonic-gate 		    free( ld );
179*0Sstevel@tonic-gate 		    return( NULL );
180*0Sstevel@tonic-gate 		}
181*0Sstevel@tonic-gate 	    }
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	    if ( ld->ld_host == NULL ) {
184*0Sstevel@tonic-gate 		    ld->ld_host = strdup( host );
185*0Sstevel@tonic-gate 	    }
186*0Sstevel@tonic-gate 	}
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate     } else {
189*0Sstevel@tonic-gate 	address = INADDR_LOOPBACK;
190*0Sstevel@tonic-gate 	sock.sin_addr.s_addr = htonl( address );
191*0Sstevel@tonic-gate 	if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
192*0Sstevel@tonic-gate 	    close( s );
193*0Sstevel@tonic-gate 	    free( ld );
194*0Sstevel@tonic-gate 	    return( NULL );
195*0Sstevel@tonic-gate 	}
196*0Sstevel@tonic-gate     }
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate     if ( ld->ld_sb.sb_addrs == NULL
199*0Sstevel@tonic-gate #ifdef LDAP_REFERRALS
200*0Sstevel@tonic-gate 	    || ( ld->ld_defconn = new_connection( ld, NULL, 1,0,0 )) == NULL
201*0Sstevel@tonic-gate #endif /* LDAP_REFERRALS */
202*0Sstevel@tonic-gate 	    ) {
203*0Sstevel@tonic-gate 	free( ld );
204*0Sstevel@tonic-gate 	return( NULL );
205*0Sstevel@tonic-gate     }
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate     ld->ld_sb.sb_useaddr = ld->ld_sb.sb_addrs[ 0 ];
208*0Sstevel@tonic-gate     cldap_setretryinfo( ld, 0, 0 );
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate #ifdef LDAP_DEBUG
211*0Sstevel@tonic-gate     putchar( '\n' );
212*0Sstevel@tonic-gate     for ( i = 0; i < ld->ld_sb.sb_naddr; ++i ) {
213*0Sstevel@tonic-gate 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 114, "end of cldap_open address %1$d is %2$s\n"),
214*0Sstevel@tonic-gate 		i, inet_ntoa( ((struct sockaddr_in *)
215*0Sstevel@tonic-gate 		ld->ld_sb.sb_addrs[ i ])->sin_addr ), 0 );
216*0Sstevel@tonic-gate     }
217*0Sstevel@tonic-gate #endif
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate     return( ld );
220*0Sstevel@tonic-gate }
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate void
225*0Sstevel@tonic-gate cldap_close( LDAP *ld )
226*0Sstevel@tonic-gate {
227*0Sstevel@tonic-gate 	ldap_ld_free( ld, 0 );
228*0Sstevel@tonic-gate }
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate void
232*0Sstevel@tonic-gate cldap_setretryinfo( LDAP *ld, int tries, time_t timeout )
233*0Sstevel@tonic-gate {
234*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
235*0Sstevel@tonic-gate     LOCK_LDAP(ld);
236*0Sstevel@tonic-gate #endif
237*0Sstevel@tonic-gate     ld->ld_cldaptries = ( tries <= 0 ) ? DEF_CLDAP_TRIES : tries;
238*0Sstevel@tonic-gate     ld->ld_cldaptimeout = ( timeout <= 0 ) ? DEF_CLDAP_TIMEOUT : timeout;
239*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
240*0Sstevel@tonic-gate     UNLOCK_LDAP(ld);
241*0Sstevel@tonic-gate #endif
242*0Sstevel@tonic-gate }
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate int
246*0Sstevel@tonic-gate cldap_search_s( LDAP *ld, char *base, int scope, char *filter, char **attrs,
247*0Sstevel@tonic-gate 	int attrsonly, LDAPMessage **res, char *logdn )
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate     int				ret, msgid;
250*0Sstevel@tonic-gate     struct cldap_retinfo	cri;
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate     *res = NULLMSG;
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate     (void) memset( &cri, 0, sizeof( cri ));
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
257*0Sstevel@tonic-gate     LOCK_LDAP(ld);
258*0Sstevel@tonic-gate #endif
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate     if ( logdn != NULL ) {
261*0Sstevel@tonic-gate 	ld->ld_cldapdn = logdn;
262*0Sstevel@tonic-gate     } else if ( ld->ld_cldapdn == NULL ) {
263*0Sstevel@tonic-gate 	ld->ld_cldapdn = "";
264*0Sstevel@tonic-gate     }
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate     do {
267*0Sstevel@tonic-gate 	if ( cri.cri_try != 0 ) {
268*0Sstevel@tonic-gate 		--ld->ld_msgid;	/* use same id as before */
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 	ld->ld_sb.sb_useaddr = ld->ld_sb.sb_addrs[ cri.cri_useaddr ];
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 115, "cldap_search_s try %1$d (to %2$s)\n"),
273*0Sstevel@tonic-gate 	    cri.cri_try, inet_ntoa( ((struct sockaddr_in *)
274*0Sstevel@tonic-gate 	    ld->ld_sb.sb_useaddr)->sin_addr ), 0 );
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	    if ( (msgid = ldap_search( ld, base, scope, filter, attrs,
277*0Sstevel@tonic-gate 		attrsonly )) == -1 ) {
278*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
279*0Sstevel@tonic-gate 	            UNLOCK_LDAP(ld);
280*0Sstevel@tonic-gate #endif
281*0Sstevel@tonic-gate 		    return( ld->ld_errno );
282*0Sstevel@tonic-gate 	    }
283*0Sstevel@tonic-gate #ifndef NO_CACHE
284*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
285*0Sstevel@tonic-gate 	    LOCK_RESPONSE(ld);
286*0Sstevel@tonic-gate #endif
287*0Sstevel@tonic-gate 	    if ( ld->ld_cache != NULL && ld->ld_responses != NULL ) {
288*0Sstevel@tonic-gate 		Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 116, "cldap_search_s res from cache\n"),
289*0Sstevel@tonic-gate 			0, 0, 0 );
290*0Sstevel@tonic-gate 		*res = ld->ld_responses;
291*0Sstevel@tonic-gate 		ld->ld_responses = ld->ld_responses->lm_next;
292*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
293*0Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
294*0Sstevel@tonic-gate 		ret = ldap_result2error( ld, *res, 0 );
295*0Sstevel@tonic-gate 		UNLOCK_RESPONSE(ld);
296*0Sstevel@tonic-gate 		return( ret );
297*0Sstevel@tonic-gate #else
298*0Sstevel@tonic-gate 		return( ldap_result2error( ld, *res, 0 ));
299*0Sstevel@tonic-gate #endif
300*0Sstevel@tonic-gate 	    }
301*0Sstevel@tonic-gate #endif /* NO_CACHE */
302*0Sstevel@tonic-gate 	    ret = cldap_result( ld, msgid, res, &cri, base );
303*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
304*0Sstevel@tonic-gate 	    UNLOCK_RESPONSE(ld);
305*0Sstevel@tonic-gate #endif
306*0Sstevel@tonic-gate 	} while (ret == -1);
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	return( ret );
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate static int
313*0Sstevel@tonic-gate add_addr( LDAP *ld, struct sockaddr *sap )
314*0Sstevel@tonic-gate {
315*0Sstevel@tonic-gate     struct sockaddr	*newsap, **addrs;
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate     if (( newsap = (struct sockaddr *)malloc( sizeof( struct sockaddr )))
318*0Sstevel@tonic-gate 	    == NULL ) {
319*0Sstevel@tonic-gate 	ld->ld_errno = LDAP_NO_MEMORY;
320*0Sstevel@tonic-gate 	return( -1 );
321*0Sstevel@tonic-gate     }
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate     if ( ld->ld_sb.sb_naddr == 0 ) {
324*0Sstevel@tonic-gate 	addrs = (struct sockaddr **)malloc( sizeof(struct sockaddr *));
325*0Sstevel@tonic-gate     } else {
326*0Sstevel@tonic-gate 	addrs = (struct sockaddr **)realloc( ld->ld_sb.sb_addrs,
327*0Sstevel@tonic-gate 		( ld->ld_sb.sb_naddr + 1 ) * sizeof(struct sockaddr *));
328*0Sstevel@tonic-gate     }
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate     if ( addrs == NULL ) {
331*0Sstevel@tonic-gate 	free( newsap );
332*0Sstevel@tonic-gate 	ld->ld_errno = LDAP_NO_MEMORY;
333*0Sstevel@tonic-gate 	return( -1 );
334*0Sstevel@tonic-gate     }
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate     SAFEMEMCPY( (char *)newsap, (char *)sap, sizeof( struct sockaddr ));
337*0Sstevel@tonic-gate     addrs[ ld->ld_sb.sb_naddr++ ] = newsap;
338*0Sstevel@tonic-gate     ld->ld_sb.sb_addrs = (void **)addrs;
339*0Sstevel@tonic-gate     return( 0 );
340*0Sstevel@tonic-gate }
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate static int
344*0Sstevel@tonic-gate cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
345*0Sstevel@tonic-gate 	struct cldap_retinfo *crip, char *base )
346*0Sstevel@tonic-gate {
347*0Sstevel@tonic-gate     Sockbuf 		*sb;
348*0Sstevel@tonic-gate     BerElement		ber;
349*0Sstevel@tonic-gate     char		*logdn;
350*0Sstevel@tonic-gate     int			ret, id, fromaddr, i;
351*0Sstevel@tonic-gate     struct timeval	tv;
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
354*0Sstevel@tonic-gate     LOCK_LDAP(ld);
355*0Sstevel@tonic-gate #endif
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate     sb = &ld->ld_sb;
358*0Sstevel@tonic-gate     fromaddr = -1;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate     if ( crip->cri_try == 0 ) {
361*0Sstevel@tonic-gate 	crip->cri_maxtries = ld->ld_cldaptries * sb->sb_naddr;
362*0Sstevel@tonic-gate 	crip->cri_timeout = ld->ld_cldaptimeout;
363*0Sstevel@tonic-gate 	crip->cri_useaddr = 0;
364*0Sstevel@tonic-gate 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 117, "cldap_result tries %1$d timeout %2$d\n"),
365*0Sstevel@tonic-gate 		ld->ld_cldaptries, ld->ld_cldaptimeout, 0 );
366*0Sstevel@tonic-gate     }
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate     if ((tv.tv_sec = crip->cri_timeout / sb->sb_naddr) < 1 ) {
369*0Sstevel@tonic-gate 	tv.tv_sec = 1;
370*0Sstevel@tonic-gate     }
371*0Sstevel@tonic-gate     tv.tv_usec = 0;
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate     Debug( LDAP_DEBUG_TRACE,
374*0Sstevel@tonic-gate 	    catgets(slapdcat, 1, 118, "cldap_result waiting up to %d seconds for a response\n"),
375*0Sstevel@tonic-gate 	    tv.tv_sec, 0, 0 );
376*0Sstevel@tonic-gate     ber_zero_init( &ber, 0 );
377*0Sstevel@tonic-gate     set_ber_options( ld, &ber );
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate     if ( cldap_getmsg( ld, &tv, &ber ) == -1 ) {
380*0Sstevel@tonic-gate 	ret = ld->ld_errno;
381*0Sstevel@tonic-gate 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 119, "cldap_getmsg returned -1 (%d)\n"),
382*0Sstevel@tonic-gate 		ret, 0, 0 );
383*0Sstevel@tonic-gate     } else if ( ld->ld_errno == LDAP_TIMEOUT ) {
384*0Sstevel@tonic-gate 	Debug( LDAP_DEBUG_TRACE,
385*0Sstevel@tonic-gate 	    catgets(slapdcat, 1, 120, "cldap_result timed out\n"), 0, 0, 0 );
386*0Sstevel@tonic-gate 	/*
387*0Sstevel@tonic-gate 	 * It timed out; is it time to give up?
388*0Sstevel@tonic-gate 	 */
389*0Sstevel@tonic-gate 	if ( ++crip->cri_try >= crip->cri_maxtries ) {
390*0Sstevel@tonic-gate 	    ret = LDAP_TIMEOUT;
391*0Sstevel@tonic-gate 	    --crip->cri_try;
392*0Sstevel@tonic-gate 	} else {
393*0Sstevel@tonic-gate 	    if ( ++crip->cri_useaddr >= sb->sb_naddr ) {
394*0Sstevel@tonic-gate 		/*
395*0Sstevel@tonic-gate 		 * new round: reset address to first one and
396*0Sstevel@tonic-gate 		 * double the timeout
397*0Sstevel@tonic-gate 		 */
398*0Sstevel@tonic-gate 		crip->cri_useaddr = 0;
399*0Sstevel@tonic-gate 		crip->cri_timeout <<= 1;
400*0Sstevel@tonic-gate 	    }
401*0Sstevel@tonic-gate 	    ret = -1;
402*0Sstevel@tonic-gate 	}
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate     } else {
405*0Sstevel@tonic-gate 	/*
406*0Sstevel@tonic-gate 	 * Got a response.  It should look like:
407*0Sstevel@tonic-gate 	 * { msgid, logdn, { searchresponse...}}
408*0Sstevel@tonic-gate 	 */
409*0Sstevel@tonic-gate 	logdn = NULL;
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	if ( ber_scanf( &ber, "ia", &id, &logdn ) == LBER_ERROR ) {
412*0Sstevel@tonic-gate 	    free( ber.ber_buf );	/* gack! */
413*0Sstevel@tonic-gate 	    ret = LDAP_DECODING_ERROR;
414*0Sstevel@tonic-gate 	    Debug( LDAP_DEBUG_TRACE,
415*0Sstevel@tonic-gate 		    catgets(slapdcat, 1, 121, "cldap_result: ber_scanf returned LBER_ERROR (%d)\n"),
416*0Sstevel@tonic-gate 		    ret, 0, 0 );
417*0Sstevel@tonic-gate 	} else if ( id != msgid ) {
418*0Sstevel@tonic-gate 	    free( ber.ber_buf );	/* gack! */
419*0Sstevel@tonic-gate 	    Debug( LDAP_DEBUG_TRACE,
420*0Sstevel@tonic-gate 		    catgets(slapdcat, 1, 122, "cldap_result: looking for msgid %1$d; got %2$d\n"),
421*0Sstevel@tonic-gate 		    msgid, id, 0 );
422*0Sstevel@tonic-gate 	    ret = -1;	/* ignore and keep looking */
423*0Sstevel@tonic-gate 	} else {
424*0Sstevel@tonic-gate 	    /*
425*0Sstevel@tonic-gate 	     * got a result: determine which server it came from
426*0Sstevel@tonic-gate 	     * decode into ldap message chain
427*0Sstevel@tonic-gate 	     */
428*0Sstevel@tonic-gate 	    for ( fromaddr = 0; fromaddr < sb->sb_naddr; ++fromaddr ) {
429*0Sstevel@tonic-gate 		    if ( memcmp( &((struct sockaddr_in *)
430*0Sstevel@tonic-gate 			    sb->sb_addrs[ fromaddr ])->sin_addr,
431*0Sstevel@tonic-gate 			    &((struct sockaddr_in *)sb->sb_fromaddr)->sin_addr,
432*0Sstevel@tonic-gate 			    sizeof( struct in_addr )) == 0 ) {
433*0Sstevel@tonic-gate 			break;
434*0Sstevel@tonic-gate 		    }
435*0Sstevel@tonic-gate 	    }
436*0Sstevel@tonic-gate 	    ret = cldap_parsemsg( ld, msgid, &ber, res, base );
437*0Sstevel@tonic-gate 	    free( ber.ber_buf );	/* gack! */
438*0Sstevel@tonic-gate 	    Debug( LDAP_DEBUG_TRACE,
439*0Sstevel@tonic-gate 		catgets(slapdcat, 1, 123, "cldap_result got result (%d)\n"), ret, 0, 0 );
440*0Sstevel@tonic-gate 	}
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	if ( logdn != NULL ) {
443*0Sstevel@tonic-gate 		free( logdn );
444*0Sstevel@tonic-gate 	}
445*0Sstevel@tonic-gate     }
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate     /*
449*0Sstevel@tonic-gate      * If we are giving up (successfully or otherwise) then
450*0Sstevel@tonic-gate      * abandon any outstanding requests.
451*0Sstevel@tonic-gate      */
452*0Sstevel@tonic-gate     if ( ret != -1 ) {
453*0Sstevel@tonic-gate 	i = crip->cri_try;
454*0Sstevel@tonic-gate 	if ( i >= sb->sb_naddr ) {
455*0Sstevel@tonic-gate 	    i = sb->sb_naddr - 1;
456*0Sstevel@tonic-gate 	}
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	for ( ; i >= 0; --i ) {
459*0Sstevel@tonic-gate 	    if ( i == fromaddr ) {
460*0Sstevel@tonic-gate 		continue;
461*0Sstevel@tonic-gate 	    }
462*0Sstevel@tonic-gate 	    sb->sb_useaddr = sb->sb_addrs[ i ];
463*0Sstevel@tonic-gate 	    Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 124, "cldap_result abandoning id %1$d (to %2$s)\n"),
464*0Sstevel@tonic-gate 		msgid, inet_ntoa( ((struct sockaddr_in *)
465*0Sstevel@tonic-gate 		sb->sb_useaddr)->sin_addr ), 0 );
466*0Sstevel@tonic-gate 	    (void) ldap_abandon( ld, msgid );
467*0Sstevel@tonic-gate 	}
468*0Sstevel@tonic-gate     }
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
471*0Sstevel@tonic-gate     UNLOCK_LDAP(ld);
472*0Sstevel@tonic-gate #endif
473*0Sstevel@tonic-gate     return( ld->ld_errno = ret );
474*0Sstevel@tonic-gate }
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate static int
478*0Sstevel@tonic-gate cldap_parsemsg( LDAP *ld, int msgid, BerElement *ber,
479*0Sstevel@tonic-gate 	LDAPMessage **res, char *base )
480*0Sstevel@tonic-gate {
481*0Sstevel@tonic-gate     unsigned int	tag, len;
482*0Sstevel@tonic-gate     int		      rc;
483*0Sstevel@tonic-gate     size_t        baselen, slen;
484*0Sstevel@tonic-gate     char		      *dn, *p, *cookie;
485*0Sstevel@tonic-gate     LDAPMessage	*chain, *prev, *ldm;
486*0Sstevel@tonic-gate     struct berval	*bv;
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate     rc = LDAP_DECODING_ERROR;	/* pessimistic */
489*0Sstevel@tonic-gate     ldm = chain = prev = NULLMSG;
490*0Sstevel@tonic-gate     baselen = ( base == NULL ) ? 0 : strlen( base );
491*0Sstevel@tonic-gate     bv = NULL;
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate     for ( tag = ber_first_element( ber, &len, &cookie );
494*0Sstevel@tonic-gate 	    tag != LBER_DEFAULT && rc != LDAP_SUCCESS;
495*0Sstevel@tonic-gate 	    tag = ber_next_element( ber, &len, cookie )) {
496*0Sstevel@tonic-gate 	if (( ldm = (LDAPMessage *)calloc( 1, sizeof(LDAPMessage)))
497*0Sstevel@tonic-gate 		== NULL || ( ldm->lm_ber = alloc_ber_with_options( ld ))
498*0Sstevel@tonic-gate 		== NULLBER ) {
499*0Sstevel@tonic-gate 	    rc = LDAP_NO_MEMORY;
500*0Sstevel@tonic-gate 	    break;	/* return w/error*/
501*0Sstevel@tonic-gate 	}
502*0Sstevel@tonic-gate 	ldm->lm_msgid = msgid;
503*0Sstevel@tonic-gate 	ldm->lm_msgtype = tag;
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	if ( tag == LDAP_RES_SEARCH_RESULT ) {
506*0Sstevel@tonic-gate 	    Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 125, "cldap_parsemsg got search result\n"),
507*0Sstevel@tonic-gate 		    0, 0, 0 );
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	    if ( ber_get_stringal( ber, &bv ) == LBER_DEFAULT ) {
510*0Sstevel@tonic-gate 		break;	/* return w/error */
511*0Sstevel@tonic-gate 	    }
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 	    if ( ber_printf( ldm->lm_ber, "to", tag, bv->bv_val,
514*0Sstevel@tonic-gate 		    bv->bv_len ) == -1 ) {
515*0Sstevel@tonic-gate 		break;	/* return w/error */
516*0Sstevel@tonic-gate 	    }
517*0Sstevel@tonic-gate 	    ber_bvfree( bv );
518*0Sstevel@tonic-gate 	    bv = NULL;
519*0Sstevel@tonic-gate 	    rc = LDAP_SUCCESS;
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 	} else if ( tag == LDAP_RES_SEARCH_ENTRY ) {
522*0Sstevel@tonic-gate 	    if ( ber_scanf( ber, "{aO", &dn, &bv ) == LBER_ERROR ) {
523*0Sstevel@tonic-gate 		break;	/* return w/error */
524*0Sstevel@tonic-gate 	    }
525*0Sstevel@tonic-gate 	    Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 126, "cldap_parsemsg entry %s\n"), dn, 0, 0 );
526*0Sstevel@tonic-gate 	    if ( dn != NULL && *(dn + ( slen = strlen(dn)) - 1) == '*' &&
527*0Sstevel@tonic-gate 		    baselen > 0 ) {
528*0Sstevel@tonic-gate 		/*
529*0Sstevel@tonic-gate 		 * substitute original searchbase for trailing '*'
530*0Sstevel@tonic-gate 		 */
531*0Sstevel@tonic-gate 		if (( p = (char *)malloc( slen + baselen )) == NULL ) {
532*0Sstevel@tonic-gate 		    rc = LDAP_NO_MEMORY;
533*0Sstevel@tonic-gate 		    free( dn );
534*0Sstevel@tonic-gate 		    break;	/* return w/error */
535*0Sstevel@tonic-gate 		}
536*0Sstevel@tonic-gate 		strcpy( p, dn );
537*0Sstevel@tonic-gate 		strcpy( p + slen - 1, base );
538*0Sstevel@tonic-gate 		free( dn );
539*0Sstevel@tonic-gate 		dn = p;
540*0Sstevel@tonic-gate 	    }
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	    if ( ber_printf( ldm->lm_ber, "t{so}", tag, dn, bv->bv_val,
543*0Sstevel@tonic-gate 		    bv->bv_len ) == -1 ) {
544*0Sstevel@tonic-gate 		break;	/* return w/error */
545*0Sstevel@tonic-gate 	    }
546*0Sstevel@tonic-gate 	    free( dn );
547*0Sstevel@tonic-gate 	    ber_bvfree( bv );
548*0Sstevel@tonic-gate 	    bv = NULL;
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate 	} else {
551*0Sstevel@tonic-gate 	    Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 127, "cldap_parsemsg got unknown tag %d\n"),
552*0Sstevel@tonic-gate 		    tag, 0, 0 );
553*0Sstevel@tonic-gate 	    rc = LDAP_PROTOCOL_ERROR;
554*0Sstevel@tonic-gate 	    break;	/* return w/error */
555*0Sstevel@tonic-gate 	}
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 	/* Reset message ber so we can read from it later.  Gack! */
558*0Sstevel@tonic-gate 	ldm->lm_ber->ber_end = ldm->lm_ber->ber_ptr;
559*0Sstevel@tonic-gate 	ldm->lm_ber->ber_ptr = ldm->lm_ber->ber_buf;
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate #ifdef LDAP_DEBUG
562*0Sstevel@tonic-gate 	if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
563*0Sstevel@tonic-gate 	    fprintf( stderr, "cldap_parsemsg add message id %d type %d:\n",
564*0Sstevel@tonic-gate 		    ldm->lm_msgid, ldm->lm_msgtype  );
565*0Sstevel@tonic-gate 	    ber_dump( ldm->lm_ber, 1 );
566*0Sstevel@tonic-gate 	}
567*0Sstevel@tonic-gate #endif /* LDAP_DEBUG */
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate #ifndef NO_CACHE
570*0Sstevel@tonic-gate 	    if ( ld->ld_cache != NULL ) {
571*0Sstevel@tonic-gate 		add_result_to_cache( ld, ldm );
572*0Sstevel@tonic-gate 	    }
573*0Sstevel@tonic-gate #endif /* NO_CACHE */
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	if ( chain == NULL ) {
576*0Sstevel@tonic-gate 	    chain = ldm;
577*0Sstevel@tonic-gate 	} else {
578*0Sstevel@tonic-gate 	    prev->lm_chain = ldm;
579*0Sstevel@tonic-gate 	}
580*0Sstevel@tonic-gate 	prev = ldm;
581*0Sstevel@tonic-gate 	ldm = NULL;
582*0Sstevel@tonic-gate     }
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate     /* dispose of any leftovers */
585*0Sstevel@tonic-gate     if ( ldm != NULL ) {
586*0Sstevel@tonic-gate 	if ( ldm->lm_ber != NULLBER ) {
587*0Sstevel@tonic-gate 	    ber_free( ldm->lm_ber, 1 );
588*0Sstevel@tonic-gate 	}
589*0Sstevel@tonic-gate 	free( ldm );
590*0Sstevel@tonic-gate     }
591*0Sstevel@tonic-gate     if ( bv != NULL ) {
592*0Sstevel@tonic-gate 	ber_bvfree( bv );
593*0Sstevel@tonic-gate     }
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate     /* return chain, calling result2error if we got anything at all */
596*0Sstevel@tonic-gate     *res = chain;
597*0Sstevel@tonic-gate     return(( *res == NULLMSG ) ? rc : ldap_result2error( ld, *res, 0 ));
598*0Sstevel@tonic-gate }
599*0Sstevel@tonic-gate #endif /* CLDAP */
600