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