1 /*
   2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 #pragma ident   "%Z%%M% %I%     %E% SMI"
   7 
   8 
   9 /*
  10  * The contents of this file are subject to the Netscape Public
  11  * License Version 1.1 (the "License"); you may not use this file
  12  * except in compliance with the License. You may obtain a copy of
  13  * the License at http://www.mozilla.org/NPL/
  14  *
  15  * Software distributed under the License is distributed on an "AS
  16  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  17  * implied. See the License for the specific language governing
  18  * rights and limitations under the License.
  19  *
  20  * The Original Code is Mozilla Communicator client code, released
  21  * March 31, 1998.
  22  *
  23  * The Initial Developer of the Original Code is Netscape
  24  * Communications Corporation. Portions created by Netscape are
  25  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
  26  * Rights Reserved.
  27  *
  28  * Contributor(s):
  29  */
  30 /*
  31  *  Copyright (c) 1995 Regents of the University of Michigan.
  32  *  All rights reserved.
  33  */
  34 /*
  35  *  open.c
  36  */
  37 
  38 #if 0
  39 #ifndef lint 
  40 static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
  41 #endif
  42 #endif
  43 
  44 #include "ldap-int.h"
  45 #ifdef LDAP_SASLIO_HOOKS
  46 /* Valid for any ANSI C compiler */
  47 #include <limits.h>
  48 #endif
  49 
  50 #define VI_PRODUCTVERSION 3
  51 
  52 #ifndef INADDR_LOOPBACK
  53 #define INADDR_LOOPBACK ((unsigned long) 0x7f000001)
  54 #endif
  55 
  56 #ifndef MAXHOSTNAMELEN
  57 #define MAXHOSTNAMELEN  64
  58 #endif
  59 
  60 #ifdef LDAP_DEBUG
  61 int     ldap_debug;
  62 #endif
  63 
  64 
  65 /*
  66  * global defaults for callbacks are stored here.  callers of the API set
  67  *    these by passing a NULL "ld" to ldap_set_option().  Everything in
  68  *    nsldapi_ld_defaults can be overridden on a per-ld basis as well (the
  69  *    memory allocation functions are global to all ld's).
  70  */
  71 struct ldap                     nsldapi_ld_defaults;
  72 struct ldap_memalloc_fns        nsldapi_memalloc_fns = { 0, 0, 0, 0 };
  73 int                             nsldapi_initialized = 0;
  74 
  75 #ifndef _WINDOWS
  76 #include <pthread.h>
  77 static pthread_key_t            nsldapi_key;
  78 
  79 struct nsldapi_ldap_error {
  80         int     le_errno;
  81         char    *le_matched;
  82         char    *le_errmsg;
  83 };
  84 #else
  85 __declspec ( thread ) int       nsldapi_gldaperrno;
  86 __declspec ( thread ) char      *nsldapi_gmatched = NULL;
  87 __declspec ( thread ) char      *nsldapi_gldaperror = NULL; 
  88 #endif /* _WINDOWS */
  89 
  90 #ifdef _WINDOWS
  91 #define LDAP_MUTEX_T    HANDLE
  92 
  93 int
  94 pthread_mutex_init( LDAP_MUTEX_T *mp, void *attr)
  95 {
  96         if ( (*mp = CreateMutex(NULL, FALSE, NULL)) == NULL )
  97                 return( 1 );
  98         else
  99                 return( 0 );
 100 }
 101 
 102 static void *
 103 pthread_mutex_alloc( void )
 104 {
 105         LDAP_MUTEX_T *mutexp;
 106 
 107         if ( (mutexp = malloc( sizeof(LDAP_MUTEX_T) )) != NULL ) {
 108                 pthread_mutex_init( mutexp, NULL );
 109         }
 110         return( mutexp );
 111 }
 112 
 113 int
 114 pthread_mutex_destroy( LDAP_MUTEX_T *mp )
 115 {
 116         if ( !(CloseHandle(*mp)) )
 117                 return( 1 );
 118         else
 119                 return( 0 );
 120 }
 121 
 122 static void
 123 pthread_mutex_free( void *mutexp )
 124 {
 125         pthread_mutex_destroy( (LDAP_MUTEX_T *) mutexp );
 126         free( mutexp );
 127 }
 128 
 129 int
 130 pthread_mutex_lock( LDAP_MUTEX_T *mp )
 131 {
 132         if ( (WaitForSingleObject(*mp, INFINITE) != WAIT_OBJECT_0) )
 133                 return( 1 );
 134         else
 135                 return( 0 );
 136 }
 137 
 138 int
 139 pthread_mutex_unlock( LDAP_MUTEX_T *mp )
 140 {
 141         if ( !(ReleaseMutex(*mp)) )
 142                 return( 1 );
 143         else
 144                 return( 0 );
 145 }
 146 
 147 static int
 148 get_errno( void )
 149 {
 150         return errno;
 151 }
 152 
 153 static void
 154 set_errno( int Errno )
 155 {
 156         errno = Errno;
 157 }
 158 
 159 static int
 160 get_ld_error( char **LDMatched, char **LDError, void * Args )
 161 {
 162         if ( LDMatched != NULL )
 163         {
 164                 *LDMatched = nsldapi_gmatched;
 165         }
 166         if ( LDError != NULL )
 167         {
 168                 *LDError = nsldapi_gldaperror;
 169         }
 170         return nsldapi_gldaperrno;
 171 }
 172 
 173 static void
 174 set_ld_error( int LDErrno, char *  LDMatched, char *  LDError,
 175         void *  Args )
 176 {
 177         /* Clean up any previous string storage. */
 178         if ( nsldapi_gmatched != NULL )
 179         {
 180                 ldap_memfree( nsldapi_gmatched );
 181         }
 182         if ( nsldapi_gldaperror != NULL )
 183         {
 184                 ldap_memfree( nsldapi_gldaperror );
 185         }
 186 
 187         nsldapi_gldaperrno  = LDErrno;
 188         nsldapi_gmatched    = LDMatched;
 189         nsldapi_gldaperror  = LDError;
 190 }
 191 #else
 192 static void *
 193 pthread_mutex_alloc( void )
 194 {
 195         pthread_mutex_t *mutexp;
 196 
 197         if ( (mutexp = malloc( sizeof(pthread_mutex_t) )) != NULL ) {
 198                 pthread_mutex_init( mutexp, NULL );
 199         }
 200         return( mutexp );
 201 }
 202 
 203 static void
 204 pthread_mutex_free( void *mutexp )
 205 {
 206         pthread_mutex_destroy( (pthread_mutex_t *) mutexp );
 207         free( mutexp );
 208 }
 209 
 210 static void
 211 set_ld_error( int err, char *matched, char *errmsg, void *dummy )
 212 {
 213         struct nsldapi_ldap_error *le;
 214         void *tsd;
 215 
 216         le = pthread_getspecific( nsldapi_key );
 217 
 218         if (le == NULL) {
 219                 tsd = (void *)calloc(1, sizeof(struct nsldapi_ldap_error));
 220                 pthread_setspecific( nsldapi_key, tsd );
 221         }
 222 
 223         le = pthread_getspecific( nsldapi_key );
 224 
 225         if (le == NULL) {
 226                 free(tsd);
 227                 return;
 228         }
 229 
 230         le->le_errno = err;
 231 
 232         if ( le->le_matched != NULL ) {
 233                 ldap_memfree( le->le_matched );
 234         }
 235         le->le_matched = matched;
 236 
 237         if ( le->le_errmsg != NULL ) {
 238                 ldap_memfree( le->le_errmsg );
 239         }
 240         le->le_errmsg = errmsg;
 241 }
 242 
 243 static int
 244 get_ld_error( char **matched, char **errmsg, void *dummy )
 245 {
 246         struct nsldapi_ldap_error *le;
 247 
 248         le = pthread_getspecific( nsldapi_key );
 249         if (le != NULL) {
 250                 if ( matched != NULL ) {
 251                         *matched = le->le_matched;
 252                 }
 253                 if ( errmsg != NULL ) {
 254                         *errmsg = le->le_errmsg;
 255                 }
 256                 return( le->le_errno );
 257         } else {
 258                 if ( matched != NULL )
 259                         *matched = NULL;
 260                 if ( errmsg != NULL )
 261                         *errmsg = NULL;
 262         }
 263         return (LDAP_SUCCESS);
 264 }
 265 
 266 static void
 267 set_errno( int err )
 268 {
 269         errno = err;
 270 }
 271 
 272 static int
 273 get_errno( void )
 274 {
 275         return( errno );
 276 }
 277 #endif /* _WINDOWS */
 278 
 279 static struct ldap_thread_fns
 280         nsldapi_default_thread_fns = {
 281                 (void *(*)(void))pthread_mutex_alloc,
 282                 (void (*)(void *))pthread_mutex_free,
 283                 (int (*)(void *))pthread_mutex_lock,
 284                 (int (*)(void *))pthread_mutex_unlock,
 285                 (int (*)(void))get_errno,
 286                 (void (*)(int))set_errno,
 287                 (int (*)(char **, char **, void *))get_ld_error,
 288                 (void (*)(int, char *, char *, void *))set_ld_error,
 289                 0 };
 290 
 291 static struct ldap_extra_thread_fns
 292         nsldapi_default_extra_thread_fns = {
 293                 0, 0, 0, 0, 0,
 294 #ifdef _WINDOWS
 295                 0
 296 #else
 297                 (void *(*)(void))pthread_self
 298 #endif /* _WINDOWS */
 299                 };
 300 
 301 void
 302 nsldapi_initialize_defaults( void )
 303 {
 304 
 305         if ( nsldapi_initialized ) {
 306                 return;
 307         }
 308 #ifdef  _SOLARIS_SDK
 309         /*
 310          * This has to be called before nsldapi_initialized is set to 1
 311          * because nsldapi_initialized does not have mutex protection
 312          */
 313         prldap_nspr_init();
 314 #endif
 315 
 316 #ifndef _WINDOWS
 317         if ( pthread_key_create(&nsldapi_key, free ) != 0) {
 318                 perror("pthread_key_create");
 319         }
 320 #endif /* _WINDOWS */
 321 
 322         nsldapi_initialized = 1;
 323         memset( &nsldapi_memalloc_fns, 0, sizeof( nsldapi_memalloc_fns ));
 324         memset( &nsldapi_ld_defaults, 0, sizeof( nsldapi_ld_defaults ));
 325         nsldapi_ld_defaults.ld_options = LDAP_BITOPT_REFERRALS;
 326         nsldapi_ld_defaults.ld_version = LDAP_VERSION2;
 327         nsldapi_ld_defaults.ld_lberoptions = LBER_OPT_USE_DER;
 328         nsldapi_ld_defaults.ld_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT;
 329 
 330 #ifdef LDAP_SASLIO_HOOKS
 331         /* SASL default option settings */
 332         nsldapi_ld_defaults.ld_def_sasl_mech = NULL;
 333         nsldapi_ld_defaults.ld_def_sasl_realm = NULL;
 334         nsldapi_ld_defaults.ld_def_sasl_authcid = NULL;
 335         nsldapi_ld_defaults.ld_def_sasl_authzid = NULL;
 336         /* SASL Security properties */
 337         nsldapi_ld_defaults.ld_sasl_secprops.max_ssf = UINT_MAX;
 338         nsldapi_ld_defaults.ld_sasl_secprops.maxbufsize = SASL_MAX_BUFF_SIZE;
 339         nsldapi_ld_defaults.ld_sasl_secprops.security_flags =
 340                 SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS;
 341 #endif
 342 
 343 #if defined( STR_TRANSLATION ) && defined( LDAP_DEFAULT_CHARSET )
 344         nsldapi_ld_defaults.ld_lberoptions |= LBER_OPT_TRANSLATE_STRINGS;
 345 #if LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET
 346         ldap_set_string_translators( &nsldapi_ld_defaults, ldap_8859_to_t61,
 347             ldap_t61_to_8859 );
 348 #endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */
 349 #endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
 350 
 351         /* set default connect timeout (in milliseconds) */
 352         /* this was picked as it is the standard tcp timeout as well */
 353         nsldapi_ld_defaults.ld_connect_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
 354 
 355         /* load up default platform specific locking routines */
 356         if (ldap_set_option( NULL, LDAP_OPT_THREAD_FN_PTRS,
 357                 (void *)&nsldapi_default_thread_fns) != LDAP_SUCCESS) {
 358                 return;
 359         }
 360 
 361 #ifndef _WINDOWS
 362         /* load up default threadid function */
 363         if (ldap_set_option( NULL, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
 364                 (void *)&nsldapi_default_extra_thread_fns) != LDAP_SUCCESS) {
 365                 return;
 366         }
 367 #endif /* _WINDOWS */
 368 }
 369 
 370 
 371 /*
 372  * ldap_version - report version levels for important properties
 373  * This function is deprecated.  Use ldap_get_option( ..., LDAP_OPT_API_INFO,
 374  *      ... ) instead.
 375  *
 376  * Example:
 377  *      LDAPVersion ver;
 378  *      ldap_version( &ver );
 379  *  if ( (ver.sdk_version < 100) || (ver.SSL_version < 300) )
 380  *      fprintf( stderr, "LDAP SDK level insufficient\n" );
 381  *
 382  * or:
 383  *  if ( ldap_version(NULL) < 100 )
 384  *      fprintf( stderr, "LDAP SDK level insufficient\n" );
 385  *
 386  */
 387 
 388 int
 389 LDAP_CALL
 390 ldap_version( LDAPVersion *ver )
 391 {
 392         if ( NULL != ver )
 393         {
 394                 memset( ver, 0, sizeof(*ver) );
 395                 ver->sdk_version = (int)(VI_PRODUCTVERSION * 100);
 396                 ver->protocol_version = LDAP_VERSION_MAX * 100;
 397                 ver->SSL_version = SSL_VERSION * 100;
 398                 /* 
 399                  * set security to none by default 
 400                  */
 401 
 402                 ver->security_level = LDAP_SECURITY_NONE;
 403 #if defined(LINK_SSL)
 404 #if defined(NS_DOMESTIC)
 405                 ver->security_level = 128;
 406 #elif defined(NSS_EXPORT)
 407                 ver->security_level = 40;
 408 #endif
 409 #endif
 410 
 411         }
 412         return (int)(VI_PRODUCTVERSION * 100);
 413 }
 414 
 415 /*
 416  * ldap_open - initialize and connect to an ldap server.  A magic cookie to
 417  * be used for future communication is returned on success, NULL on failure.
 418  * "host" may be a space-separated list of hosts or IP addresses
 419  *
 420  * Example:
 421  *      LDAP    *ld;
 422  *      ld = ldap_open( hostname, port );
 423  */
 424 
 425 LDAP *
 426 LDAP_CALL
 427 ldap_open( const char *host, int port )
 428 {
 429         LDAP    *ld;
 430 
 431         LDAPDebug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
 432 
 433         if (( ld = ldap_init( host, port )) == NULL ) {
 434                 return( NULL );
 435         }
 436 
 437         LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
 438         if ( nsldapi_open_ldap_defconn( ld ) < 0 ) {
 439                 LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
 440                 ldap_ld_free( ld, NULL, NULL, 0 );
 441                 return( NULL );
 442         }
 443 
 444         LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
 445         LDAPDebug( LDAP_DEBUG_TRACE, "ldap_open successful, ld_host is %s\n",
 446                 ( ld->ld_host == NULL ) ? "(null)" : ld->ld_host, 0, 0 );
 447 
 448         return( ld );
 449 }
 450 
 451 
 452 /*
 453  * ldap_init - initialize the LDAP library.  A magic cookie to be used for
 454  * future communication is returned on success, NULL on failure.
 455  * "defhost" may be a space-separated list of hosts or IP addresses
 456  *
 457  * Example:
 458  *      LDAP    *ld;
 459  *      ld = ldap_init( default_hostname, default_port );
 460  */
 461 LDAP *
 462 LDAP_CALL
 463 ldap_init( const char *defhost, int defport )
 464 {
 465         LDAP    *ld;
 466 
 467         if ( !nsldapi_initialized ) {
 468                 nsldapi_initialize_defaults();
 469         }
 470 
 471         if ( defport < 0 || defport > LDAP_PORT_MAX ) {
 472             LDAPDebug( LDAP_DEBUG_ANY,
 473                     "ldap_init: port %d is invalid (port numbers must range from 1 to %d)\n",
 474                     defport, LDAP_PORT_MAX, 0 );
 475 #if !defined( macintosh ) && !defined( DOS )
 476             errno = EINVAL;
 477 #endif
 478             return( NULL );
 479         }
 480 
 481         LDAPDebug( LDAP_DEBUG_TRACE, "ldap_init\n", 0, 0, 0 );
 482 
 483         if ( (ld = (LDAP*)NSLDAPI_MALLOC( sizeof(struct ldap) )) == NULL ) {
 484                 return( NULL );
 485         }
 486 
 487         /* copy defaults */
 488         SAFEMEMCPY( ld, &nsldapi_ld_defaults, sizeof( struct ldap ));
 489         if ( nsldapi_ld_defaults.ld_io_fns_ptr != NULL ) {
 490                 if (( ld->ld_io_fns_ptr = (struct ldap_io_fns *)NSLDAPI_MALLOC(
 491                     sizeof( struct ldap_io_fns ))) == NULL ) {
 492                         NSLDAPI_FREE( (char *)ld );
 493                         return( NULL );
 494                 }
 495                 /* struct copy */
 496                 *(ld->ld_io_fns_ptr) = *(nsldapi_ld_defaults.ld_io_fns_ptr);
 497         }
 498 
 499         /* call the new handle I/O callback if one is defined */
 500         if ( ld->ld_extnewhandle_fn != NULL ) {
 501                 /*
 502                  * We always pass the session extended I/O argument to
 503                  * the new handle callback.
 504                  */
 505                 if ( ld->ld_extnewhandle_fn( ld, ld->ld_ext_session_arg )
 506                     != LDAP_SUCCESS ) {
 507                         NSLDAPI_FREE( (char*)ld );
 508                         return( NULL );
 509                 }
 510         }
 511 
 512         /* allocate session-specific resources */
 513         if (( ld->ld_sbp = ber_sockbuf_alloc()) == NULL ||
 514             ( defhost != NULL &&
 515             ( ld->ld_defhost = nsldapi_strdup( defhost )) == NULL ) ||
 516             ((ld->ld_mutex = (void **) NSLDAPI_CALLOC( LDAP_MAX_LOCK, sizeof(void *))) == NULL )) {
 517                 if ( ld->ld_sbp != NULL ) {
 518                         ber_sockbuf_free( ld->ld_sbp );
 519                 }
 520                 if( ld->ld_mutex != NULL ) {
 521                         NSLDAPI_FREE( ld->ld_mutex );
 522                 }
 523                 NSLDAPI_FREE( (char*)ld );
 524                 return( NULL );
 525         }
 526 
 527         /* install Sockbuf I/O functions if set in LDAP * */
 528         if ( ld->ld_extread_fn != NULL || ld->ld_extwrite_fn != NULL ) {
 529                 struct lber_x_ext_io_fns lberiofns;
 530 
 531                 memset( &lberiofns, 0, sizeof( lberiofns ));
 532 
 533                 lberiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
 534                 lberiofns.lbextiofn_read = ld->ld_extread_fn;
 535                 lberiofns.lbextiofn_write = ld->ld_extwrite_fn;
 536                 lberiofns.lbextiofn_writev = ld->ld_extwritev_fn;
 537                 lberiofns.lbextiofn_socket_arg = NULL;
 538                 ber_sockbuf_set_option( ld->ld_sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
 539                         (void *)&lberiofns );
 540         }
 541 
 542 #ifdef _SOLARIS_SDK
 543         /* Install the functions for IPv6 support       */
 544         /* code sequencing is critical from here to nsldapi_mutex_alloc_all */
 545         if ( prldap_install_thread_functions( ld, 1 ) != 0 ||
 546              prldap_install_io_functions( ld, 1 ) != 0 ||
 547              prldap_install_dns_functions( ld ) != 0 ) {
 548                 /* go through ld and free resources */
 549                 ldap_unbind( ld );
 550                 ld = NULL;
 551                 return( NULL );
 552         }
 553 #else
 554 
 555         /* allocate mutexes */
 556         nsldapi_mutex_alloc_all( ld );
 557 #endif
 558 
 559         /* set default port */
 560         ld->ld_defport = ( defport == 0 ) ? LDAP_PORT : defport;
 561 
 562         return( ld );
 563 }
 564 
 565 void
 566 nsldapi_mutex_alloc_all( LDAP *ld )
 567 {
 568         int     i;
 569 
 570         if ( ld != &nsldapi_ld_defaults && ld->ld_mutex != NULL ) {
 571                 for ( i = 0; i<LDAP_MAX_LOCK; i++ ) {
 572                         ld->ld_mutex[i] = LDAP_MUTEX_ALLOC( ld );
 573                         ld->ld_mutex_threadid[i] = (void *) -1;
 574                         ld->ld_mutex_refcnt[i] = 0;
 575                 }
 576         }
 577 }
 578 
 579 
 580 void
 581 nsldapi_mutex_free_all( LDAP *ld )
 582 {
 583         int     i;
 584 
 585         if ( ld != &nsldapi_ld_defaults && ld->ld_mutex != NULL ) {
 586                 for ( i = 0; i<LDAP_MAX_LOCK; i++ ) {
 587                         LDAP_MUTEX_FREE( ld, ld->ld_mutex[i] );
 588                 }
 589         }
 590 }
 591 
 592 /* returns 0 if connection opened and -1 if an error occurs */
 593 int
 594 nsldapi_open_ldap_defconn( LDAP *ld )
 595 {
 596         LDAPServer      *srv;
 597 
 598         if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1, sizeof( LDAPServer ))) ==
 599             NULL || ( ld->ld_defhost != NULL && ( srv->lsrv_host =
 600             nsldapi_strdup( ld->ld_defhost )) == NULL )) {
 601                 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
 602                 return( -1 );
 603         }
 604         srv->lsrv_port = ld->ld_defport;
 605 
 606 #ifdef LDAP_SSLIO_HOOKS
 607         if (( ld->ld_options & LDAP_BITOPT_SSL ) != 0 ) {
 608                 srv->lsrv_options |= LDAP_SRV_OPT_SECURE;
 609         }
 610 #endif
 611 
 612         if (( ld->ld_defconn = nsldapi_new_connection( ld, &srv, 1, 1, 0 ))
 613             == NULL ) {
 614                 if ( ld->ld_defhost != NULL ) {
 615                         NSLDAPI_FREE( srv->lsrv_host );
 616                 }
 617                 NSLDAPI_FREE( (char *)srv );
 618                 return( -1 );
 619         }
 620         ++ld->ld_defconn->lconn_refcnt;   /* so it never gets closed/freed */
 621 
 622         return( 0 );
 623 }
 624 
 625 
 626 struct ldap_x_hostlist_status {
 627         char    *lhs_hostlist;
 628         char    *lhs_nexthost;
 629         int     lhs_defport;
 630 };
 631 
 632 /*
 633  * Return the first host and port in hostlist (setting *hostp and *portp).
 634  * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
 635  * Note that a NULL or zero-length hostlist causes the host "127.0.0.1" to
 636  * be returned.
 637  */
 638 int LDAP_CALL
 639 ldap_x_hostlist_first( const char *hostlist, int defport, char **hostp,
 640     int *portp, struct ldap_x_hostlist_status **statusp )
 641 {
 642 
 643         if ( NULL == hostp || NULL == portp || NULL == statusp ) {
 644                 return( LDAP_PARAM_ERROR );
 645         }
 646 
 647         if ( NULL == hostlist || *hostlist == '\0' ) {
 648                 *hostp = nsldapi_strdup( "127.0.0.1" );
 649                 if ( NULL == *hostp ) {
 650                         return( LDAP_NO_MEMORY );
 651                 }
 652                 *portp = defport;
 653                 *statusp = NULL;
 654                 return( LDAP_SUCCESS );
 655         }
 656 
 657         *statusp = NSLDAPI_CALLOC( 1, sizeof( struct ldap_x_hostlist_status ));
 658         if ( NULL == *statusp ) {
 659                 return( LDAP_NO_MEMORY );
 660         }
 661         (*statusp)->lhs_hostlist = nsldapi_strdup( hostlist );
 662         if ( NULL == (*statusp)->lhs_hostlist ) {
 663                 return( LDAP_NO_MEMORY );
 664         }
 665         (*statusp)->lhs_nexthost = (*statusp)->lhs_hostlist;
 666         (*statusp)->lhs_defport = defport;
 667         return( ldap_x_hostlist_next( hostp, portp, *statusp ));
 668 }
 669 
 670 /*
 671  * Return the next host and port in hostlist (setting *hostp and *portp).
 672  * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
 673  * If no more hosts are available, LDAP_SUCCESS is returned but *hostp is set
 674  * to NULL.
 675  */
 676 int LDAP_CALL
 677 ldap_x_hostlist_next( char **hostp, int *portp,
 678         struct ldap_x_hostlist_status *status )
 679 {
 680         char    *q;
 681         int             squarebrackets = 0;
 682 
 683         if ( NULL == hostp || NULL == portp ) {
 684                 return( LDAP_PARAM_ERROR );
 685         }
 686 
 687         if ( NULL == status || NULL == status->lhs_nexthost ) {
 688                 *hostp = NULL;
 689                 return( LDAP_SUCCESS );
 690         }
 691 
 692         /*
 693          * skip past leading '[' if present (IPv6 addresses may be surrounded
 694          * with square brackets, e.g., [fe80::a00:20ff:fee5:c0b4]:389
 695          */
 696         if ( status->lhs_nexthost[0] == '[' ) {
 697                 ++status->lhs_nexthost;
 698                 squarebrackets = 1;
 699         }
 700 
 701         /* copy host into *hostp */
 702         if ( NULL != ( q = strchr( status->lhs_nexthost, ' ' ))) {
 703                 size_t  len = q - status->lhs_nexthost;
 704                 *hostp = NSLDAPI_MALLOC( len + 1 );
 705                 if ( NULL == *hostp ) {
 706                         return( LDAP_NO_MEMORY );
 707                 }
 708                 strncpy( *hostp, status->lhs_nexthost, len );
 709                 (*hostp)[len] = '\0';
 710                 status->lhs_nexthost += ( len + 1 );
 711         } else {        /* last host */
 712                 *hostp = nsldapi_strdup( status->lhs_nexthost );
 713                 if ( NULL == *hostp ) {
 714                         return( LDAP_NO_MEMORY );
 715                 }
 716                 status->lhs_nexthost = NULL;
 717         }
 718 
 719         /* 
 720          * Look for closing ']' and skip past it before looking for port.
 721          */
 722         if ( squarebrackets && NULL != ( q = strchr( *hostp, ']' ))) {
 723                 *q++ = '\0';
 724         } else {
 725                 q = *hostp;
 726         }
 727 
 728         /* determine and set port */
 729         if ( NULL != ( q = strchr( q, ':' ))) {
 730                 *q++ = '\0';
 731                 *portp = atoi( q );
 732         } else {
 733                 *portp = status->lhs_defport;
 734         }
 735 
 736         return( LDAP_SUCCESS );
 737 }
 738 
 739 
 740 void LDAP_CALL
 741 ldap_x_hostlist_statusfree( struct ldap_x_hostlist_status *status )
 742 {
 743         if ( NULL != status ) {
 744                 if ( NULL != status->lhs_hostlist ) {
 745                         NSLDAPI_FREE( status->lhs_hostlist );
 746                 }
 747                 NSLDAPI_FREE( status );
 748         }
 749 }
 750 
 751 
 752 
 753 /*
 754  * memory allocation functions.  we include these in open.c since every
 755  *    LDAP application is likely to pull the rest of the code in this file
 756  *    in anyways.
 757  */
 758 void *
 759 ldap_x_malloc( size_t size )
 760 {
 761         return( nsldapi_memalloc_fns.ldapmem_malloc == NULL ?
 762             malloc( size ) :
 763             nsldapi_memalloc_fns.ldapmem_malloc( size ));
 764 }
 765 
 766 
 767 void *
 768 ldap_x_calloc( size_t nelem, size_t elsize )
 769 {
 770         return( nsldapi_memalloc_fns.ldapmem_calloc == NULL ?
 771             calloc(  nelem, elsize ) :
 772             nsldapi_memalloc_fns.ldapmem_calloc( nelem, elsize ));
 773 }
 774 
 775 
 776 void *
 777 ldap_x_realloc( void *ptr, size_t size )
 778 {
 779         return( nsldapi_memalloc_fns.ldapmem_realloc == NULL ?
 780             realloc( ptr, size ) :
 781             nsldapi_memalloc_fns.ldapmem_realloc( ptr, size ));
 782 }
 783 
 784 
 785 void
 786 ldap_x_free( void *ptr )
 787 {
 788         if ( nsldapi_memalloc_fns.ldapmem_free == NULL ) {
 789                 free( ptr );
 790         } else {
 791                 nsldapi_memalloc_fns.ldapmem_free( ptr );
 792         }
 793 }
 794 
 795 
 796 /* if s is NULL, returns NULL */
 797 char *
 798 nsldapi_strdup( const char *s )
 799 {
 800         char    *p;
 801 
 802         if ( s == NULL ||
 803             (p = (char *)NSLDAPI_MALLOC( strlen( s ) + 1 )) == NULL )
 804                 return( NULL );
 805 
 806         strcpy( p, s );
 807 
 808         return( p );
 809 }