2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
8 * The contents of this file are subject to the Netscape Public
9 * License Version 1.1 (the "License"); you may not use this file
10 * except in compliance with the License. You may obtain a copy of
11 * the License at http://www.mozilla.org/NPL/
13 * Software distributed under the License is distributed on an "AS
14 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15 * implied. See the License for the specific language governing
16 * rights and limitations under the License.
18 * The Original Code is Mozilla Communicator client code, released
21 * The Initial Developer of the Original Code is Netscape
22 * Communications Corporation. Portions created by Netscape are
23 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
29 * Copyright (c) 1995 Regents of the University of Michigan.
30 * All rights reserved.
38 static char copyright
[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
43 #ifdef LDAP_SASLIO_HOOKS
44 /* Valid for any ANSI C compiler */
48 #define VI_PRODUCTVERSION 3
50 #ifndef INADDR_LOOPBACK
51 #define INADDR_LOOPBACK ((unsigned long) 0x7f000001)
54 #ifndef MAXHOSTNAMELEN
55 #define MAXHOSTNAMELEN 64
64 * global defaults for callbacks are stored here. callers of the API set
65 * these by passing a NULL "ld" to ldap_set_option(). Everything in
66 * nsldapi_ld_defaults can be overridden on a per-ld basis as well (the
67 * memory allocation functions are global to all ld's).
69 struct ldap nsldapi_ld_defaults
;
70 struct ldap_memalloc_fns nsldapi_memalloc_fns
= { 0, 0, 0, 0 };
71 int nsldapi_initialized
= 0;
75 static pthread_key_t nsldapi_key
;
77 struct nsldapi_ldap_error
{
83 __declspec ( thread
) int nsldapi_gldaperrno
;
84 __declspec ( thread
) char *nsldapi_gmatched
= NULL
;
85 __declspec ( thread
) char *nsldapi_gldaperror
= NULL
;
89 #define LDAP_MUTEX_T HANDLE
92 pthread_mutex_init( LDAP_MUTEX_T
*mp
, void *attr
)
94 if ( (*mp
= CreateMutex(NULL
, FALSE
, NULL
)) == NULL
)
101 pthread_mutex_alloc( void )
103 LDAP_MUTEX_T
*mutexp
;
105 if ( (mutexp
= malloc( sizeof(LDAP_MUTEX_T
) )) != NULL
) {
106 pthread_mutex_init( mutexp
, NULL
);
112 pthread_mutex_destroy( LDAP_MUTEX_T
*mp
)
114 if ( !(CloseHandle(*mp
)) )
121 pthread_mutex_free( void *mutexp
)
123 pthread_mutex_destroy( (LDAP_MUTEX_T
*) mutexp
);
128 pthread_mutex_lock( LDAP_MUTEX_T
*mp
)
130 if ( (WaitForSingleObject(*mp
, INFINITE
) != WAIT_OBJECT_0
) )
137 pthread_mutex_unlock( LDAP_MUTEX_T
*mp
)
139 if ( !(ReleaseMutex(*mp
)) )
152 set_errno( int Errno
)
158 get_ld_error( char **LDMatched
, char **LDError
, void * Args
)
160 if ( LDMatched
!= NULL
)
162 *LDMatched
= nsldapi_gmatched
;
164 if ( LDError
!= NULL
)
166 *LDError
= nsldapi_gldaperror
;
168 return nsldapi_gldaperrno
;
172 set_ld_error( int LDErrno
, char * LDMatched
, char * LDError
,
175 /* Clean up any previous string storage. */
176 if ( nsldapi_gmatched
!= NULL
)
178 ldap_memfree( nsldapi_gmatched
);
180 if ( nsldapi_gldaperror
!= NULL
)
182 ldap_memfree( nsldapi_gldaperror
);
185 nsldapi_gldaperrno
= LDErrno
;
186 nsldapi_gmatched
= LDMatched
;
187 nsldapi_gldaperror
= LDError
;
191 pthread_mutex_alloc( void )
193 pthread_mutex_t
*mutexp
;
195 if ( (mutexp
= malloc( sizeof(pthread_mutex_t
) )) != NULL
) {
196 pthread_mutex_init( mutexp
, NULL
);
202 pthread_mutex_free( void *mutexp
)
204 pthread_mutex_destroy( (pthread_mutex_t
*) mutexp
);
209 set_ld_error( int err
, char *matched
, char *errmsg
, void *dummy
)
211 struct nsldapi_ldap_error
*le
;
214 le
= pthread_getspecific( nsldapi_key
);
217 tsd
= (void *)calloc(1, sizeof(struct nsldapi_ldap_error
));
218 pthread_setspecific( nsldapi_key
, tsd
);
221 le
= pthread_getspecific( nsldapi_key
);
230 if ( le
->le_matched
!= NULL
) {
231 ldap_memfree( le
->le_matched
);
233 le
->le_matched
= matched
;
235 if ( le
->le_errmsg
!= NULL
) {
236 ldap_memfree( le
->le_errmsg
);
238 le
->le_errmsg
= errmsg
;
242 get_ld_error( char **matched
, char **errmsg
, void *dummy
)
244 struct nsldapi_ldap_error
*le
;
246 le
= pthread_getspecific( nsldapi_key
);
248 if ( matched
!= NULL
) {
249 *matched
= le
->le_matched
;
251 if ( errmsg
!= NULL
) {
252 *errmsg
= le
->le_errmsg
;
254 return( le
->le_errno
);
256 if ( matched
!= NULL
)
258 if ( errmsg
!= NULL
)
261 return (LDAP_SUCCESS
);
275 #endif /* _WINDOWS */
277 static struct ldap_thread_fns
278 nsldapi_default_thread_fns
= {
279 (void *(*)(void))pthread_mutex_alloc
,
280 (void (*)(void *))pthread_mutex_free
,
281 (int (*)(void *))pthread_mutex_lock
,
282 (int (*)(void *))pthread_mutex_unlock
,
283 (int (*)(void))get_errno
,
284 (void (*)(int))set_errno
,
285 (int (*)(char **, char **, void *))get_ld_error
,
286 (void (*)(int, char *, char *, void *))set_ld_error
,
289 static struct ldap_extra_thread_fns
290 nsldapi_default_extra_thread_fns
= {
295 (void *(*)(void))pthread_self
296 #endif /* _WINDOWS */
300 nsldapi_initialize_defaults( void )
303 if ( nsldapi_initialized
) {
308 * This has to be called before nsldapi_initialized is set to 1
309 * because nsldapi_initialized does not have mutex protection
315 if ( pthread_key_create(&nsldapi_key
, free
) != 0) {
316 perror("pthread_key_create");
318 #endif /* _WINDOWS */
320 nsldapi_initialized
= 1;
321 memset( &nsldapi_memalloc_fns
, 0, sizeof( nsldapi_memalloc_fns
));
322 memset( &nsldapi_ld_defaults
, 0, sizeof( nsldapi_ld_defaults
));
323 nsldapi_ld_defaults
.ld_options
= LDAP_BITOPT_REFERRALS
;
324 nsldapi_ld_defaults
.ld_version
= LDAP_VERSION2
;
325 nsldapi_ld_defaults
.ld_lberoptions
= LBER_OPT_USE_DER
;
326 nsldapi_ld_defaults
.ld_refhoplimit
= LDAP_DEFAULT_REFHOPLIMIT
;
328 #ifdef LDAP_SASLIO_HOOKS
329 /* SASL default option settings */
330 nsldapi_ld_defaults
.ld_def_sasl_mech
= NULL
;
331 nsldapi_ld_defaults
.ld_def_sasl_realm
= NULL
;
332 nsldapi_ld_defaults
.ld_def_sasl_authcid
= NULL
;
333 nsldapi_ld_defaults
.ld_def_sasl_authzid
= NULL
;
334 /* SASL Security properties */
335 nsldapi_ld_defaults
.ld_sasl_secprops
.max_ssf
= UINT_MAX
;
336 nsldapi_ld_defaults
.ld_sasl_secprops
.maxbufsize
= SASL_MAX_BUFF_SIZE
;
337 nsldapi_ld_defaults
.ld_sasl_secprops
.security_flags
=
338 SASL_SEC_NOPLAINTEXT
| SASL_SEC_NOANONYMOUS
;
341 #if defined( STR_TRANSLATION ) && defined( LDAP_DEFAULT_CHARSET )
342 nsldapi_ld_defaults
.ld_lberoptions
|= LBER_OPT_TRANSLATE_STRINGS
;
343 #if LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET
344 ldap_set_string_translators( &nsldapi_ld_defaults
, ldap_8859_to_t61
,
346 #endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */
347 #endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
349 /* set default connect timeout (in milliseconds) */
350 /* this was picked as it is the standard tcp timeout as well */
351 nsldapi_ld_defaults
.ld_connect_timeout
= LDAP_X_IO_TIMEOUT_NO_TIMEOUT
;
353 /* load up default platform specific locking routines */
354 if (ldap_set_option( NULL
, LDAP_OPT_THREAD_FN_PTRS
,
355 (void *)&nsldapi_default_thread_fns
) != LDAP_SUCCESS
) {
360 /* load up default threadid function */
361 if (ldap_set_option( NULL
, LDAP_OPT_EXTRA_THREAD_FN_PTRS
,
362 (void *)&nsldapi_default_extra_thread_fns
) != LDAP_SUCCESS
) {
365 #endif /* _WINDOWS */
370 * ldap_version - report version levels for important properties
371 * This function is deprecated. Use ldap_get_option( ..., LDAP_OPT_API_INFO,
376 * ldap_version( &ver );
377 * if ( (ver.sdk_version < 100) || (ver.SSL_version < 300) )
378 * fprintf( stderr, "LDAP SDK level insufficient\n" );
381 * if ( ldap_version(NULL) < 100 )
382 * fprintf( stderr, "LDAP SDK level insufficient\n" );
388 ldap_version( LDAPVersion
*ver
)
392 memset( ver
, 0, sizeof(*ver
) );
393 ver
->sdk_version
= (int)(VI_PRODUCTVERSION
* 100);
394 ver
->protocol_version
= LDAP_VERSION_MAX
* 100;
395 ver
->SSL_version
= SSL_VERSION
* 100;
397 * set security to none by default
400 ver
->security_level
= LDAP_SECURITY_NONE
;
401 #if defined(LINK_SSL)
402 ver
->security_level
= 128;
406 return (int)(VI_PRODUCTVERSION
* 100);
410 * ldap_open - initialize and connect to an ldap server. A magic cookie to
411 * be used for future communication is returned on success, NULL on failure.
412 * "host" may be a space-separated list of hosts or IP addresses
416 * ld = ldap_open( hostname, port );
421 ldap_open( const char *host
, int port
)
425 LDAPDebug( LDAP_DEBUG_TRACE
, "ldap_open\n", 0, 0, 0 );
427 if (( ld
= ldap_init( host
, port
)) == NULL
) {
431 LDAP_MUTEX_LOCK( ld
, LDAP_CONN_LOCK
);
432 if ( nsldapi_open_ldap_defconn( ld
) < 0 ) {
433 LDAP_MUTEX_UNLOCK( ld
, LDAP_CONN_LOCK
);
434 ldap_ld_free( ld
, NULL
, NULL
, 0 );
438 LDAP_MUTEX_UNLOCK( ld
, LDAP_CONN_LOCK
);
439 LDAPDebug( LDAP_DEBUG_TRACE
, "ldap_open successful, ld_host is %s\n",
440 ( ld
->ld_host
== NULL
) ? "(null)" : ld
->ld_host
, 0, 0 );
447 * ldap_init - initialize the LDAP library. A magic cookie to be used for
448 * future communication is returned on success, NULL on failure.
449 * "defhost" may be a space-separated list of hosts or IP addresses
453 * ld = ldap_init( default_hostname, default_port );
457 ldap_init( const char *defhost
, int defport
)
461 if ( !nsldapi_initialized
) {
462 nsldapi_initialize_defaults();
465 if ( defport
< 0 || defport
> LDAP_PORT_MAX
) {
466 LDAPDebug( LDAP_DEBUG_ANY
,
467 "ldap_init: port %d is invalid (port numbers must range from 1 to %d)\n",
468 defport
, LDAP_PORT_MAX
, 0 );
469 #if !defined( macintosh ) && !defined( DOS )
475 LDAPDebug( LDAP_DEBUG_TRACE
, "ldap_init\n", 0, 0, 0 );
477 if ( (ld
= (LDAP
*)NSLDAPI_MALLOC( sizeof(struct ldap
) )) == NULL
) {
482 SAFEMEMCPY( ld
, &nsldapi_ld_defaults
, sizeof( struct ldap
));
483 if ( nsldapi_ld_defaults
.ld_io_fns_ptr
!= NULL
) {
484 if (( ld
->ld_io_fns_ptr
= (struct ldap_io_fns
*)NSLDAPI_MALLOC(
485 sizeof( struct ldap_io_fns
))) == NULL
) {
486 NSLDAPI_FREE( (char *)ld
);
490 *(ld
->ld_io_fns_ptr
) = *(nsldapi_ld_defaults
.ld_io_fns_ptr
);
493 /* call the new handle I/O callback if one is defined */
494 if ( ld
->ld_extnewhandle_fn
!= NULL
) {
496 * We always pass the session extended I/O argument to
497 * the new handle callback.
499 if ( ld
->ld_extnewhandle_fn( ld
, ld
->ld_ext_session_arg
)
501 NSLDAPI_FREE( (char*)ld
);
506 /* allocate session-specific resources */
507 if (( ld
->ld_sbp
= ber_sockbuf_alloc()) == NULL
||
509 ( ld
->ld_defhost
= nsldapi_strdup( defhost
)) == NULL
) ||
510 ((ld
->ld_mutex
= (void **) NSLDAPI_CALLOC( LDAP_MAX_LOCK
, sizeof(void *))) == NULL
)) {
511 if ( ld
->ld_sbp
!= NULL
) {
512 ber_sockbuf_free( ld
->ld_sbp
);
514 if( ld
->ld_mutex
!= NULL
) {
515 NSLDAPI_FREE( ld
->ld_mutex
);
517 NSLDAPI_FREE( (char*)ld
);
521 /* install Sockbuf I/O functions if set in LDAP * */
522 if ( ld
->ld_extread_fn
!= NULL
|| ld
->ld_extwrite_fn
!= NULL
) {
523 struct lber_x_ext_io_fns lberiofns
;
525 memset( &lberiofns
, 0, sizeof( lberiofns
));
527 lberiofns
.lbextiofn_size
= LBER_X_EXTIO_FNS_SIZE
;
528 lberiofns
.lbextiofn_read
= ld
->ld_extread_fn
;
529 lberiofns
.lbextiofn_write
= ld
->ld_extwrite_fn
;
530 lberiofns
.lbextiofn_writev
= ld
->ld_extwritev_fn
;
531 lberiofns
.lbextiofn_socket_arg
= NULL
;
532 ber_sockbuf_set_option( ld
->ld_sbp
, LBER_SOCKBUF_OPT_EXT_IO_FNS
,
533 (void *)&lberiofns
);
537 /* Install the functions for IPv6 support */
538 /* code sequencing is critical from here to nsldapi_mutex_alloc_all */
539 if ( prldap_install_thread_functions( ld
, 1 ) != 0 ||
540 prldap_install_io_functions( ld
, 1 ) != 0 ||
541 prldap_install_dns_functions( ld
) != 0 ) {
542 /* go through ld and free resources */
549 /* allocate mutexes */
550 nsldapi_mutex_alloc_all( ld
);
553 /* set default port */
554 ld
->ld_defport
= ( defport
== 0 ) ? LDAP_PORT
: defport
;
560 nsldapi_mutex_alloc_all( LDAP
*ld
)
564 if ( ld
!= &nsldapi_ld_defaults
&& ld
->ld_mutex
!= NULL
) {
565 for ( i
= 0; i
<LDAP_MAX_LOCK
; i
++ ) {
566 ld
->ld_mutex
[i
] = LDAP_MUTEX_ALLOC( ld
);
567 ld
->ld_mutex_threadid
[i
] = (void *) -1;
568 ld
->ld_mutex_refcnt
[i
] = 0;
575 nsldapi_mutex_free_all( LDAP
*ld
)
579 if ( ld
!= &nsldapi_ld_defaults
&& ld
->ld_mutex
!= NULL
) {
580 for ( i
= 0; i
<LDAP_MAX_LOCK
; i
++ ) {
581 LDAP_MUTEX_FREE( ld
, ld
->ld_mutex
[i
] );
586 /* returns 0 if connection opened and -1 if an error occurs */
588 nsldapi_open_ldap_defconn( LDAP
*ld
)
592 if (( srv
= (LDAPServer
*)NSLDAPI_CALLOC( 1, sizeof( LDAPServer
))) ==
593 NULL
|| ( ld
->ld_defhost
!= NULL
&& ( srv
->lsrv_host
=
594 nsldapi_strdup( ld
->ld_defhost
)) == NULL
)) {
595 LDAP_SET_LDERRNO( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
598 srv
->lsrv_port
= ld
->ld_defport
;
600 #ifdef LDAP_SSLIO_HOOKS
601 if (( ld
->ld_options
& LDAP_BITOPT_SSL
) != 0 ) {
602 srv
->lsrv_options
|= LDAP_SRV_OPT_SECURE
;
606 if (( ld
->ld_defconn
= nsldapi_new_connection( ld
, &srv
, 1, 1, 0 ))
608 if ( ld
->ld_defhost
!= NULL
) {
609 NSLDAPI_FREE( srv
->lsrv_host
);
611 NSLDAPI_FREE( (char *)srv
);
614 ++ld
->ld_defconn
->lconn_refcnt
; /* so it never gets closed/freed */
620 struct ldap_x_hostlist_status
{
627 * Return the first host and port in hostlist (setting *hostp and *portp).
628 * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
629 * Note that a NULL or zero-length hostlist causes the host "127.0.0.1" to
633 ldap_x_hostlist_first( const char *hostlist
, int defport
, char **hostp
,
634 int *portp
, struct ldap_x_hostlist_status
**statusp
)
637 if ( NULL
== hostp
|| NULL
== portp
|| NULL
== statusp
) {
638 return( LDAP_PARAM_ERROR
);
641 if ( NULL
== hostlist
|| *hostlist
== '\0' ) {
642 *hostp
= nsldapi_strdup( "127.0.0.1" );
643 if ( NULL
== *hostp
) {
644 return( LDAP_NO_MEMORY
);
648 return( LDAP_SUCCESS
);
651 *statusp
= NSLDAPI_CALLOC( 1, sizeof( struct ldap_x_hostlist_status
));
652 if ( NULL
== *statusp
) {
653 return( LDAP_NO_MEMORY
);
655 (*statusp
)->lhs_hostlist
= nsldapi_strdup( hostlist
);
656 if ( NULL
== (*statusp
)->lhs_hostlist
) {
657 return( LDAP_NO_MEMORY
);
659 (*statusp
)->lhs_nexthost
= (*statusp
)->lhs_hostlist
;
660 (*statusp
)->lhs_defport
= defport
;
661 return( ldap_x_hostlist_next( hostp
, portp
, *statusp
));
665 * Return the next host and port in hostlist (setting *hostp and *portp).
666 * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
667 * If no more hosts are available, LDAP_SUCCESS is returned but *hostp is set
671 ldap_x_hostlist_next( char **hostp
, int *portp
,
672 struct ldap_x_hostlist_status
*status
)
675 int squarebrackets
= 0;
677 if ( NULL
== hostp
|| NULL
== portp
) {
678 return( LDAP_PARAM_ERROR
);
681 if ( NULL
== status
|| NULL
== status
->lhs_nexthost
) {
683 return( LDAP_SUCCESS
);
687 * skip past leading '[' if present (IPv6 addresses may be surrounded
688 * with square brackets, e.g., [fe80::a00:20ff:fee5:c0b4]:389
690 if ( status
->lhs_nexthost
[0] == '[' ) {
691 ++status
->lhs_nexthost
;
695 /* copy host into *hostp */
696 if ( NULL
!= ( q
= strchr( status
->lhs_nexthost
, ' ' ))) {
697 size_t len
= q
- status
->lhs_nexthost
;
698 *hostp
= NSLDAPI_MALLOC( len
+ 1 );
699 if ( NULL
== *hostp
) {
700 return( LDAP_NO_MEMORY
);
702 strncpy( *hostp
, status
->lhs_nexthost
, len
);
703 (*hostp
)[len
] = '\0';
704 status
->lhs_nexthost
+= ( len
+ 1 );
705 } else { /* last host */
706 *hostp
= nsldapi_strdup( status
->lhs_nexthost
);
707 if ( NULL
== *hostp
) {
708 return( LDAP_NO_MEMORY
);
710 status
->lhs_nexthost
= NULL
;
714 * Look for closing ']' and skip past it before looking for port.
716 if ( squarebrackets
&& NULL
!= ( q
= strchr( *hostp
, ']' ))) {
722 /* determine and set port */
723 if ( NULL
!= ( q
= strchr( q
, ':' ))) {
727 *portp
= status
->lhs_defport
;
730 return( LDAP_SUCCESS
);
735 ldap_x_hostlist_statusfree( struct ldap_x_hostlist_status
*status
)
737 if ( NULL
!= status
) {
738 if ( NULL
!= status
->lhs_hostlist
) {
739 NSLDAPI_FREE( status
->lhs_hostlist
);
741 NSLDAPI_FREE( status
);
748 * memory allocation functions. we include these in open.c since every
749 * LDAP application is likely to pull the rest of the code in this file
753 ldap_x_malloc( size_t size
)
755 return( nsldapi_memalloc_fns
.ldapmem_malloc
== NULL
?
757 nsldapi_memalloc_fns
.ldapmem_malloc( size
));
762 ldap_x_calloc( size_t nelem
, size_t elsize
)
764 return( nsldapi_memalloc_fns
.ldapmem_calloc
== NULL
?
765 calloc( nelem
, elsize
) :
766 nsldapi_memalloc_fns
.ldapmem_calloc( nelem
, elsize
));
771 ldap_x_realloc( void *ptr
, size_t size
)
773 return( nsldapi_memalloc_fns
.ldapmem_realloc
== NULL
?
774 realloc( ptr
, size
) :
775 nsldapi_memalloc_fns
.ldapmem_realloc( ptr
, size
));
780 ldap_x_free( void *ptr
)
782 if ( nsldapi_memalloc_fns
.ldapmem_free
== NULL
) {
785 nsldapi_memalloc_fns
.ldapmem_free( ptr
);
790 /* if s is NULL, returns NULL */
792 nsldapi_strdup( const char *s
)
797 (p
= (char *)NSLDAPI_MALLOC( strlen( s
) + 1 )) == NULL
)