1*3857Sstevel /*
2*3857Sstevel * Portions Copyright 1998 Sun Microsystems, Inc. All rights reserved.
3*3857Sstevel * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
70Sstevel@tonic-gate
80Sstevel@tonic-gate /*
90Sstevel@tonic-gate * Copyright (c) 1990, 1994 Regents of the University of Michigan.
100Sstevel@tonic-gate * All rights reserved.
110Sstevel@tonic-gate *
120Sstevel@tonic-gate * cldap.c - synchronous, retrying interface to the cldap protocol
130Sstevel@tonic-gate */
140Sstevel@tonic-gate
150Sstevel@tonic-gate
160Sstevel@tonic-gate #ifdef CLDAP
170Sstevel@tonic-gate
180Sstevel@tonic-gate #ifndef lint
190Sstevel@tonic-gate static char copyright[] = "@(#) Copyright (c) 1990, 1994 Regents of the University of Michigan.\nAll rights reserved.\n";
200Sstevel@tonic-gate #endif
210Sstevel@tonic-gate
220Sstevel@tonic-gate #include <stdio.h>
230Sstevel@tonic-gate #include <string.h>
240Sstevel@tonic-gate #include <errno.h>
250Sstevel@tonic-gate #ifdef MACOS
260Sstevel@tonic-gate #include <stdlib.h>
270Sstevel@tonic-gate #include "macos.h"
280Sstevel@tonic-gate #else /* MACOS */
290Sstevel@tonic-gate #ifdef DOS
300Sstevel@tonic-gate #include "msdos.h"
310Sstevel@tonic-gate #else /* DOS */
320Sstevel@tonic-gate #include <sys/time.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/socket.h>
350Sstevel@tonic-gate #include <netinet/in.h>
360Sstevel@tonic-gate #include <netdb.h>
370Sstevel@tonic-gate #endif /* DOS */
380Sstevel@tonic-gate #endif /* MACOS */
390Sstevel@tonic-gate #ifdef SUN
400Sstevel@tonic-gate #include <nss_dbdefs.h>
410Sstevel@tonic-gate #endif
420Sstevel@tonic-gate
430Sstevel@tonic-gate #include "lber.h"
440Sstevel@tonic-gate #include "ldap.h"
450Sstevel@tonic-gate #include "ldap-private.h"
460Sstevel@tonic-gate #include "ldap-int.h"
470Sstevel@tonic-gate
480Sstevel@tonic-gate #define DEF_CLDAP_TIMEOUT 3
490Sstevel@tonic-gate #define DEF_CLDAP_TRIES 4
500Sstevel@tonic-gate
510Sstevel@tonic-gate #ifndef INADDR_LOOPBACK
520Sstevel@tonic-gate #define INADDR_LOOPBACK ((in_addr_t) 0x7f000001)
530Sstevel@tonic-gate #endif
540Sstevel@tonic-gate
550Sstevel@tonic-gate
560Sstevel@tonic-gate struct cldap_retinfo {
570Sstevel@tonic-gate int cri_maxtries;
580Sstevel@tonic-gate int cri_try;
590Sstevel@tonic-gate int cri_useaddr;
600Sstevel@tonic-gate time_t cri_timeout;
610Sstevel@tonic-gate };
620Sstevel@tonic-gate
630Sstevel@tonic-gate #ifdef NEEDPROTOS
640Sstevel@tonic-gate static int add_addr( LDAP *ld, struct sockaddr *sap );
650Sstevel@tonic-gate static int cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
660Sstevel@tonic-gate struct cldap_retinfo *crip, char *base );
670Sstevel@tonic-gate static int cldap_parsemsg( LDAP *ld, int msgid, BerElement *ber,
680Sstevel@tonic-gate LDAPMessage **res, char *base );
690Sstevel@tonic-gate #else /* NEEDPROTOS */
700Sstevel@tonic-gate static int add_addr();
710Sstevel@tonic-gate static int cldap_result();
720Sstevel@tonic-gate static int cldap_parsemsg();
730Sstevel@tonic-gate #endif /* NEEDPROTOS */
740Sstevel@tonic-gate
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate * cldap_open - initialize and connect to an ldap server. A magic cookie to
770Sstevel@tonic-gate * be used for future communication is returned on success, NULL on failure.
780Sstevel@tonic-gate *
790Sstevel@tonic-gate * Example:
800Sstevel@tonic-gate * LDAP *ld;
810Sstevel@tonic-gate * ld = cldap_open( hostname, port );
820Sstevel@tonic-gate */
830Sstevel@tonic-gate
840Sstevel@tonic-gate LDAP *
cldap_open(char * host,int port)850Sstevel@tonic-gate cldap_open( char *host, int port )
860Sstevel@tonic-gate {
870Sstevel@tonic-gate int s;
880Sstevel@tonic-gate in_addr_t address;
890Sstevel@tonic-gate struct sockaddr_in sock;
900Sstevel@tonic-gate struct hostent *hp;
910Sstevel@tonic-gate LDAP *ld;
920Sstevel@tonic-gate char *p;
930Sstevel@tonic-gate int i;
940Sstevel@tonic-gate #ifdef SUN
950Sstevel@tonic-gate struct hostent hpret;
960Sstevel@tonic-gate char hpbuf[NSS_BUFLEN_HOSTS];
970Sstevel@tonic-gate int hperrno;
980Sstevel@tonic-gate #endif
990Sstevel@tonic-gate in_addr_t inet_addr(const char *);
1000Sstevel@tonic-gate int close(int);
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 113, "ldap_open\n"), 0, 0, 0 );
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate if ( port == 0 ) {
1050Sstevel@tonic-gate port = LDAP_PORT;
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate if ( (s = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) {
1090Sstevel@tonic-gate return( NULL );
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate sock.sin_addr.s_addr = 0;
1130Sstevel@tonic-gate sock.sin_family = AF_INET;
1140Sstevel@tonic-gate sock.sin_port = 0;
1150Sstevel@tonic-gate if ( bind(s, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
1160Sstevel@tonic-gate close( s );
1170Sstevel@tonic-gate return( NULL );
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate if (( ld = ldap_init( host, port )) == NULL ) {
1210Sstevel@tonic-gate close( s );
1220Sstevel@tonic-gate return( NULL );
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate if ( (ld->ld_sb.sb_fromaddr = (void *) calloc( 1,
1250Sstevel@tonic-gate sizeof( struct sockaddr ))) == NULL ) {
1260Sstevel@tonic-gate free( ld );
1270Sstevel@tonic-gate close( s );
1280Sstevel@tonic-gate return( NULL );
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate ld->ld_sb.sb_sd = s;
1310Sstevel@tonic-gate ld->ld_sb.sb_naddr = 0;
1320Sstevel@tonic-gate ld->ld_version = LDAP_VERSION;
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate sock.sin_family = AF_INET;
1350Sstevel@tonic-gate sock.sin_port = htons( port );
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate /*
1380Sstevel@tonic-gate * 'host' may be a space-separated list.
1390Sstevel@tonic-gate */
1400Sstevel@tonic-gate if ( host != NULL ) {
1410Sstevel@tonic-gate for ( ; host != NULL; host = p ) {
1420Sstevel@tonic-gate if (( p = strchr( host, ' ' )) != NULL ) {
1430Sstevel@tonic-gate for (*p++ = '\0'; *p == ' '; p++) {
1440Sstevel@tonic-gate ;
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate if ( (address = inet_addr( host )) == -1 ) {
1490Sstevel@tonic-gate #ifdef SUN
1500Sstevel@tonic-gate if ( (hp = gethostbyname_r( host, &hpret, hpbuf, NSS_BUFLEN_HOSTS, &hperrno)) == NULL ) {
1510Sstevel@tonic-gate errno = EHOSTUNREACH;
1520Sstevel@tonic-gate continue;
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate #else
1550Sstevel@tonic-gate if ( (hp = gethostbyname( host )) == NULL ) {
1560Sstevel@tonic-gate errno = EHOSTUNREACH;
1570Sstevel@tonic-gate continue;
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate #endif
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate for ( i = 0; hp->h_addr_list[ i ] != 0; ++i ) {
1620Sstevel@tonic-gate SAFEMEMCPY( (char *)&sock.sin_addr.s_addr,
1630Sstevel@tonic-gate (char *)hp->h_addr_list[ i ],
1640Sstevel@tonic-gate sizeof(sock.sin_addr.s_addr));
1650Sstevel@tonic-gate if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
1660Sstevel@tonic-gate close( s );
1670Sstevel@tonic-gate free( ld );
1680Sstevel@tonic-gate return( NULL );
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate } else {
1730Sstevel@tonic-gate sock.sin_addr.s_addr = address;
1740Sstevel@tonic-gate if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
1750Sstevel@tonic-gate close( s );
1760Sstevel@tonic-gate free( ld );
1770Sstevel@tonic-gate return( NULL );
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate if ( ld->ld_host == NULL ) {
1820Sstevel@tonic-gate ld->ld_host = strdup( host );
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate } else {
1870Sstevel@tonic-gate address = INADDR_LOOPBACK;
1880Sstevel@tonic-gate sock.sin_addr.s_addr = htonl( address );
1890Sstevel@tonic-gate if ( add_addr( ld, (struct sockaddr *)&sock ) < 0 ) {
1900Sstevel@tonic-gate close( s );
1910Sstevel@tonic-gate free( ld );
1920Sstevel@tonic-gate return( NULL );
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate if ( ld->ld_sb.sb_addrs == NULL
1970Sstevel@tonic-gate #ifdef LDAP_REFERRALS
1980Sstevel@tonic-gate || ( ld->ld_defconn = new_connection( ld, NULL, 1,0,0 )) == NULL
1990Sstevel@tonic-gate #endif /* LDAP_REFERRALS */
2000Sstevel@tonic-gate ) {
2010Sstevel@tonic-gate free( ld );
2020Sstevel@tonic-gate return( NULL );
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate ld->ld_sb.sb_useaddr = ld->ld_sb.sb_addrs[ 0 ];
2060Sstevel@tonic-gate cldap_setretryinfo( ld, 0, 0 );
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate #ifdef LDAP_DEBUG
2090Sstevel@tonic-gate putchar( '\n' );
2100Sstevel@tonic-gate for ( i = 0; i < ld->ld_sb.sb_naddr; ++i ) {
2110Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 114, "end of cldap_open address %1$d is %2$s\n"),
2120Sstevel@tonic-gate i, inet_ntoa( ((struct sockaddr_in *)
2130Sstevel@tonic-gate ld->ld_sb.sb_addrs[ i ])->sin_addr ), 0 );
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate #endif
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate return( ld );
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate void
cldap_close(LDAP * ld)2230Sstevel@tonic-gate cldap_close( LDAP *ld )
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate ldap_ld_free( ld, 0 );
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate void
cldap_setretryinfo(LDAP * ld,int tries,time_t timeout)2300Sstevel@tonic-gate cldap_setretryinfo( LDAP *ld, int tries, time_t timeout )
2310Sstevel@tonic-gate {
2320Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
2330Sstevel@tonic-gate LOCK_LDAP(ld);
2340Sstevel@tonic-gate #endif
2350Sstevel@tonic-gate ld->ld_cldaptries = ( tries <= 0 ) ? DEF_CLDAP_TRIES : tries;
2360Sstevel@tonic-gate ld->ld_cldaptimeout = ( timeout <= 0 ) ? DEF_CLDAP_TIMEOUT : timeout;
2370Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
2380Sstevel@tonic-gate UNLOCK_LDAP(ld);
2390Sstevel@tonic-gate #endif
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate int
cldap_search_s(LDAP * ld,char * base,int scope,char * filter,char ** attrs,int attrsonly,LDAPMessage ** res,char * logdn)2440Sstevel@tonic-gate cldap_search_s( LDAP *ld, char *base, int scope, char *filter, char **attrs,
2450Sstevel@tonic-gate int attrsonly, LDAPMessage **res, char *logdn )
2460Sstevel@tonic-gate {
2470Sstevel@tonic-gate int ret, msgid;
2480Sstevel@tonic-gate struct cldap_retinfo cri;
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate *res = NULLMSG;
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate (void) memset( &cri, 0, sizeof( cri ));
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
2550Sstevel@tonic-gate LOCK_LDAP(ld);
2560Sstevel@tonic-gate #endif
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate if ( logdn != NULL ) {
2590Sstevel@tonic-gate ld->ld_cldapdn = logdn;
2600Sstevel@tonic-gate } else if ( ld->ld_cldapdn == NULL ) {
2610Sstevel@tonic-gate ld->ld_cldapdn = "";
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate do {
2650Sstevel@tonic-gate if ( cri.cri_try != 0 ) {
2660Sstevel@tonic-gate --ld->ld_msgid; /* use same id as before */
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate ld->ld_sb.sb_useaddr = ld->ld_sb.sb_addrs[ cri.cri_useaddr ];
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 115, "cldap_search_s try %1$d (to %2$s)\n"),
2710Sstevel@tonic-gate cri.cri_try, inet_ntoa( ((struct sockaddr_in *)
2720Sstevel@tonic-gate ld->ld_sb.sb_useaddr)->sin_addr ), 0 );
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate if ( (msgid = ldap_search( ld, base, scope, filter, attrs,
2750Sstevel@tonic-gate attrsonly )) == -1 ) {
2760Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
2770Sstevel@tonic-gate UNLOCK_LDAP(ld);
2780Sstevel@tonic-gate #endif
2790Sstevel@tonic-gate return( ld->ld_errno );
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate #ifndef NO_CACHE
2820Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
2830Sstevel@tonic-gate LOCK_RESPONSE(ld);
2840Sstevel@tonic-gate #endif
2850Sstevel@tonic-gate if ( ld->ld_cache != NULL && ld->ld_responses != NULL ) {
2860Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 116, "cldap_search_s res from cache\n"),
2870Sstevel@tonic-gate 0, 0, 0 );
2880Sstevel@tonic-gate *res = ld->ld_responses;
2890Sstevel@tonic-gate ld->ld_responses = ld->ld_responses->lm_next;
2900Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
2910Sstevel@tonic-gate UNLOCK_LDAP(ld);
2920Sstevel@tonic-gate ret = ldap_result2error( ld, *res, 0 );
2930Sstevel@tonic-gate UNLOCK_RESPONSE(ld);
2940Sstevel@tonic-gate return( ret );
2950Sstevel@tonic-gate #else
2960Sstevel@tonic-gate return( ldap_result2error( ld, *res, 0 ));
2970Sstevel@tonic-gate #endif
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate #endif /* NO_CACHE */
3000Sstevel@tonic-gate ret = cldap_result( ld, msgid, res, &cri, base );
3010Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
3020Sstevel@tonic-gate UNLOCK_RESPONSE(ld);
3030Sstevel@tonic-gate #endif
3040Sstevel@tonic-gate } while (ret == -1);
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate return( ret );
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate static int
add_addr(LDAP * ld,struct sockaddr * sap)3110Sstevel@tonic-gate add_addr( LDAP *ld, struct sockaddr *sap )
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate struct sockaddr *newsap, **addrs;
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate if (( newsap = (struct sockaddr *)malloc( sizeof( struct sockaddr )))
3160Sstevel@tonic-gate == NULL ) {
3170Sstevel@tonic-gate ld->ld_errno = LDAP_NO_MEMORY;
3180Sstevel@tonic-gate return( -1 );
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate if ( ld->ld_sb.sb_naddr == 0 ) {
3220Sstevel@tonic-gate addrs = (struct sockaddr **)malloc( sizeof(struct sockaddr *));
3230Sstevel@tonic-gate } else {
3240Sstevel@tonic-gate addrs = (struct sockaddr **)realloc( ld->ld_sb.sb_addrs,
3250Sstevel@tonic-gate ( ld->ld_sb.sb_naddr + 1 ) * sizeof(struct sockaddr *));
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate if ( addrs == NULL ) {
3290Sstevel@tonic-gate free( newsap );
3300Sstevel@tonic-gate ld->ld_errno = LDAP_NO_MEMORY;
3310Sstevel@tonic-gate return( -1 );
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate SAFEMEMCPY( (char *)newsap, (char *)sap, sizeof( struct sockaddr ));
3350Sstevel@tonic-gate addrs[ ld->ld_sb.sb_naddr++ ] = newsap;
3360Sstevel@tonic-gate ld->ld_sb.sb_addrs = (void **)addrs;
3370Sstevel@tonic-gate return( 0 );
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate static int
cldap_result(LDAP * ld,int msgid,LDAPMessage ** res,struct cldap_retinfo * crip,char * base)3420Sstevel@tonic-gate cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
3430Sstevel@tonic-gate struct cldap_retinfo *crip, char *base )
3440Sstevel@tonic-gate {
3450Sstevel@tonic-gate Sockbuf *sb;
3460Sstevel@tonic-gate BerElement ber;
3470Sstevel@tonic-gate char *logdn;
3480Sstevel@tonic-gate int ret, id, fromaddr, i;
3490Sstevel@tonic-gate struct timeval tv;
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
3520Sstevel@tonic-gate LOCK_LDAP(ld);
3530Sstevel@tonic-gate #endif
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate sb = &ld->ld_sb;
3560Sstevel@tonic-gate fromaddr = -1;
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate if ( crip->cri_try == 0 ) {
3590Sstevel@tonic-gate crip->cri_maxtries = ld->ld_cldaptries * sb->sb_naddr;
3600Sstevel@tonic-gate crip->cri_timeout = ld->ld_cldaptimeout;
3610Sstevel@tonic-gate crip->cri_useaddr = 0;
3620Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 117, "cldap_result tries %1$d timeout %2$d\n"),
3630Sstevel@tonic-gate ld->ld_cldaptries, ld->ld_cldaptimeout, 0 );
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate if ((tv.tv_sec = crip->cri_timeout / sb->sb_naddr) < 1 ) {
3670Sstevel@tonic-gate tv.tv_sec = 1;
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate tv.tv_usec = 0;
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE,
3720Sstevel@tonic-gate catgets(slapdcat, 1, 118, "cldap_result waiting up to %d seconds for a response\n"),
3730Sstevel@tonic-gate tv.tv_sec, 0, 0 );
3740Sstevel@tonic-gate ber_zero_init( &ber, 0 );
3750Sstevel@tonic-gate set_ber_options( ld, &ber );
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate if ( cldap_getmsg( ld, &tv, &ber ) == -1 ) {
3780Sstevel@tonic-gate ret = ld->ld_errno;
3790Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 119, "cldap_getmsg returned -1 (%d)\n"),
3800Sstevel@tonic-gate ret, 0, 0 );
3810Sstevel@tonic-gate } else if ( ld->ld_errno == LDAP_TIMEOUT ) {
3820Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE,
3830Sstevel@tonic-gate catgets(slapdcat, 1, 120, "cldap_result timed out\n"), 0, 0, 0 );
3840Sstevel@tonic-gate /*
3850Sstevel@tonic-gate * It timed out; is it time to give up?
3860Sstevel@tonic-gate */
3870Sstevel@tonic-gate if ( ++crip->cri_try >= crip->cri_maxtries ) {
3880Sstevel@tonic-gate ret = LDAP_TIMEOUT;
3890Sstevel@tonic-gate --crip->cri_try;
3900Sstevel@tonic-gate } else {
3910Sstevel@tonic-gate if ( ++crip->cri_useaddr >= sb->sb_naddr ) {
3920Sstevel@tonic-gate /*
3930Sstevel@tonic-gate * new round: reset address to first one and
3940Sstevel@tonic-gate * double the timeout
3950Sstevel@tonic-gate */
3960Sstevel@tonic-gate crip->cri_useaddr = 0;
3970Sstevel@tonic-gate crip->cri_timeout <<= 1;
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate ret = -1;
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate } else {
4030Sstevel@tonic-gate /*
4040Sstevel@tonic-gate * Got a response. It should look like:
4050Sstevel@tonic-gate * { msgid, logdn, { searchresponse...}}
4060Sstevel@tonic-gate */
4070Sstevel@tonic-gate logdn = NULL;
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate if ( ber_scanf( &ber, "ia", &id, &logdn ) == LBER_ERROR ) {
4100Sstevel@tonic-gate free( ber.ber_buf ); /* gack! */
4110Sstevel@tonic-gate ret = LDAP_DECODING_ERROR;
4120Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE,
4130Sstevel@tonic-gate catgets(slapdcat, 1, 121, "cldap_result: ber_scanf returned LBER_ERROR (%d)\n"),
4140Sstevel@tonic-gate ret, 0, 0 );
4150Sstevel@tonic-gate } else if ( id != msgid ) {
4160Sstevel@tonic-gate free( ber.ber_buf ); /* gack! */
4170Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE,
4180Sstevel@tonic-gate catgets(slapdcat, 1, 122, "cldap_result: looking for msgid %1$d; got %2$d\n"),
4190Sstevel@tonic-gate msgid, id, 0 );
4200Sstevel@tonic-gate ret = -1; /* ignore and keep looking */
4210Sstevel@tonic-gate } else {
4220Sstevel@tonic-gate /*
4230Sstevel@tonic-gate * got a result: determine which server it came from
4240Sstevel@tonic-gate * decode into ldap message chain
4250Sstevel@tonic-gate */
4260Sstevel@tonic-gate for ( fromaddr = 0; fromaddr < sb->sb_naddr; ++fromaddr ) {
4270Sstevel@tonic-gate if ( memcmp( &((struct sockaddr_in *)
4280Sstevel@tonic-gate sb->sb_addrs[ fromaddr ])->sin_addr,
4290Sstevel@tonic-gate &((struct sockaddr_in *)sb->sb_fromaddr)->sin_addr,
4300Sstevel@tonic-gate sizeof( struct in_addr )) == 0 ) {
4310Sstevel@tonic-gate break;
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate ret = cldap_parsemsg( ld, msgid, &ber, res, base );
4350Sstevel@tonic-gate free( ber.ber_buf ); /* gack! */
4360Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE,
4370Sstevel@tonic-gate catgets(slapdcat, 1, 123, "cldap_result got result (%d)\n"), ret, 0, 0 );
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate if ( logdn != NULL ) {
4410Sstevel@tonic-gate free( logdn );
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate * If we are giving up (successfully or otherwise) then
4480Sstevel@tonic-gate * abandon any outstanding requests.
4490Sstevel@tonic-gate */
4500Sstevel@tonic-gate if ( ret != -1 ) {
4510Sstevel@tonic-gate i = crip->cri_try;
4520Sstevel@tonic-gate if ( i >= sb->sb_naddr ) {
4530Sstevel@tonic-gate i = sb->sb_naddr - 1;
4540Sstevel@tonic-gate }
4550Sstevel@tonic-gate
4560Sstevel@tonic-gate for ( ; i >= 0; --i ) {
4570Sstevel@tonic-gate if ( i == fromaddr ) {
4580Sstevel@tonic-gate continue;
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate sb->sb_useaddr = sb->sb_addrs[ i ];
4610Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 124, "cldap_result abandoning id %1$d (to %2$s)\n"),
4620Sstevel@tonic-gate msgid, inet_ntoa( ((struct sockaddr_in *)
4630Sstevel@tonic-gate sb->sb_useaddr)->sin_addr ), 0 );
4640Sstevel@tonic-gate (void) ldap_abandon( ld, msgid );
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate #if defined( SUN ) && defined( _REENTRANT )
4690Sstevel@tonic-gate UNLOCK_LDAP(ld);
4700Sstevel@tonic-gate #endif
4710Sstevel@tonic-gate return( ld->ld_errno = ret );
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate static int
cldap_parsemsg(LDAP * ld,int msgid,BerElement * ber,LDAPMessage ** res,char * base)4760Sstevel@tonic-gate cldap_parsemsg( LDAP *ld, int msgid, BerElement *ber,
4770Sstevel@tonic-gate LDAPMessage **res, char *base )
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate unsigned int tag, len;
4800Sstevel@tonic-gate int rc;
4810Sstevel@tonic-gate size_t baselen, slen;
4820Sstevel@tonic-gate char *dn, *p, *cookie;
4830Sstevel@tonic-gate LDAPMessage *chain, *prev, *ldm;
4840Sstevel@tonic-gate struct berval *bv;
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate rc = LDAP_DECODING_ERROR; /* pessimistic */
4870Sstevel@tonic-gate ldm = chain = prev = NULLMSG;
4880Sstevel@tonic-gate baselen = ( base == NULL ) ? 0 : strlen( base );
4890Sstevel@tonic-gate bv = NULL;
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate for ( tag = ber_first_element( ber, &len, &cookie );
4920Sstevel@tonic-gate tag != LBER_DEFAULT && rc != LDAP_SUCCESS;
4930Sstevel@tonic-gate tag = ber_next_element( ber, &len, cookie )) {
4940Sstevel@tonic-gate if (( ldm = (LDAPMessage *)calloc( 1, sizeof(LDAPMessage)))
4950Sstevel@tonic-gate == NULL || ( ldm->lm_ber = alloc_ber_with_options( ld ))
4960Sstevel@tonic-gate == NULLBER ) {
4970Sstevel@tonic-gate rc = LDAP_NO_MEMORY;
4980Sstevel@tonic-gate break; /* return w/error*/
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate ldm->lm_msgid = msgid;
5010Sstevel@tonic-gate ldm->lm_msgtype = tag;
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate if ( tag == LDAP_RES_SEARCH_RESULT ) {
5040Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 125, "cldap_parsemsg got search result\n"),
5050Sstevel@tonic-gate 0, 0, 0 );
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate if ( ber_get_stringal( ber, &bv ) == LBER_DEFAULT ) {
5080Sstevel@tonic-gate break; /* return w/error */
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate if ( ber_printf( ldm->lm_ber, "to", tag, bv->bv_val,
5120Sstevel@tonic-gate bv->bv_len ) == -1 ) {
5130Sstevel@tonic-gate break; /* return w/error */
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate ber_bvfree( bv );
5160Sstevel@tonic-gate bv = NULL;
5170Sstevel@tonic-gate rc = LDAP_SUCCESS;
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate } else if ( tag == LDAP_RES_SEARCH_ENTRY ) {
5200Sstevel@tonic-gate if ( ber_scanf( ber, "{aO", &dn, &bv ) == LBER_ERROR ) {
5210Sstevel@tonic-gate break; /* return w/error */
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 126, "cldap_parsemsg entry %s\n"), dn, 0, 0 );
5240Sstevel@tonic-gate if ( dn != NULL && *(dn + ( slen = strlen(dn)) - 1) == '*' &&
5250Sstevel@tonic-gate baselen > 0 ) {
5260Sstevel@tonic-gate /*
5270Sstevel@tonic-gate * substitute original searchbase for trailing '*'
5280Sstevel@tonic-gate */
5290Sstevel@tonic-gate if (( p = (char *)malloc( slen + baselen )) == NULL ) {
5300Sstevel@tonic-gate rc = LDAP_NO_MEMORY;
5310Sstevel@tonic-gate free( dn );
5320Sstevel@tonic-gate break; /* return w/error */
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate strcpy( p, dn );
5350Sstevel@tonic-gate strcpy( p + slen - 1, base );
5360Sstevel@tonic-gate free( dn );
5370Sstevel@tonic-gate dn = p;
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate if ( ber_printf( ldm->lm_ber, "t{so}", tag, dn, bv->bv_val,
5410Sstevel@tonic-gate bv->bv_len ) == -1 ) {
5420Sstevel@tonic-gate break; /* return w/error */
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate free( dn );
5450Sstevel@tonic-gate ber_bvfree( bv );
5460Sstevel@tonic-gate bv = NULL;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate } else {
5490Sstevel@tonic-gate Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 127, "cldap_parsemsg got unknown tag %d\n"),
5500Sstevel@tonic-gate tag, 0, 0 );
5510Sstevel@tonic-gate rc = LDAP_PROTOCOL_ERROR;
5520Sstevel@tonic-gate break; /* return w/error */
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate /* Reset message ber so we can read from it later. Gack! */
5560Sstevel@tonic-gate ldm->lm_ber->ber_end = ldm->lm_ber->ber_ptr;
5570Sstevel@tonic-gate ldm->lm_ber->ber_ptr = ldm->lm_ber->ber_buf;
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate #ifdef LDAP_DEBUG
5600Sstevel@tonic-gate if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
5610Sstevel@tonic-gate fprintf( stderr, "cldap_parsemsg add message id %d type %d:\n",
5620Sstevel@tonic-gate ldm->lm_msgid, ldm->lm_msgtype );
5630Sstevel@tonic-gate ber_dump( ldm->lm_ber, 1 );
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate #endif /* LDAP_DEBUG */
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate #ifndef NO_CACHE
5680Sstevel@tonic-gate if ( ld->ld_cache != NULL ) {
5690Sstevel@tonic-gate add_result_to_cache( ld, ldm );
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate #endif /* NO_CACHE */
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate if ( chain == NULL ) {
5740Sstevel@tonic-gate chain = ldm;
5750Sstevel@tonic-gate } else {
5760Sstevel@tonic-gate prev->lm_chain = ldm;
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate prev = ldm;
5790Sstevel@tonic-gate ldm = NULL;
5800Sstevel@tonic-gate }
5810Sstevel@tonic-gate
5820Sstevel@tonic-gate /* dispose of any leftovers */
5830Sstevel@tonic-gate if ( ldm != NULL ) {
5840Sstevel@tonic-gate if ( ldm->lm_ber != NULLBER ) {
5850Sstevel@tonic-gate ber_free( ldm->lm_ber, 1 );
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate free( ldm );
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate if ( bv != NULL ) {
5900Sstevel@tonic-gate ber_bvfree( bv );
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate /* return chain, calling result2error if we got anything at all */
5940Sstevel@tonic-gate *res = chain;
5950Sstevel@tonic-gate return(( *res == NULLMSG ) ? rc : ldap_result2error( ld, *res, 0 ));
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate #endif /* CLDAP */
598