2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * The contents of this file are subject to the Netscape Public
8 * License Version 1.1 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of
10 * the License at http://www.mozilla.org/NPL/
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is Netscape
21 * Communications Corporation. Portions created by Netscape are
22 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
34 #if defined( _WINDOWS )
38 /* XXX:mhein The following is a workaround for the redefinition of */
39 /* const problem on OSF. Fix to be provided by NSS */
40 /* This is a pretty benign workaround for us which */
41 /* should not cause problems in the future even if */
42 /* we forget to take it out :-) */
65 #include "solaris-int.h"
70 #include <nss_dbdefs.h>
71 #include <netinet/in.h>
73 #define HOST_BUF_SIZE 2048
76 #define INADDR_NONE (-1)
80 str2hostent(const char *instr
, int lenstr
, void *ent
, char *buffer
,
84 str2hostent6(const char *instr
, int lenstr
, void *ent
, char *buffer
,
88 _ns_gethostbyaddr(LDAP
*ld
, const char *addr
, int length
, int type
,
89 LDAPHostEnt
*result
, char *buffer
, int buflen
, int *statusp
,
92 static char *host_service
= NULL
;
94 static DEFINE_NSS_DB_ROOT(db_root_hosts
);
95 static DEFINE_NSS_DB_ROOT(db_root_ipnodes
);
99 * Data structure to hold the standard NSPR I/O function pointers set by
100 * libprldap. We save them in our session data structure so we can call
101 * them from our own I/O functions (we add functionality to support SSL
102 * while using libprldap's functions as much as possible).
104 typedef struct ldapssl_std_functions
{
105 LDAP_X_EXTIOF_CLOSE_CALLBACK
*lssf_close_fn
;
106 LDAP_X_EXTIOF_CONNECT_CALLBACK
*lssf_connect_fn
;
107 LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK
*lssf_disposehdl_fn
;
108 } LDAPSSLStdFunctions
;
113 * LDAP session data structure.
115 typedef struct ldapssl_session_info
{
116 int lssei_using_pcks_fns
;
117 int lssei_ssl_strength
;
118 char *lssei_certnickname
;
119 char *lssei_keypasswd
;
120 LDAPSSLStdFunctions lssei_std_functions
;
121 CERTCertDBHandle
*lssei_certdbh
;
125 * ld is used so that we can use libldap's gethostbyaddr
126 * resolver. This is needed to prevent recursion with libsldap.
129 #endif /* _SOLARIS_SDK */
130 } LDAPSSLSessionInfo
;
134 * LDAP socket data structure.
136 typedef struct ldapssl_socket_info
{
137 LDAPSSLSessionInfo
*soi_sessioninfo
; /* session info */
142 * XXXceb This is a hack until the new IO functions are done.
143 * this function MUST be called before ldap_enable_clienauth.
144 * right now, this function is called in ldapssl_pkcs_init();
147 static int using_pkcs_functions
= 0;
149 void set_using_pkcs_functions( int val
)
151 using_pkcs_functions
= val
;
158 static void ldapssl_free_session_info( LDAPSSLSessionInfo
**ssipp
);
159 static void ldapssl_free_socket_info( LDAPSSLSocketInfo
**soipp
);
166 static int ldapssl_AuthCertificate(void *sessionarg
, PRFileDesc
*fd
,
167 PRBool checkSig
, PRBool isServer
);
172 static int get_clientauth_data( void *sessionarg
, PRFileDesc
*prfd
,
173 CERTDistNames
*caNames
, CERTCertificate
**pRetCert
,
174 SECKEYPrivateKey
**pRetKey
);
175 static int get_keyandcert( LDAPSSLSessionInfo
*ssip
,
176 CERTCertificate
**pRetCert
, SECKEYPrivateKey
**pRetKey
,
178 static int check_clientauth_nicknames_and_passwd( LDAP
*ld
,
179 LDAPSSLSessionInfo
*ssip
);
180 static char *get_keypassword( PK11SlotInfo
*slot
, PRBool retry
,
187 static int default_ssl_strength
= LDAPSSL_AUTH_CNCHECK
;
189 static int default_ssl_strength
= LDAPSSL_AUTH_CERT
;
193 * Like ldap_init(), except also install I/O routines from libsec so we
194 * can support SSL. If defsecure is non-zero, SSL is enabled for the
195 * default connection as well.
199 ldapssl_init( const char *defhost
, int defport
, int defsecure
)
204 #ifndef LDAP_SSLIO_HOOKS
208 defport
= LDAPS_PORT
;
210 if (( ld
= ldap_init( defhost
, defport
)) == NULL
) {
214 if ( ldapssl_install_routines( ld
) < 0 || ldap_set_option( ld
,
215 LDAP_OPT_SSL
, defsecure
? LDAP_OPT_ON
: LDAP_OPT_OFF
) != 0 ) {
216 PR_SetError( PR_UNKNOWN_ERROR
, EINVAL
); /* XXXmcs: just a guess! */
227 ldapssl_close(int s
, struct lextiof_socket_private
*socketarg
)
229 PRLDAPSocketInfo soi
;
230 LDAPSSLSocketInfo
*ssoip
;
231 LDAPSSLSessionInfo
*sseip
;
233 memset( &soi
, 0, sizeof(soi
));
234 soi
.soinfo_size
= PRLDAP_SOCKETINFO_SIZE
;
235 if ( prldap_get_socket_info( s
, socketarg
, &soi
) != LDAP_SUCCESS
) {
239 ssoip
= (LDAPSSLSocketInfo
*)soi
.soinfo_appdata
;
240 sseip
= ssoip
->soi_sessioninfo
;
242 ldapssl_free_socket_info( (LDAPSSLSocketInfo
**)&soi
.soinfo_appdata
);
244 return( (*(sseip
->lssei_std_functions
.lssf_close_fn
))( s
, socketarg
));
248 do_ldapssl_connect(const char *hostlist
, int defport
, int timeout
,
249 unsigned long options
, struct lextiof_session_private
*sessionarg
,
250 struct lextiof_socket_private
**socketargp
, int clientauth
)
254 PRLDAPSessionInfo sei
;
255 PRLDAPSocketInfo soi
;
256 LDAPSSLSocketInfo
*ssoip
= NULL
;
257 LDAPSSLSessionInfo
*sseip
;
258 PRFileDesc
*sslfd
= NULL
;
264 struct ldap_x_hostlist_status
267 in6_addr_t addr_ipv6
;
270 LDAPHostEnt host_ent
;
273 #endif /* _SOLARIS_SDK */
276 * Determine if secure option is set. Also, clear secure bit in options
277 * the we pass to the standard connect() function (since it doesn't know
278 * how to handle the secure option).
280 if ( 0 != ( options
& LDAP_X_EXTIOF_OPT_SECURE
)) {
282 options
&= ~LDAP_X_EXTIOF_OPT_SECURE
;
288 * Retrieve session info. so we can store a pointer to our session info.
289 * in our socket info. later.
291 memset( &sei
, 0, sizeof(sei
));
292 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
293 if ( prldap_get_session_info( NULL
, sessionarg
, &sei
) != LDAP_SUCCESS
) {
296 sseip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
299 * Call the standard connect() callback to make the TCP connection.
300 * If it succeeds, *socketargp is set.
303 intfd
= (*(sseip
->lssei_std_functions
.lssf_connect_fn
))( hostlist
, defport
,
304 timeout
, options
, sessionarg
, socketargp
309 #endif /* _SOLARIS_SDK */
317 * Determine if the "host name" is an ip address. If so,
318 * we must look up the actual host name corresponding to
321 if ( NULL
== host
) {
322 goto close_socket_and_exit_with_error
;
325 if (strlen(host
) < INET6_ADDRSTRLEN
&&
326 inet_pton(AF_INET6
, host
, &addr_ipv6
) == 1) {
328 } else if (strlen(host
) < INET_ADDRSTRLEN
&&
329 inet_pton(AF_INET
, host
, &addr_ipv4
) == 1) {
332 if (type
== AF_INET
|| type
== AF_INET6
) {
333 host_buf
= malloc(HOST_BUF_SIZE
);
334 if (host_buf
== NULL
) {
335 /* will free host in close_socket_and_exit_with_error */
336 goto close_socket_and_exit_with_error
;
339 /* Call ldap layer's gethostbyaddr resolver */
340 hent
= _ns_gethostbyaddr(sseip
->ld
, host
, strlen(host
), type
,
341 &host_ent
, host_buf
, HOST_BUF_SIZE
, &stat
, NULL
);
343 /* If we are unable to lookup the host addr, we fail! */
346 "libldap: do_ldapssl_connect: "
347 "Unable to resolve '%s'", host
);
349 /* will free host in close_socket_and_exit_with_error */
350 goto close_socket_and_exit_with_error
;
352 /* We support only the primary host name */
354 if (hent
->ldaphe_name
!= NULL
)
355 name
= strdup(hent
->ldaphe_name
);
358 goto close_socket_and_exit_with_error
;
360 ldap_memfree(host
); host
= NULL
;
364 #endif /* _SOLARIS_SDK */
367 * Retrieve socket info. so we have the PRFileDesc.
369 memset( &soi
, 0, sizeof(soi
));
370 soi
.soinfo_size
= PRLDAP_SOCKETINFO_SIZE
;
371 if ( prldap_get_socket_info( intfd
, *socketargp
, &soi
) != LDAP_SUCCESS
) {
372 goto close_socket_and_exit_with_error
;
376 * Allocate a structure to hold our socket-specific data.
378 if ( NULL
== ( ssoip
= PR_Calloc( 1, sizeof( LDAPSSLSocketInfo
)))) {
379 goto close_socket_and_exit_with_error
;
381 ssoip
->soi_sessioninfo
= sseip
;
384 * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
386 if (( sslfd
= SSL_ImportFD( NULL
, soi
.soinfo_prfd
)) == NULL
) {
387 goto close_socket_and_exit_with_error
;
390 if ( SSL_OptionSet( sslfd
, SSL_SECURITY
, secure
) != SECSuccess
||
391 SSL_OptionSet( sslfd
, SSL_HANDSHAKE_AS_CLIENT
, secure
)
392 != SECSuccess
|| ( secure
&& SSL_ResetHandshake( sslfd
,
393 PR_FALSE
) != SECSuccess
)) {
394 goto close_socket_and_exit_with_error
;
398 * Let the standard NSPR to LDAP layer know about the new socket and
399 * our own socket-specific data.
401 soi
.soinfo_prfd
= sslfd
;
402 soi
.soinfo_appdata
= (void *)ssoip
;
403 if ( prldap_set_socket_info( intfd
, *socketargp
, &soi
) != LDAP_SUCCESS
) {
404 goto close_socket_and_exit_with_error
;
409 * Set hostname which will be retrieved (depending on ssl strength) when
410 * using client or server auth.
412 if (SSL_SetURL(sslfd
, host
) != SECSuccess
)
413 goto close_socket_and_exit_with_error
;
416 #endif /* _SOLARIS_SDK */
418 sslfd
= NULL
; /* so we don't close the socket twice upon error */
421 * Install certificate hook function.
423 SSL_AuthCertificateHook( soi
.soinfo_prfd
,
424 (SSLAuthCertificate
)ldapssl_AuthCertificate
,
427 if ( SSL_GetClientAuthDataHook( soi
.soinfo_prfd
,
428 get_clientauth_data
, clientauth
? sseip
: NULL
) != 0 ) {
429 goto close_socket_and_exit_with_error
;
432 return( intfd
); /* success */
434 close_socket_and_exit_with_error
:
436 if ( NULL
!= host
) ldap_memfree(host
);
437 #endif /* _SOLARIS_SDK */
438 if ( NULL
!= sslfd
) {
441 if ( NULL
!= ssoip
) {
442 ldapssl_free_socket_info( &ssoip
);
444 if ( intfd
>= 0 && NULL
!= *socketargp
) {
445 (*(sseip
->lssei_std_functions
.lssf_close_fn
))( intfd
, *socketargp
);
452 ldapssl_connect(const char *hostlist
, int defport
, int timeout
,
453 unsigned long options
, struct lextiof_session_private
*sessionarg
,
454 struct lextiof_socket_private
**socketargp
)
456 return( do_ldapssl_connect( hostlist
, defport
, timeout
, options
,
457 sessionarg
, socketargp
, 0 ));
462 ldapssl_clientauth_connect(const char *hostlist
, int defport
, int timeout
,
463 unsigned long options
, struct lextiof_session_private
*sessionarg
,
464 struct lextiof_socket_private
**socketargp
)
466 return( do_ldapssl_connect( hostlist
, defport
, timeout
, options
,
467 sessionarg
, socketargp
, 1 ));
472 ldapssl_disposehandle(LDAP
*ld
, struct lextiof_session_private
*sessionarg
)
474 PRLDAPSessionInfo sei
;
475 LDAPSSLSessionInfo
*sseip
;
476 LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK
*disposehdl_fn
;
478 memset( &sei
, 0, sizeof( sei
));
479 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
480 if ( prldap_get_session_info( ld
, NULL
, &sei
) == LDAP_SUCCESS
) {
481 sseip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
482 disposehdl_fn
= sseip
->lssei_std_functions
.lssf_disposehdl_fn
;
483 ldapssl_free_session_info( &sseip
);
484 (*disposehdl_fn
)( ld
, sessionarg
);
490 * Install I/O routines from libsec and NSPR into libldap to allow libldap
493 * We rely on libprldap to provide most of the functions, and then we override
494 * a few of them to support SSL.
498 ldapssl_install_routines( LDAP
*ld
)
500 #ifndef LDAP_SSLIO_HOOKS
501 ldap_set_lderrno( ld
, LDAP_LOCAL_ERROR
, NULL
, NULL
);
504 struct ldap_x_ext_io_fns iofns
;
505 LDAPSSLSessionInfo
*ssip
;
506 PRLDAPSessionInfo sei
;
509 * This is done within ldap_init() and
510 * ldap_init() is called from ldapssl_init()
513 if ( prldap_install_routines(
515 1 /* shared -- we have to assume it is */ )
519 #endif /*_SOLARIS_SDK*/
522 * Allocate our own session information.
524 if ( NULL
== ( ssip
= (LDAPSSLSessionInfo
*)PR_Calloc( 1,
525 sizeof( LDAPSSLSessionInfo
)))) {
526 ldap_set_lderrno( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
530 * Initialize session info.
531 * XXX: it would be nice to be able to set these on a per-session basis:
532 * lssei_using_pcks_fns
535 ssip
->lssei_ssl_strength
= default_ssl_strength
;
536 ssip
->lssei_using_pcks_fns
= using_pkcs_functions
;
537 ssip
->lssei_certdbh
= CERT_GetDefaultCertDB();
540 * This is part of a hack to allow the ssl portion of the
541 * library to call the ldap library gethostbyaddr resolver.
544 #endif /* _SOLARIS_SDK */
547 * override a few functions, saving a pointer to the standard function
548 * in each case so we can call it from our SSL savvy functions.
550 memset( &iofns
, 0, sizeof(iofns
));
551 iofns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
552 if ( ldap_get_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
) < 0 ) {
553 ldapssl_free_session_info( &ssip
);
557 /* override socket, connect, and ioctl */
558 ssip
->lssei_std_functions
.lssf_connect_fn
= iofns
.lextiof_connect
;
559 iofns
.lextiof_connect
= ldapssl_connect
;
560 ssip
->lssei_std_functions
.lssf_close_fn
= iofns
.lextiof_close
;
561 iofns
.lextiof_close
= ldapssl_close
;
562 ssip
->lssei_std_functions
.lssf_disposehdl_fn
= iofns
.lextiof_disposehandle
;
563 iofns
.lextiof_disposehandle
= ldapssl_disposehandle
;
565 if ( ldap_set_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
) < 0 ) {
566 ldapssl_free_session_info( &ssip
);
571 * Store session info. for later retrieval.
573 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
574 sei
.seinfo_appdata
= (void *)ssip
;
575 if ( prldap_set_session_info( ld
, NULL
, &sei
) != LDAP_SUCCESS
) {
585 * Set the SSL strength for an existing SSL-enabled LDAP session handle.
587 * See the description of ldapssl_serverauth_init() above for valid
588 * sslstrength values. If ld is NULL, the default for new LDAP session
591 * Returns 0 if all goes well and -1 if an error occurs.
595 ldapssl_set_strength( LDAP
*ld
, int sslstrength
)
597 int rc
= 0; /* assume success */
599 if ( sslstrength
!= LDAPSSL_AUTH_WEAK
&&
600 sslstrength
!= LDAPSSL_AUTH_CERT
&&
601 sslstrength
!= LDAPSSL_AUTH_CNCHECK
) {
604 if ( NULL
== ld
) { /* set default strength */
605 default_ssl_strength
= sslstrength
;
606 } else { /* set session-specific strength */
607 PRLDAPSessionInfo sei
;
608 LDAPSSLSessionInfo
*sseip
;
610 memset( &sei
, 0, sizeof( sei
));
611 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
612 if ( prldap_get_session_info( ld
, NULL
, &sei
) == LDAP_SUCCESS
)
614 sseip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
615 sseip
->lssei_ssl_strength
= sslstrength
;
627 ldapssl_enable_clientauth( LDAP
*ld
, char *keynickname
,
628 char *keypasswd
, char *certnickname
)
630 #ifndef LDAP_SSLIO_HOOKS
631 ldap_set_lderrno( ld
, LDAP_LOCAL_ERROR
, NULL
, NULL
);
634 struct ldap_x_ext_io_fns iofns
;
635 LDAPSSLSessionInfo
*ssip
;
636 PRLDAPSessionInfo sei
;
641 if ( certnickname
== NULL
|| keypasswd
== NULL
) {
642 ldap_set_lderrno( ld
, LDAP_PARAM_ERROR
, NULL
, NULL
);
647 * Update session info. data structure.
649 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
650 if ( prldap_get_session_info( ld
, NULL
, &sei
) != LDAP_SUCCESS
) {
653 ssip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
654 if ( NULL
== ssip
) {
655 ldap_set_lderrno( ld
, LDAP_PARAM_ERROR
, NULL
, NULL
);
658 ssip
->lssei_certnickname
= PL_strdup( certnickname
);
659 ssip
->lssei_keypasswd
= PL_strdup( keypasswd
);
661 if ( NULL
== ssip
->lssei_certnickname
|| NULL
== ssip
->lssei_keypasswd
) {
662 ldap_set_lderrno( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
666 if ( check_clientauth_nicknames_and_passwd( ld
, ssip
) != 0 ) {
671 * replace standard SSL CONNECT function with client auth aware one
673 memset( &iofns
, 0, sizeof(iofns
));
674 iofns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
675 if ( ldap_get_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
)
680 if ( iofns
.lextiof_connect
!= ldapssl_connect
) {
681 /* standard SSL setup has not done */
682 ldap_set_lderrno( ld
, LDAP_PARAM_ERROR
, NULL
, NULL
);
686 iofns
.lextiof_connect
= ldapssl_clientauth_connect
;
688 if ( ldap_set_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
)
699 ldapssl_free_session_info( LDAPSSLSessionInfo
**ssipp
)
701 if ( NULL
!= ssipp
&& NULL
!= *ssipp
) {
702 if ( NULL
!= (*ssipp
)->lssei_certnickname
) {
703 PL_strfree( (*ssipp
)->lssei_certnickname
);
704 (*ssipp
)->lssei_certnickname
= NULL
;
706 if ( NULL
!= (*ssipp
)->lssei_keypasswd
) {
707 PL_strfree( (*ssipp
)->lssei_keypasswd
);
708 (*ssipp
)->lssei_keypasswd
= NULL
;
717 ldapssl_free_socket_info( LDAPSSLSocketInfo
**soipp
)
719 if ( NULL
!= soipp
&& NULL
!= *soipp
) {
726 /* this function provides cert authentication. This is called during
727 * the SSL_Handshake process. Once the cert has been retrieved from
728 * the server, the it is checked, using VerifyCertNow(), then
729 * the cn is checked against the host name, set with SSL_SetURL()
733 ldapssl_AuthCertificate(void *sessionarg
, PRFileDesc
*fd
, PRBool checkSig
,
736 SECStatus rv
= SECFailure
;
737 LDAPSSLSessionInfo
*sseip
;
738 CERTCertificate
*cert
;
739 SECCertUsage certUsage
;
740 char *hostname
= NULL
;
742 if (!sessionarg
|| !socket
)
745 sseip
= (LDAPSSLSessionInfo
*)sessionarg
;
747 if (LDAPSSL_AUTH_WEAK
== sseip
->lssei_ssl_strength
) { /* no check */
752 certUsage
= certUsageSSLClient
;
754 certUsage
= certUsageSSLServer
;
756 cert
= SSL_PeerCertificate( fd
);
758 rv
= CERT_VerifyCertNow(sseip
->lssei_certdbh
, cert
, checkSig
,
761 if ( rv
!= SECSuccess
|| isServer
)
764 if ( LDAPSSL_AUTH_CNCHECK
== sseip
->lssei_ssl_strength
)
766 /* cert is OK. This is the client side of an SSL connection.
767 * Now check the name field in the cert against the desired hostname.
768 * NB: This is our only defense against Man-In-The-Middle (MITM)
772 hostname
= SSL_RevealURL( fd
);
774 if (hostname
&& hostname
[0]) {
775 rv
= CERT_VerifyCertName(cert
, hostname
);
781 if (rv
!= SECSuccess
)
782 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN
);
790 * called during SSL client auth. when server wants our cert and key.
791 * return 0 if we succeeded and set *pRetCert and *pRetKey, -1 otherwise.
792 * if -1 is returned SSL will proceed without sending a cert.
796 get_clientauth_data( void *sessionarg
, PRFileDesc
*prfd
,
797 CERTDistNames
*caNames
, CERTCertificate
**pRetCert
,
798 SECKEYPrivateKey
**pRetKey
)
801 LDAPSSLSessionInfo
*ssip
;
803 if (( ssip
= (LDAPSSLSessionInfo
*)sessionarg
) == NULL
) {
804 return( -1 ); /* client auth. not enabled */
807 return( get_keyandcert( ssip
, pRetCert
, pRetKey
, NULL
));
811 get_keyandcert( LDAPSSLSessionInfo
*ssip
,
812 CERTCertificate
**pRetCert
, SECKEYPrivateKey
**pRetKey
,
815 CERTCertificate
*cert
;
816 SECKEYPrivateKey
*key
;
818 if (( cert
= PK11_FindCertFromNickname( ssip
->lssei_certnickname
, NULL
))
820 if ( errmsgp
!= NULL
) {
821 *errmsgp
= dgettext(TEXT_DOMAIN
, "unable to find certificate");
827 PK11_SetPasswordFunc( get_keypassword
);
832 if (( key
= PK11_FindKeyByAnyCert( cert
, (void *)ssip
)) == NULL
) {
833 CERT_DestroyCertificate( cert
);
834 if ( errmsgp
!= NULL
) {
835 *errmsgp
= dgettext(TEXT_DOMAIN
, "bad key or key password");
847 * This function returns the password to NSS.
848 * This function is enable through PK11_SetPasswordFunc
849 * only if pkcs functions are not being used.
853 get_keypassword( PK11SlotInfo
*slot
, PRBool retry
, void *sessionarg
)
855 LDAPSSLSessionInfo
*ssip
;
860 ssip
= (LDAPSSLSessionInfo
*)sessionarg
;
861 if ( NULL
== ssip
) {
865 return( ssip
->lssei_keypasswd
);
870 * performs some basic checks on clientauth cert and key/password
872 * XXXmcs: could perform additional checks... see servers/slapd/ssl.c
873 * 1) check expiration
874 * 2) check that public key in cert matches private key
875 * see ns/netsite/ldap/servers/slapd/ssl.c:slapd_ssl_init() for example code.
878 check_clientauth_nicknames_and_passwd( LDAP
*ld
, LDAPSSLSessionInfo
*ssip
)
881 CERTCertificate
*cert
= NULL
;
882 SECKEYPrivateKey
*key
= NULL
;
885 rv
= get_keyandcert( ssip
, &cert
, &key
, &errmsg
);
888 if ( errmsg
!= NULL
) {
889 errmsg
= strdup( errmsg
);
891 ldap_set_lderrno( ld
, LDAP_PARAM_ERROR
, NULL
, errmsg
);
895 if ( cert
!= NULL
) {
896 CERT_DestroyCertificate( cert
);
899 SECKEY_DestroyPrivateKey( key
);
905 #if 0 /* NOT_NEEDED_IN_LIBLDAP */
906 /* there are patches and kludges. this is both. force some linkers to
909 int stubs_o_stuff( void )
911 PRExplodedTime exploded
;
914 const char *name
="t";
915 PRUint32 size
= 0, align
= 0;
917 PR_ImplodeTime( &exploded
);
918 PL_InitArenaPool( &pool
, name
, size
, align
);
920 PR_fprintf((PRFileDesc
*)stderr
, "Bad IDEA!!");
925 #endif /* NOT_NEEDED_IN_LIBLDAP */
929 * Import the file descriptor corresponding to the socket of an already
930 * open LDAP connection into SSL, and update the socket and session
931 * information accordingly.
933 int ldapssl_import_fd ( LDAP
*ld
, int secure
)
935 PRLDAPSessionInfo sei
;
936 PRLDAPSocketInfo soi
;
937 LDAPSSLSocketInfo
*ssoip
= NULL
;
938 LDAPSSLSessionInfo
*sseip
;
939 PRFileDesc
*sslfd
= NULL
;
943 * Retrieve session info. so we can store a pointer to our session info.
944 * in our socket info. later.
946 memset( &sei
, 0, sizeof(sei
));
947 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
948 if ( prldap_get_session_info( ld
, NULL
, &sei
) != LDAP_SUCCESS
) {
951 sseip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
955 * Retrieve socket info. so we have the PRFileDesc.
957 memset( &soi
, 0, sizeof(soi
));
958 soi
.soinfo_size
= PRLDAP_SOCKETINFO_SIZE
;
959 if ( prldap_get_default_socket_info( ld
, &soi
) != LDAP_SUCCESS
) {
964 * Allocate a structure to hold our socket-specific data.
966 if ( NULL
== ( ssoip
= PR_Calloc( 1, sizeof( LDAPSSLSocketInfo
)))) {
967 goto reset_socket_and_exit_with_error
;
969 ssoip
->soi_sessioninfo
= sseip
;
972 * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
974 if (( sslfd
= SSL_ImportFD( NULL
, soi
.soinfo_prfd
)) == NULL
) {
975 goto reset_socket_and_exit_with_error
;
978 if ( SSL_OptionSet( sslfd
, SSL_SECURITY
, secure
) != SECSuccess
||
979 SSL_OptionSet( sslfd
, SSL_HANDSHAKE_AS_CLIENT
, secure
)
980 != SECSuccess
|| ( secure
&& SSL_ResetHandshake( sslfd
,
981 PR_FALSE
) != SECSuccess
)) {
982 goto reset_socket_and_exit_with_error
;
986 * Let the standard NSPR to LDAP layer know about the new socket and
987 * our own socket-specific data.
989 soi
.soinfo_prfd
= sslfd
;
990 soi
.soinfo_appdata
= (void *)ssoip
;
991 if ( prldap_set_default_socket_info( ld
, &soi
) != LDAP_SUCCESS
) {
992 goto reset_socket_and_exit_with_error
;
996 * Install certificate hook function.
998 if ( SSL_AuthCertificateHook( soi
.soinfo_prfd
,
999 (SSLAuthCertificate
)ldapssl_AuthCertificate
,
1000 (void *)CERT_GetDefaultCertDB()) != 0 ) {
1001 goto reset_socket_and_exit_with_error
;
1004 if ( SSL_GetClientAuthDataHook( soi
.soinfo_prfd
,
1005 get_clientauth_data
, sseip
->lssei_certnickname
? sseip
: NULL
)
1007 goto reset_socket_and_exit_with_error
;
1012 reset_socket_and_exit_with_error
:
1013 if ( NULL
!= sslfd
) {
1015 * "Unimport" the socket from SSL, i.e. get rid of the upper layer of
1016 * the file descriptor stack, which represents SSL.
1018 soi
.soinfo_prfd
= sslfd
;
1019 sslfd
= PR_PopIOLayer( soi
.soinfo_prfd
, PR_TOP_IO_LAYER
);
1020 sslfd
->dtor( sslfd
);
1022 if ( NULL
!= ssoip
) {
1023 ldapssl_free_socket_info( &ssoip
);
1024 soi
.soinfo_appdata
= NULL
;
1026 prldap_set_default_socket_info( ld
, &soi
);
1033 * Reset an LDAP session from SSL to a non-secure status.
1034 * Basically, this function undoes the work done by ldapssl_install_routines.
1036 int ldapssl_reset_to_nonsecure ( LDAP
*ld
)
1038 PRLDAPSessionInfo sei
;
1039 LDAPSSLSessionInfo
*sseip
;
1041 struct ldap_x_ext_io_fns iofns
;
1045 * Retrieve session info.
1047 memset( &sei
, 0, sizeof(sei
));
1048 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
1049 if ( prldap_get_session_info( ld
, NULL
, &sei
) != LDAP_SUCCESS
) {
1052 sseip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
1054 if ( sseip
!= NULL
) {
1056 * Reset the standard extended io functions.
1058 memset( &iofns
, 0, sizeof(iofns
));
1059 iofns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
1060 if ( ldap_get_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
)
1063 goto free_session_info
;
1066 /* reset socket, connect, and ioctl */
1067 iofns
.lextiof_connect
= sseip
->lssei_std_functions
.lssf_connect_fn
;
1068 iofns
.lextiof_close
= sseip
->lssei_std_functions
.lssf_close_fn
;
1069 iofns
.lextiof_disposehandle
=
1070 sseip
->lssei_std_functions
.lssf_disposehdl_fn
;
1072 if ( ldap_set_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
)
1075 goto free_session_info
;
1079 ldapssl_free_session_info( &sseip
);
1080 sei
.seinfo_appdata
= NULL
;
1081 if ( prldap_set_session_info( ld
, NULL
, &sei
) != LDAP_SUCCESS
) {
1084 } /* if ( sseip && *sseip ) */
1086 if ( ldap_set_option( ld
, LDAP_OPT_SSL
, LDAP_OPT_OFF
) < 0 ) {
1096 _nss_initf_ipnodes(nss_db_params_t
*p
)
1098 static char *no_service
= "";
1100 p
->name
= NSS_DBNAM_IPNODES
;
1101 p
->flags
|= NSS_USE_DEFAULT_CONFIG
;
1102 p
->default_config
= host_service
== NULL
? no_service
: host_service
;
1106 _nss_initf_hosts(nss_db_params_t
*p
)
1108 static char *no_service
= "";
1110 p
->name
= NSS_DBNAM_HOSTS
;
1111 p
->flags
|= NSS_USE_DEFAULT_CONFIG
;
1112 p
->default_config
= host_service
== NULL
? no_service
: host_service
;
1115 static struct hostent
*
1116 _switch_gethostbyaddr_r(const char *addr
, int len
, int type
,
1117 struct hostent
*result
, char *buffer
, int buflen
,
1120 nss_XbyY_args_t arg
;
1123 void (*nss_initf
)();
1124 nss_db_root_t
*nss_db_root
;
1126 if (AF_INET
== type
) {
1127 str2ent
= str2hostent
;
1128 nss_initf
= _nss_initf_hosts
;
1129 nss_db_root
= &db_root_hosts
;
1130 } else if (AF_INET6
== type
) {
1131 str2ent
= str2hostent6
;
1132 nss_initf
= _nss_initf_ipnodes
;
1133 nss_db_root
= &db_root_ipnodes
;
1138 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2ent
);
1140 arg
.key
.hostaddr
.addr
= addr
;
1141 arg
.key
.hostaddr
.len
= len
;
1142 arg
.key
.hostaddr
.type
= type
;
1145 res
= nss_search(nss_db_root
, nss_initf
,
1146 NSS_DBOP_HOSTS_BYADDR
, &arg
);
1148 *h_errnop
= arg
.h_errno
;
1149 return (struct hostent
*)NSS_XbyY_FINI(&arg
);
1153 * ns_gethostbyaddr is used to be a substitute gethostbyaddr for
1154 * libldap when ssl will need to determine the fully qualified
1155 * host name from an address when it is unsafe to use the normal
1156 * nameservice functions.
1158 * Note that the ldap name service resolver calls this with the address as
1159 * a character string - which we must convert into address form.
1163 static LDAPHostEnt
*
1164 ns_gethostbyaddr(const char *addr
, int len
, int type
,
1165 LDAPHostEnt
*result
, char *buffer
, int buflen
, int *statusp
,
1168 LDAPHostEnt
*ldap_hent
;
1170 struct hostent h_ent
;
1171 struct hostent
*h_e
= NULL
;
1174 int inet_error
; /* error returned by inet_pton */
1177 if (addr
== NULL
|| result
== NULL
|| buffer
== NULL
||
1178 (type
!= AF_INET
&& type
!= AF_INET6
))
1182 (void) memset(&h_ent
, 0, sizeof (h_ent
));
1184 if (AF_INET
== type
) {
1185 if (inet_pton(type
, addr
, &a
.s_addr
) == 1) {
1186 h_e
= _switch_gethostbyaddr_r((char *)&a
,
1187 sizeof (a
.s_addr
), type
, &h_ent
,
1188 buffer
, buflen
, &h_errno
);
1190 } else if (AF_INET6
== type
) {
1191 if (inet_pton(type
, addr
, &a6
.s6_addr
) == 1) {
1192 h_e
= _switch_gethostbyaddr_r((char *)&a6
,
1193 sizeof (a6
.s6_addr
), type
, &h_ent
,
1194 buffer
, buflen
, &h_errno
);
1201 (void) memset(result
, 0, sizeof (LDAPHostEnt
));
1203 result
->ldaphe_name
= h_e
->h_name
;
1204 result
->ldaphe_aliases
= h_e
->h_aliases
;
1205 result
->ldaphe_addrtype
= h_e
->h_addrtype
;
1206 result
->ldaphe_length
= h_e
->h_length
;
1207 result
->ldaphe_addr_list
= h_e
->h_addr_list
;
1213 * ldapssl_install_gethostbyaddr attempts to prevent recursion in
1214 * gethostbyaddr calls when an ip address is given to ssl. This ip address
1215 * must be resolved to a host name.
1217 * For example, libsldap cannot use LDAP to resolve this address to a
1218 * name because of recursion. The caller is instructing libldap to skip
1219 * the specified name service when resolving addresses for the specified
1222 * Currently only ldap and dns name services always return fully qualified
1223 * names. The other name services (files, nis, and nisplus) will returned
1224 * fully qualified names if the host names are stored as fully qualified names
1225 * in these name services.
1229 * Since host_service applies to all connections, calling
1230 * ldapssl_install_gethostbyaddr with different name services to
1231 * skip will lead to unpredictable results.
1239 ldapssl_install_gethostbyaddr(LDAP
*ld
, const char *skip
)
1241 enum __nsw_parse_err pserr
;
1242 struct __nsw_switchconfig
*conf
;
1243 struct __nsw_lookup
*lkp
;
1244 struct ldap_dns_fns dns_fns
;
1245 char *name_list
= NULL
;
1249 boolean_t got_skip
= B_FALSE
;
1252 * db_root_hosts.lock mutex is used to ensure that the name list
1253 * is not in use by the name service switch while we are updating
1257 (void) mutex_lock(&db_root_hosts
.lock
);
1258 conf
= __nsw_getconfig("hosts", &pserr
);
1260 (void) mutex_unlock(&db_root_hosts
.lock
);
1264 /* check for ldap and count other backends */
1265 for (lkp
= conf
->lookups
; lkp
!= NULL
; lkp
= lkp
->next
) {
1266 name
= lkp
->service_name
;
1267 if (strcmp(name
, skip
) == 0) {
1271 if (name_list
== NULL
)
1272 name_list
= strdup(name
);
1274 len
= strlen(name_list
);
1275 tmp
= realloc(name_list
, len
+ strlen(name
) + 2);
1281 name_list
[len
++] = ' ';
1282 (void) strcpy(name_list
+len
, name
);
1285 if (name_list
== NULL
) { /* alloc error */
1286 (void) mutex_unlock(&db_root_hosts
.lock
);
1287 __nsw_freeconfig(conf
);
1291 __nsw_freeconfig(conf
);
1294 * Since skip name service not used for hosts, we do not need
1295 * to install our private address resolution function
1297 (void) mutex_unlock(&db_root_hosts
.lock
);
1302 host_service
= name_list
;
1303 (void) mutex_unlock(&db_root_hosts
.lock
);
1305 if (ldap_get_option(ld
, LDAP_OPT_DNS_FN_PTRS
, &dns_fns
) != 0)
1307 dns_fns
.lddnsfn_gethostbyaddr
= ns_gethostbyaddr
;
1308 if (ldap_set_option(ld
, LDAP_OPT_DNS_FN_PTRS
, &dns_fns
) != 0)
1312 #endif /* _SOLARIS_SDK */
1313 #endif /* NET_SSL */