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.
37 static char copyright
[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
41 #ifdef LDAP_SASLIO_HOOKS
42 /* Valid for any ANSI C compiler */
46 #define VI_PRODUCTVERSION 3
48 #ifndef INADDR_LOOPBACK
49 #define INADDR_LOOPBACK ((unsigned long) 0x7f000001)
52 #ifndef MAXHOSTNAMELEN
53 #define MAXHOSTNAMELEN 64
62 * global defaults for callbacks are stored here. callers of the API set
63 * these by passing a NULL "ld" to ldap_set_option(). Everything in
64 * nsldapi_ld_defaults can be overridden on a per-ld basis as well (the
65 * memory allocation functions are global to all ld's).
67 struct ldap nsldapi_ld_defaults
;
68 struct ldap_memalloc_fns nsldapi_memalloc_fns
= { 0, 0, 0, 0 };
69 int nsldapi_initialized
= 0;
73 static pthread_key_t nsldapi_key
;
75 struct nsldapi_ldap_error
{
81 __declspec ( thread
) int nsldapi_gldaperrno
;
82 __declspec ( thread
) char *nsldapi_gmatched
= NULL
;
83 __declspec ( thread
) char *nsldapi_gldaperror
= NULL
;
87 #define LDAP_MUTEX_T HANDLE
90 pthread_mutex_init( LDAP_MUTEX_T
*mp
, void *attr
)
92 if ( (*mp
= CreateMutex(NULL
, FALSE
, NULL
)) == NULL
)
99 pthread_mutex_alloc( void )
101 LDAP_MUTEX_T
*mutexp
;
103 if ( (mutexp
= malloc( sizeof(LDAP_MUTEX_T
) )) != NULL
) {
104 pthread_mutex_init( mutexp
, NULL
);
110 pthread_mutex_destroy( LDAP_MUTEX_T
*mp
)
112 if ( !(CloseHandle(*mp
)) )
119 pthread_mutex_free( void *mutexp
)
121 pthread_mutex_destroy( (LDAP_MUTEX_T
*) mutexp
);
126 pthread_mutex_lock( LDAP_MUTEX_T
*mp
)
128 if ( (WaitForSingleObject(*mp
, INFINITE
) != WAIT_OBJECT_0
) )
135 pthread_mutex_unlock( LDAP_MUTEX_T
*mp
)
137 if ( !(ReleaseMutex(*mp
)) )
150 set_errno( int Errno
)
156 get_ld_error( char **LDMatched
, char **LDError
, void * Args
)
158 if ( LDMatched
!= NULL
)
160 *LDMatched
= nsldapi_gmatched
;
162 if ( LDError
!= NULL
)
164 *LDError
= nsldapi_gldaperror
;
166 return nsldapi_gldaperrno
;
170 set_ld_error( int LDErrno
, char * LDMatched
, char * LDError
,
173 /* Clean up any previous string storage. */
174 if ( nsldapi_gmatched
!= NULL
)
176 ldap_memfree( nsldapi_gmatched
);
178 if ( nsldapi_gldaperror
!= NULL
)
180 ldap_memfree( nsldapi_gldaperror
);
183 nsldapi_gldaperrno
= LDErrno
;
184 nsldapi_gmatched
= LDMatched
;
185 nsldapi_gldaperror
= LDError
;
189 pthread_mutex_alloc( void )
191 pthread_mutex_t
*mutexp
;
193 if ( (mutexp
= malloc( sizeof(pthread_mutex_t
) )) != NULL
) {
194 pthread_mutex_init( mutexp
, NULL
);
200 pthread_mutex_free( void *mutexp
)
202 pthread_mutex_destroy( (pthread_mutex_t
*) mutexp
);
207 set_ld_error( int err
, char *matched
, char *errmsg
, void *dummy
)
209 struct nsldapi_ldap_error
*le
;
212 le
= pthread_getspecific( nsldapi_key
);
215 tsd
= (void *)calloc(1, sizeof(struct nsldapi_ldap_error
));
216 pthread_setspecific( nsldapi_key
, tsd
);
219 le
= pthread_getspecific( nsldapi_key
);
228 if ( le
->le_matched
!= NULL
) {
229 ldap_memfree( le
->le_matched
);
231 le
->le_matched
= matched
;
233 if ( le
->le_errmsg
!= NULL
) {
234 ldap_memfree( le
->le_errmsg
);
236 le
->le_errmsg
= errmsg
;
240 get_ld_error( char **matched
, char **errmsg
, void *dummy
)
242 struct nsldapi_ldap_error
*le
;
244 le
= pthread_getspecific( nsldapi_key
);
246 if ( matched
!= NULL
) {
247 *matched
= le
->le_matched
;
249 if ( errmsg
!= NULL
) {
250 *errmsg
= le
->le_errmsg
;
252 return( le
->le_errno
);
254 if ( matched
!= NULL
)
256 if ( errmsg
!= NULL
)
259 return (LDAP_SUCCESS
);
273 #endif /* _WINDOWS */
275 static struct ldap_thread_fns
276 nsldapi_default_thread_fns
= {
277 (void *(*)(void))pthread_mutex_alloc
,
278 (void (*)(void *))pthread_mutex_free
,
279 (int (*)(void *))pthread_mutex_lock
,
280 (int (*)(void *))pthread_mutex_unlock
,
281 (int (*)(void))get_errno
,
282 (void (*)(int))set_errno
,
283 (int (*)(char **, char **, void *))get_ld_error
,
284 (void (*)(int, char *, char *, void *))set_ld_error
,
287 static struct ldap_extra_thread_fns
288 nsldapi_default_extra_thread_fns
= {
293 (void *(*)(void))pthread_self
294 #endif /* _WINDOWS */
298 nsldapi_initialize_defaults( void )
301 if ( nsldapi_initialized
) {
306 * This has to be called before nsldapi_initialized is set to 1
307 * because nsldapi_initialized does not have mutex protection
313 if ( pthread_key_create(&nsldapi_key
, free
) != 0) {
314 perror("pthread_key_create");
316 #endif /* _WINDOWS */
318 nsldapi_initialized
= 1;
319 memset( &nsldapi_memalloc_fns
, 0, sizeof( nsldapi_memalloc_fns
));
320 memset( &nsldapi_ld_defaults
, 0, sizeof( nsldapi_ld_defaults
));
321 nsldapi_ld_defaults
.ld_options
= LDAP_BITOPT_REFERRALS
;
322 nsldapi_ld_defaults
.ld_version
= LDAP_VERSION2
;
323 nsldapi_ld_defaults
.ld_lberoptions
= LBER_OPT_USE_DER
;
324 nsldapi_ld_defaults
.ld_refhoplimit
= LDAP_DEFAULT_REFHOPLIMIT
;
326 #ifdef LDAP_SASLIO_HOOKS
327 /* SASL default option settings */
328 nsldapi_ld_defaults
.ld_def_sasl_mech
= NULL
;
329 nsldapi_ld_defaults
.ld_def_sasl_realm
= NULL
;
330 nsldapi_ld_defaults
.ld_def_sasl_authcid
= NULL
;
331 nsldapi_ld_defaults
.ld_def_sasl_authzid
= NULL
;
332 /* SASL Security properties */
333 nsldapi_ld_defaults
.ld_sasl_secprops
.max_ssf
= UINT_MAX
;
334 nsldapi_ld_defaults
.ld_sasl_secprops
.maxbufsize
= SASL_MAX_BUFF_SIZE
;
335 nsldapi_ld_defaults
.ld_sasl_secprops
.security_flags
=
336 SASL_SEC_NOPLAINTEXT
| SASL_SEC_NOANONYMOUS
;
339 #if defined( STR_TRANSLATION ) && defined( LDAP_DEFAULT_CHARSET )
340 nsldapi_ld_defaults
.ld_lberoptions
|= LBER_OPT_TRANSLATE_STRINGS
;
341 #if LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET
342 ldap_set_string_translators( &nsldapi_ld_defaults
, ldap_8859_to_t61
,
344 #endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */
345 #endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
347 /* set default connect timeout (in milliseconds) */
348 /* this was picked as it is the standard tcp timeout as well */
349 nsldapi_ld_defaults
.ld_connect_timeout
= LDAP_X_IO_TIMEOUT_NO_TIMEOUT
;
351 /* load up default platform specific locking routines */
352 if (ldap_set_option( NULL
, LDAP_OPT_THREAD_FN_PTRS
,
353 (void *)&nsldapi_default_thread_fns
) != LDAP_SUCCESS
) {
358 /* load up default threadid function */
359 if (ldap_set_option( NULL
, LDAP_OPT_EXTRA_THREAD_FN_PTRS
,
360 (void *)&nsldapi_default_extra_thread_fns
) != LDAP_SUCCESS
) {
363 #endif /* _WINDOWS */
368 * ldap_version - report version levels for important properties
369 * This function is deprecated. Use ldap_get_option( ..., LDAP_OPT_API_INFO,
374 * ldap_version( &ver );
375 * if ( (ver.sdk_version < 100) || (ver.SSL_version < 300) )
376 * fprintf( stderr, "LDAP SDK level insufficient\n" );
379 * if ( ldap_version(NULL) < 100 )
380 * fprintf( stderr, "LDAP SDK level insufficient\n" );
386 ldap_version( LDAPVersion
*ver
)
390 memset( ver
, 0, sizeof(*ver
) );
391 ver
->sdk_version
= (int)(VI_PRODUCTVERSION
* 100);
392 ver
->protocol_version
= LDAP_VERSION_MAX
* 100;
393 ver
->SSL_version
= SSL_VERSION
* 100;
395 * set security to none by default
398 ver
->security_level
= LDAP_SECURITY_NONE
;
399 #if defined(LINK_SSL)
400 ver
->security_level
= 128;
404 return (int)(VI_PRODUCTVERSION
* 100);
408 * ldap_open - initialize and connect to an ldap server. A magic cookie to
409 * be used for future communication is returned on success, NULL on failure.
410 * "host" may be a space-separated list of hosts or IP addresses
414 * ld = ldap_open( hostname, port );
419 ldap_open( const char *host
, int port
)
423 LDAPDebug( LDAP_DEBUG_TRACE
, "ldap_open\n", 0, 0, 0 );
425 if (( ld
= ldap_init( host
, port
)) == NULL
) {
429 LDAP_MUTEX_LOCK( ld
, LDAP_CONN_LOCK
);
430 if ( nsldapi_open_ldap_defconn( ld
) < 0 ) {
431 LDAP_MUTEX_UNLOCK( ld
, LDAP_CONN_LOCK
);
432 ldap_ld_free( ld
, NULL
, NULL
, 0 );
436 LDAP_MUTEX_UNLOCK( ld
, LDAP_CONN_LOCK
);
437 LDAPDebug( LDAP_DEBUG_TRACE
, "ldap_open successful, ld_host is %s\n",
438 ( ld
->ld_host
== NULL
) ? "(null)" : ld
->ld_host
, 0, 0 );
445 * ldap_init - initialize the LDAP library. A magic cookie to be used for
446 * future communication is returned on success, NULL on failure.
447 * "defhost" may be a space-separated list of hosts or IP addresses
451 * ld = ldap_init( default_hostname, default_port );
455 ldap_init( const char *defhost
, int defport
)
459 if ( !nsldapi_initialized
) {
460 nsldapi_initialize_defaults();
463 if ( defport
< 0 || defport
> LDAP_PORT_MAX
) {
464 LDAPDebug( LDAP_DEBUG_ANY
,
465 "ldap_init: port %d is invalid (port numbers must range from 1 to %d)\n",
466 defport
, LDAP_PORT_MAX
, 0 );
467 #if !defined( macintosh ) && !defined( DOS )
473 LDAPDebug( LDAP_DEBUG_TRACE
, "ldap_init\n", 0, 0, 0 );
475 if ( (ld
= (LDAP
*)NSLDAPI_MALLOC( sizeof(struct ldap
) )) == NULL
) {
480 SAFEMEMCPY( ld
, &nsldapi_ld_defaults
, sizeof( struct ldap
));
481 if ( nsldapi_ld_defaults
.ld_io_fns_ptr
!= NULL
) {
482 if (( ld
->ld_io_fns_ptr
= (struct ldap_io_fns
*)NSLDAPI_MALLOC(
483 sizeof( struct ldap_io_fns
))) == NULL
) {
484 NSLDAPI_FREE( (char *)ld
);
488 *(ld
->ld_io_fns_ptr
) = *(nsldapi_ld_defaults
.ld_io_fns_ptr
);
491 /* call the new handle I/O callback if one is defined */
492 if ( ld
->ld_extnewhandle_fn
!= NULL
) {
494 * We always pass the session extended I/O argument to
495 * the new handle callback.
497 if ( ld
->ld_extnewhandle_fn( ld
, ld
->ld_ext_session_arg
)
499 NSLDAPI_FREE( (char*)ld
);
504 /* allocate session-specific resources */
505 if (( ld
->ld_sbp
= ber_sockbuf_alloc()) == NULL
||
507 ( ld
->ld_defhost
= nsldapi_strdup( defhost
)) == NULL
) ||
508 ((ld
->ld_mutex
= (void **) NSLDAPI_CALLOC( LDAP_MAX_LOCK
, sizeof(void *))) == NULL
)) {
509 if ( ld
->ld_sbp
!= NULL
) {
510 ber_sockbuf_free( ld
->ld_sbp
);
512 if( ld
->ld_mutex
!= NULL
) {
513 NSLDAPI_FREE( ld
->ld_mutex
);
515 NSLDAPI_FREE( (char*)ld
);
519 /* install Sockbuf I/O functions if set in LDAP * */
520 if ( ld
->ld_extread_fn
!= NULL
|| ld
->ld_extwrite_fn
!= NULL
) {
521 struct lber_x_ext_io_fns lberiofns
;
523 memset( &lberiofns
, 0, sizeof( lberiofns
));
525 lberiofns
.lbextiofn_size
= LBER_X_EXTIO_FNS_SIZE
;
526 lberiofns
.lbextiofn_read
= ld
->ld_extread_fn
;
527 lberiofns
.lbextiofn_write
= ld
->ld_extwrite_fn
;
528 lberiofns
.lbextiofn_writev
= ld
->ld_extwritev_fn
;
529 lberiofns
.lbextiofn_socket_arg
= NULL
;
530 ber_sockbuf_set_option( ld
->ld_sbp
, LBER_SOCKBUF_OPT_EXT_IO_FNS
,
531 (void *)&lberiofns
);
535 /* Install the functions for IPv6 support */
536 /* code sequencing is critical from here to nsldapi_mutex_alloc_all */
537 if ( prldap_install_thread_functions( ld
, 1 ) != 0 ||
538 prldap_install_io_functions( ld
, 1 ) != 0 ||
539 prldap_install_dns_functions( ld
) != 0 ) {
540 /* go through ld and free resources */
547 /* allocate mutexes */
548 nsldapi_mutex_alloc_all( ld
);
551 /* set default port */
552 ld
->ld_defport
= ( defport
== 0 ) ? LDAP_PORT
: defport
;
558 nsldapi_mutex_alloc_all( LDAP
*ld
)
562 if ( ld
!= &nsldapi_ld_defaults
&& ld
->ld_mutex
!= NULL
) {
563 for ( i
= 0; i
<LDAP_MAX_LOCK
; i
++ ) {
564 ld
->ld_mutex
[i
] = LDAP_MUTEX_ALLOC( ld
);
565 ld
->ld_mutex_threadid
[i
] = (void *) -1;
566 ld
->ld_mutex_refcnt
[i
] = 0;
573 nsldapi_mutex_free_all( LDAP
*ld
)
577 if ( ld
!= &nsldapi_ld_defaults
&& ld
->ld_mutex
!= NULL
) {
578 for ( i
= 0; i
<LDAP_MAX_LOCK
; i
++ ) {
579 LDAP_MUTEX_FREE( ld
, ld
->ld_mutex
[i
] );
584 /* returns 0 if connection opened and -1 if an error occurs */
586 nsldapi_open_ldap_defconn( LDAP
*ld
)
590 if (( srv
= (LDAPServer
*)NSLDAPI_CALLOC( 1, sizeof( LDAPServer
))) ==
591 NULL
|| ( ld
->ld_defhost
!= NULL
&& ( srv
->lsrv_host
=
592 nsldapi_strdup( ld
->ld_defhost
)) == NULL
)) {
593 LDAP_SET_LDERRNO( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
596 srv
->lsrv_port
= ld
->ld_defport
;
598 #ifdef LDAP_SSLIO_HOOKS
599 if (( ld
->ld_options
& LDAP_BITOPT_SSL
) != 0 ) {
600 srv
->lsrv_options
|= LDAP_SRV_OPT_SECURE
;
604 if (( ld
->ld_defconn
= nsldapi_new_connection( ld
, &srv
, 1, 1, 0 ))
606 if ( ld
->ld_defhost
!= NULL
) {
607 NSLDAPI_FREE( srv
->lsrv_host
);
609 NSLDAPI_FREE( (char *)srv
);
612 ++ld
->ld_defconn
->lconn_refcnt
; /* so it never gets closed/freed */
618 struct ldap_x_hostlist_status
{
625 * Return the first host and port in hostlist (setting *hostp and *portp).
626 * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
627 * Note that a NULL or zero-length hostlist causes the host "127.0.0.1" to
631 ldap_x_hostlist_first( const char *hostlist
, int defport
, char **hostp
,
632 int *portp
, struct ldap_x_hostlist_status
**statusp
)
635 if ( NULL
== hostp
|| NULL
== portp
|| NULL
== statusp
) {
636 return( LDAP_PARAM_ERROR
);
639 if ( NULL
== hostlist
|| *hostlist
== '\0' ) {
640 *hostp
= nsldapi_strdup( "127.0.0.1" );
641 if ( NULL
== *hostp
) {
642 return( LDAP_NO_MEMORY
);
646 return( LDAP_SUCCESS
);
649 *statusp
= NSLDAPI_CALLOC( 1, sizeof( struct ldap_x_hostlist_status
));
650 if ( NULL
== *statusp
) {
651 return( LDAP_NO_MEMORY
);
653 (*statusp
)->lhs_hostlist
= nsldapi_strdup( hostlist
);
654 if ( NULL
== (*statusp
)->lhs_hostlist
) {
655 return( LDAP_NO_MEMORY
);
657 (*statusp
)->lhs_nexthost
= (*statusp
)->lhs_hostlist
;
658 (*statusp
)->lhs_defport
= defport
;
659 return( ldap_x_hostlist_next( hostp
, portp
, *statusp
));
663 * Return the next host and port in hostlist (setting *hostp and *portp).
664 * Return value is an LDAP API error code (LDAP_SUCCESS if all goes well).
665 * If no more hosts are available, LDAP_SUCCESS is returned but *hostp is set
669 ldap_x_hostlist_next( char **hostp
, int *portp
,
670 struct ldap_x_hostlist_status
*status
)
673 int squarebrackets
= 0;
675 if ( NULL
== hostp
|| NULL
== portp
) {
676 return( LDAP_PARAM_ERROR
);
679 if ( NULL
== status
|| NULL
== status
->lhs_nexthost
) {
681 return( LDAP_SUCCESS
);
685 * skip past leading '[' if present (IPv6 addresses may be surrounded
686 * with square brackets, e.g., [fe80::a00:20ff:fee5:c0b4]:389
688 if ( status
->lhs_nexthost
[0] == '[' ) {
689 ++status
->lhs_nexthost
;
693 /* copy host into *hostp */
694 if ( NULL
!= ( q
= strchr( status
->lhs_nexthost
, ' ' ))) {
695 size_t len
= q
- status
->lhs_nexthost
;
696 *hostp
= NSLDAPI_MALLOC( len
+ 1 );
697 if ( NULL
== *hostp
) {
698 return( LDAP_NO_MEMORY
);
700 strncpy( *hostp
, status
->lhs_nexthost
, len
);
701 (*hostp
)[len
] = '\0';
702 status
->lhs_nexthost
+= ( len
+ 1 );
703 } else { /* last host */
704 *hostp
= nsldapi_strdup( status
->lhs_nexthost
);
705 if ( NULL
== *hostp
) {
706 return( LDAP_NO_MEMORY
);
708 status
->lhs_nexthost
= NULL
;
712 * Look for closing ']' and skip past it before looking for port.
714 if ( squarebrackets
&& NULL
!= ( q
= strchr( *hostp
, ']' ))) {
720 /* determine and set port */
721 if ( NULL
!= ( q
= strchr( q
, ':' ))) {
725 *portp
= status
->lhs_defport
;
728 return( LDAP_SUCCESS
);
733 ldap_x_hostlist_statusfree( struct ldap_x_hostlist_status
*status
)
735 if ( NULL
!= status
) {
736 if ( NULL
!= status
->lhs_hostlist
) {
737 NSLDAPI_FREE( status
->lhs_hostlist
);
739 NSLDAPI_FREE( status
);
746 * memory allocation functions. we include these in open.c since every
747 * LDAP application is likely to pull the rest of the code in this file
751 ldap_x_malloc( size_t size
)
753 return( nsldapi_memalloc_fns
.ldapmem_malloc
== NULL
?
755 nsldapi_memalloc_fns
.ldapmem_malloc( size
));
760 ldap_x_calloc( size_t nelem
, size_t elsize
)
762 return( nsldapi_memalloc_fns
.ldapmem_calloc
== NULL
?
763 calloc( nelem
, elsize
) :
764 nsldapi_memalloc_fns
.ldapmem_calloc( nelem
, elsize
));
769 ldap_x_realloc( void *ptr
, size_t size
)
771 return( nsldapi_memalloc_fns
.ldapmem_realloc
== NULL
?
772 realloc( ptr
, size
) :
773 nsldapi_memalloc_fns
.ldapmem_realloc( ptr
, size
));
778 ldap_x_free( void *ptr
)
780 if ( nsldapi_memalloc_fns
.ldapmem_free
== NULL
) {
783 nsldapi_memalloc_fns
.ldapmem_free( ptr
);
788 /* if s is NULL, returns NULL */
790 nsldapi_strdup( const char *s
)
795 (p
= (char *)NSLDAPI_MALLOC( strlen( s
) + 1 )) == NULL
)