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                 ver->security_level = 128;
 405 #endif
 406 
 407         }
 408         return (int)(VI_PRODUCTVERSION * 100);
 409 }
 410 
 411 /*
 412  * ldap_open - initialize and connect to an ldap server.  A magic cookie to
 413  * be used for future communication is returned on success, NULL on failure.
 414  * "host" may be a space-separated list of hosts or IP addresses
 415  *
 416  * Example:
 417  *      LDAP    *ld;
 418  *      ld = ldap_open( hostname, port );
 419  */
 420 
 421 LDAP *
 422 LDAP_CALL
 423 ldap_open( const char *host, int port )
 424 {
 425         LDAP    *ld;
 426 
 427         LDAPDebug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
 428 
 429         if (( ld = ldap_init( host, port )) == NULL ) {
 430                 return( NULL );
 431         }
 432 
 433         LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
 434         if ( nsldapi_open_ldap_defconn( ld ) < 0 ) {
 435                 LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
 436                 ldap_ld_free( ld, NULL, NULL, 0 );
 437                 return( NULL );
 438         }
 439 
 440         LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
 441         LDAPDebug( LDAP_DEBUG_TRACE, "ldap_open successful, ld_host is %s\n",
 442                 ( ld->ld_host == NULL ) ? "(null)" : ld->ld_host, 0, 0 );
 443 
 444         return( ld );
 445 }
 446 
 447 
 448 /*
 449  * ldap_init - initialize the LDAP library.  A magic cookie to be used for
 450  * future communication is returned on success, NULL on failure.
 451  * "defhost" may be a space-separated list of hosts or IP addresses
 452  *
 453  * Example:
 454  *      LDAP    *ld;
 455  *      ld = ldap_init( default_hostname, default_port );
 456  */
 457 LDAP *
 458 LDAP_CALL
 459 ldap_init( const char *defhost, int defport )
 460 {
 461         LDAP    *ld;
 462 
 463         if ( !nsldapi_initialized ) {
 464                 nsldapi_initialize_defaults();
 465         }
 466 
 467         if ( defport < 0 || defport > LDAP_PORT_MAX ) {
 468             LDAPDebug( LDAP_DEBUG_ANY,
 469                     "ldap_init: port %d is invalid (port numbers must range from 1 to %d)\n",
 470                     defport, LDAP_PORT_MAX, 0 );
 471 #if !defined( macintosh ) && !defined( DOS )
 472             errno = EINVAL;
 473 #endif
 474             return( NULL );
 475         }
 476 
 477         LDAPDebug( LDAP_DEBUG_TRACE, "ldap_init\n", 0, 0, 0 );
 478 
 479         if ( (ld = (LDAP*)NSLDAPI_MALLOC( sizeof(struct ldap) )) == NULL ) {
 480                 return( NULL );
 481         }
 482 
 483         /* copy defaults */
 484         SAFEMEMCPY( ld, &nsldapi_ld_defaults, sizeof( struct ldap ));
 485         if ( nsldapi_ld_defaults.ld_io_fns_ptr != NULL ) {
 486                 if (( ld->ld_io_fns_ptr = (struct ldap_io_fns *)NSLDAPI_MALLOC(
 487                     sizeof( struct ldap_io_fns ))) == NULL ) {
 488                         NSLDAPI_FREE( (char *)ld );
 489                         return( NULL );
 490                 }
 491                 /* struct copy */
 492                 *(ld->ld_io_fns_ptr) = *(nsldapi_ld_defaults.ld_io_fns_ptr);
 493         }
 494 
 495         /* call the new handle I/O callback if one is defined */
 496         if ( ld->ld_extnewhandle_fn != NULL ) {
 497                 /*
 498                  * We always pass the session extended I/O argument to
 499                  * the new handle callback.
 500                  */
 501                 if ( ld->ld_extnewhandle_fn( ld, ld->ld_ext_session_arg )
 502                     != LDAP_SUCCESS ) {
 503                         NSLDAPI_FREE( (char*)ld );
 504                         return( NULL );
 505                 }
 506         }
 507 
 508         /* allocate session-specific resources */
 509         if (( ld->ld_sbp = ber_sockbuf_alloc()) == NULL ||
 510             ( defhost != NULL &&
 511             ( ld->ld_defhost = nsldapi_strdup( defhost )) == NULL ) ||
 512             ((ld->ld_mutex = (void **) NSLDAPI_CALLOC( LDAP_MAX_LOCK, sizeof(void *))) == NULL )) {
 513                 if ( ld->ld_sbp != NULL ) {
 514                         ber_sockbuf_free( ld->ld_sbp );
 515                 }
 516                 if( ld->ld_mutex != NULL ) {
 517                         NSLDAPI_FREE( ld->ld_mutex );
 518                 }
 519                 NSLDAPI_FREE( (char*)ld );
 520                 return( NULL );
 521         }
 522 
 523         /* install Sockbuf I/O functions if set in LDAP * */
 524         if ( ld->ld_extread_fn != NULL || ld->ld_extwrite_fn != NULL ) {
 525                 struct lber_x_ext_io_fns lberiofns;
 526 
 527                 memset( &lberiofns, 0, sizeof( lberiofns ));
 528 
 529                 lberiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
 530                 lberiofns.lbextiofn_read = ld->ld_extread_fn;
 531                 lberiofns.lbextiofn_write = ld->ld_extwrite_fn;
 532                 lberiofns.lbextiofn_writev = ld->ld_extwritev_fn;
 533                 lberiofns.lbextiofn_socket_arg = NULL;
 534                 ber_sockbuf_set_option( ld->ld_sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
 535                         (void *)&lberiofns );
 536         }
 537 
 538 #ifdef _SOLARIS_SDK
 539         /* Install the functions for IPv6 support       */
 540         /* code sequencing is critical from here to nsldapi_mutex_alloc_all */
 541         if ( prldap_install_thread_functions( ld, 1 ) != 0 ||
 542              prldap_install_io_functions( ld, 1 ) != 0 ||
 543              prldap_install_dns_functions( ld ) != 0 ) {
 544                 /* go through ld and free resources */
 545                 ldap_unbind( ld );
 546                 ld = NULL;
 547                 return( NULL );
 548         }
 549 #else
 550 
 551         /* allocate mutexes */
 552         nsldapi_mutex_alloc_all( ld );
 553 #endif
 554 
 555         /* set default port */
 556         ld->ld_defport = ( defport == 0 ) ? LDAP_PORT : defport;
 557 
 558         return( ld );
 559 }
 560 
 561 void
 562 nsldapi_mutex_alloc_all( LDAP *ld )
 563 {
 564         int     i;
 565 
 566         if ( ld != &nsldapi_ld_defaults && ld->ld_mutex != NULL ) {
 567                 for ( i = 0; i<LDAP_MAX_LOCK; i++ ) {
 568                         ld->ld_mutex[i] = LDAP_MUTEX_ALLOC( ld );
 569                         ld->ld_mutex_threadid[i] = (void *) -1;
 570                         ld->ld_mutex_refcnt[i] = 0;
 571                 }
 572         }
 573 }
 574 
 575 
 576 void
 577 nsldapi_mutex_free_all( LDAP *ld )
 578 {
 579         int     i;
 580 
 581         if ( ld != &nsldapi_ld_defaults && ld->ld_mutex != NULL ) {
 582                 for ( i = 0; i<LDAP_MAX_LOCK; i++ ) {
 583                         LDAP_MUTEX_FREE( ld, ld->ld_mutex[i] );
 584                 }
 585         }
 586 }
 587 
 588 /* returns 0 if connection opened and -1 if an error occurs */
 589 int
 590 nsldapi_open_ldap_defconn( LDAP *ld )
 591 {
 592         LDAPServer      *srv;
 593 
 594         if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1, sizeof( LDAPServer ))) ==
 595             NULL || ( ld->ld_defhost != NULL && ( srv->lsrv_host =
 596             nsldapi_strdup( ld->ld_defhost )) == NULL )) {
 597                 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
 598                 return( -1 );
 599         }
 600         srv->lsrv_port = ld->ld_defport;
 601 
 602 #ifdef LDAP_SSLIO_HOOKS
 603         if (( ld->ld_options & LDAP_BITOPT_SSL ) != 0 ) {
 604                 srv->lsrv_options |= LDAP_SRV_OPT_SECURE;
 605         }
 606 #endif
 607 
 608         if (( ld->ld_defconn = nsldapi_new_connection( ld, &srv, 1, 1, 0 ))
 609             == NULL ) {
 610                 if ( ld->ld_defhost != NULL ) {
 611                         NSLDAPI_FREE( srv->lsrv_host );
 612                 }
 613                 NSLDAPI_FREE( (char *)srv );
 614                 return( -1 );
 615         }
 616         ++ld->ld_defconn->lconn_refcnt;   /* so it never gets closed/freed */
 617 
 618         return( 0 );
 619 }
 620 
 621 
 622 struct ldap_x_hostlist_status {
 623         char    *lhs_hostlist;
 624         char    *lhs_nexthost;
 625         int     lhs_defport;
 626 };
 627 
 628 /*
 629  * Return the first host and port in hostlist (setting *hostp and *portp).
 630  * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
 631  * Note that a NULL or zero-length hostlist causes the host "127.0.0.1" to
 632  * be returned.
 633  */
 634 int LDAP_CALL
 635 ldap_x_hostlist_first( const char *hostlist, int defport, char **hostp,
 636     int *portp, struct ldap_x_hostlist_status **statusp )
 637 {
 638 
 639         if ( NULL == hostp || NULL == portp || NULL == statusp ) {
 640                 return( LDAP_PARAM_ERROR );
 641         }
 642 
 643         if ( NULL == hostlist || *hostlist == '\0' ) {
 644                 *hostp = nsldapi_strdup( "127.0.0.1" );
 645                 if ( NULL == *hostp ) {
 646                         return( LDAP_NO_MEMORY );
 647                 }
 648                 *portp = defport;
 649                 *statusp = NULL;
 650                 return( LDAP_SUCCESS );
 651         }
 652 
 653         *statusp = NSLDAPI_CALLOC( 1, sizeof( struct ldap_x_hostlist_status ));
 654         if ( NULL == *statusp ) {
 655                 return( LDAP_NO_MEMORY );
 656         }
 657         (*statusp)->lhs_hostlist = nsldapi_strdup( hostlist );
 658         if ( NULL == (*statusp)->lhs_hostlist ) {
 659                 return( LDAP_NO_MEMORY );
 660         }
 661         (*statusp)->lhs_nexthost = (*statusp)->lhs_hostlist;
 662         (*statusp)->lhs_defport = defport;
 663         return( ldap_x_hostlist_next( hostp, portp, *statusp ));
 664 }
 665 
 666 /*
 667  * Return the next host and port in hostlist (setting *hostp and *portp).
 668  * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
 669  * If no more hosts are available, LDAP_SUCCESS is returned but *hostp is set
 670  * to NULL.
 671  */
 672 int LDAP_CALL
 673 ldap_x_hostlist_next( char **hostp, int *portp,
 674         struct ldap_x_hostlist_status *status )
 675 {
 676         char    *q;
 677         int             squarebrackets = 0;
 678 
 679         if ( NULL == hostp || NULL == portp ) {
 680                 return( LDAP_PARAM_ERROR );
 681         }
 682 
 683         if ( NULL == status || NULL == status->lhs_nexthost ) {
 684                 *hostp = NULL;
 685                 return( LDAP_SUCCESS );
 686         }
 687 
 688         /*
 689          * skip past leading '[' if present (IPv6 addresses may be surrounded
 690          * with square brackets, e.g., [fe80::a00:20ff:fee5:c0b4]:389
 691          */
 692         if ( status->lhs_nexthost[0] == '[' ) {
 693                 ++status->lhs_nexthost;
 694                 squarebrackets = 1;
 695         }
 696 
 697         /* copy host into *hostp */
 698         if ( NULL != ( q = strchr( status->lhs_nexthost, ' ' ))) {
 699                 size_t  len = q - status->lhs_nexthost;
 700                 *hostp = NSLDAPI_MALLOC( len + 1 );
 701                 if ( NULL == *hostp ) {
 702                         return( LDAP_NO_MEMORY );
 703                 }
 704                 strncpy( *hostp, status->lhs_nexthost, len );
 705                 (*hostp)[len] = '\0';
 706                 status->lhs_nexthost += ( len + 1 );
 707         } else {        /* last host */
 708                 *hostp = nsldapi_strdup( status->lhs_nexthost );
 709                 if ( NULL == *hostp ) {
 710                         return( LDAP_NO_MEMORY );
 711                 }
 712                 status->lhs_nexthost = NULL;
 713         }
 714 
 715         /* 
 716          * Look for closing ']' and skip past it before looking for port.
 717          */
 718         if ( squarebrackets && NULL != ( q = strchr( *hostp, ']' ))) {
 719                 *q++ = '\0';
 720         } else {
 721                 q = *hostp;
 722         }
 723 
 724         /* determine and set port */
 725         if ( NULL != ( q = strchr( q, ':' ))) {
 726                 *q++ = '\0';
 727                 *portp = atoi( q );
 728         } else {
 729                 *portp = status->lhs_defport;
 730         }
 731 
 732         return( LDAP_SUCCESS );
 733 }
 734 
 735 
 736 void LDAP_CALL
 737 ldap_x_hostlist_statusfree( struct ldap_x_hostlist_status *status )
 738 {
 739         if ( NULL != status ) {
 740                 if ( NULL != status->lhs_hostlist ) {
 741                         NSLDAPI_FREE( status->lhs_hostlist );
 742                 }
 743                 NSLDAPI_FREE( status );
 744         }
 745 }
 746 
 747 
 748 
 749 /*
 750  * memory allocation functions.  we include these in open.c since every
 751  *    LDAP application is likely to pull the rest of the code in this file
 752  *    in anyways.
 753  */
 754 void *
 755 ldap_x_malloc( size_t size )
 756 {
 757         return( nsldapi_memalloc_fns.ldapmem_malloc == NULL ?
 758             malloc( size ) :
 759             nsldapi_memalloc_fns.ldapmem_malloc( size ));
 760 }
 761 
 762 
 763 void *
 764 ldap_x_calloc( size_t nelem, size_t elsize )
 765 {
 766         return( nsldapi_memalloc_fns.ldapmem_calloc == NULL ?
 767             calloc(  nelem, elsize ) :
 768             nsldapi_memalloc_fns.ldapmem_calloc( nelem, elsize ));
 769 }
 770 
 771 
 772 void *
 773 ldap_x_realloc( void *ptr, size_t size )
 774 {
 775         return( nsldapi_memalloc_fns.ldapmem_realloc == NULL ?
 776             realloc( ptr, size ) :
 777             nsldapi_memalloc_fns.ldapmem_realloc( ptr, size ));
 778 }
 779 
 780 
 781 void
 782 ldap_x_free( void *ptr )
 783 {
 784         if ( nsldapi_memalloc_fns.ldapmem_free == NULL ) {
 785                 free( ptr );
 786         } else {
 787                 nsldapi_memalloc_fns.ldapmem_free( ptr );
 788         }
 789 }
 790 
 791 
 792 /* if s is NULL, returns NULL */
 793 char *
 794 nsldapi_strdup( const char *s )
 795 {
 796         char    *p;
 797 
 798         if ( s == NULL ||
 799             (p = (char *)NSLDAPI_MALLOC( strlen( s ) + 1 )) == NULL )
 800                 return( NULL );
 801 
 802         strcpy( p, s );
 803 
 804         return( p );
 805 }