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 * 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 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 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 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 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 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 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