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
pthread_mutex_init(LDAP_MUTEX_T * mp,void * attr)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 *
pthread_mutex_alloc(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
pthread_mutex_destroy(LDAP_MUTEX_T * mp)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
pthread_mutex_free(void * mutexp)123 pthread_mutex_free( void *mutexp )
124 {
125 pthread_mutex_destroy( (LDAP_MUTEX_T *) mutexp );
126 free( mutexp );
127 }
128
129 int
pthread_mutex_lock(LDAP_MUTEX_T * mp)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
pthread_mutex_unlock(LDAP_MUTEX_T * mp)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
get_errno(void)148 get_errno( void )
149 {
150 return errno;
151 }
152
153 static void
set_errno(int Errno)154 set_errno( int Errno )
155 {
156 errno = Errno;
157 }
158
159 static int
get_ld_error(char ** LDMatched,char ** LDError,void * Args)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
set_ld_error(int LDErrno,char * LDMatched,char * LDError,void * Args)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 *
pthread_mutex_alloc(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
pthread_mutex_free(void * mutexp)204 pthread_mutex_free( void *mutexp )
205 {
206 pthread_mutex_destroy( (pthread_mutex_t *) mutexp );
207 free( mutexp );
208 }
209
210 static void
set_ld_error(int err,char * matched,char * errmsg,void * dummy)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
get_ld_error(char ** matched,char ** errmsg,void * dummy)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
set_errno(int err)267 set_errno( int err )
268 {
269 errno = err;
270 }
271
272 static int
get_errno(void)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
nsldapi_initialize_defaults(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
ldap_version(LDAPVersion * ver)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
ldap_open(const char * host,int port)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
ldap_init(const char * defhost,int defport)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
nsldapi_mutex_alloc_all(LDAP * ld)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
nsldapi_mutex_free_all(LDAP * ld)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
nsldapi_open_ldap_defconn(LDAP * ld)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
ldap_x_hostlist_first(const char * hostlist,int defport,char ** hostp,int * portp,struct ldap_x_hostlist_status ** statusp)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
ldap_x_hostlist_next(char ** hostp,int * portp,struct ldap_x_hostlist_status * status)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
ldap_x_hostlist_statusfree(struct ldap_x_hostlist_status * status)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 *
ldap_x_malloc(size_t size)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 *
ldap_x_calloc(size_t nelem,size_t elsize)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 *
ldap_x_realloc(void * ptr,size_t size)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
ldap_x_free(void * ptr)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 *
nsldapi_strdup(const char * s)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 }
810