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
28 #pragma ident "%Z%%M% %I% %E% SMI"
36 #if defined( _WINDOWS )
40 /* XXX:mhein The following is a workaround for the redefinition of */
41 /* const problem on OSF. Fix to be provided by NSS */
42 /* This is a pretty benign workaround for us which */
43 /* should not cause problems in the future even if */
44 /* we forget to take it out :-) */
67 #include "solaris-int.h"
72 #include <nss_dbdefs.h>
73 #include <netinet/in.h>
75 #define HOST_BUF_SIZE 2048
78 #define INADDR_NONE (-1)
82 str2hostent(const char *instr
, int lenstr
, void *ent
, char *buffer
,
86 str2hostent6(const char *instr
, int lenstr
, void *ent
, char *buffer
,
90 _ns_gethostbyaddr(LDAP
*ld
, const char *addr
, int length
, int type
,
91 LDAPHostEnt
*result
, char *buffer
, int buflen
, int *statusp
,
94 static char *host_service
= NULL
;
96 static DEFINE_NSS_DB_ROOT(db_root_hosts
);
97 static DEFINE_NSS_DB_ROOT(db_root_ipnodes
);
101 * Data structure to hold the standard NSPR I/O function pointers set by
102 * libprldap. We save them in our session data structure so we can call
103 * them from our own I/O functions (we add functionality to support SSL
104 * while using libprldap's functions as much as possible).
106 typedef struct ldapssl_std_functions
{
107 LDAP_X_EXTIOF_CLOSE_CALLBACK
*lssf_close_fn
;
108 LDAP_X_EXTIOF_CONNECT_CALLBACK
*lssf_connect_fn
;
109 LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK
*lssf_disposehdl_fn
;
110 } LDAPSSLStdFunctions
;
115 * LDAP session data structure.
117 typedef struct ldapssl_session_info
{
118 int lssei_using_pcks_fns
;
119 int lssei_ssl_strength
;
120 char *lssei_certnickname
;
121 char *lssei_keypasswd
;
122 LDAPSSLStdFunctions lssei_std_functions
;
123 CERTCertDBHandle
*lssei_certdbh
;
127 * ld is used so that we can use libldap's gethostbyaddr
128 * resolver. This is needed to prevent recursion with libsldap.
131 #endif /* _SOLARIS_SDK */
132 } LDAPSSLSessionInfo
;
136 * LDAP socket data structure.
138 typedef struct ldapssl_socket_info
{
139 LDAPSSLSessionInfo
*soi_sessioninfo
; /* session info */
144 * XXXceb This is a hack until the new IO functions are done.
145 * this function MUST be called before ldap_enable_clienauth.
146 * right now, this function is called in ldapssl_pkcs_init();
149 static int using_pkcs_functions
= 0;
151 void set_using_pkcs_functions( int val
)
153 using_pkcs_functions
= val
;
160 static void ldapssl_free_session_info( LDAPSSLSessionInfo
**ssipp
);
161 static void ldapssl_free_socket_info( LDAPSSLSocketInfo
**soipp
);
168 static int ldapssl_AuthCertificate(void *sessionarg
, PRFileDesc
*fd
,
169 PRBool checkSig
, PRBool isServer
);
174 static int get_clientauth_data( void *sessionarg
, PRFileDesc
*prfd
,
175 CERTDistNames
*caNames
, CERTCertificate
**pRetCert
,
176 SECKEYPrivateKey
**pRetKey
);
177 static int get_keyandcert( LDAPSSLSessionInfo
*ssip
,
178 CERTCertificate
**pRetCert
, SECKEYPrivateKey
**pRetKey
,
180 static int check_clientauth_nicknames_and_passwd( LDAP
*ld
,
181 LDAPSSLSessionInfo
*ssip
);
182 static char *get_keypassword( PK11SlotInfo
*slot
, PRBool retry
,
189 static int default_ssl_strength
= LDAPSSL_AUTH_CNCHECK
;
191 static int default_ssl_strength
= LDAPSSL_AUTH_CERT
;
195 * Like ldap_init(), except also install I/O routines from libsec so we
196 * can support SSL. If defsecure is non-zero, SSL is enabled for the
197 * default connection as well.
201 ldapssl_init( const char *defhost
, int defport
, int defsecure
)
206 #ifndef LDAP_SSLIO_HOOKS
210 defport
= LDAPS_PORT
;
212 if (( ld
= ldap_init( defhost
, defport
)) == NULL
) {
216 if ( ldapssl_install_routines( ld
) < 0 || ldap_set_option( ld
,
217 LDAP_OPT_SSL
, defsecure
? LDAP_OPT_ON
: LDAP_OPT_OFF
) != 0 ) {
218 PR_SetError( PR_UNKNOWN_ERROR
, EINVAL
); /* XXXmcs: just a guess! */
229 ldapssl_close(int s
, struct lextiof_socket_private
*socketarg
)
231 PRLDAPSocketInfo soi
;
232 LDAPSSLSocketInfo
*ssoip
;
233 LDAPSSLSessionInfo
*sseip
;
235 memset( &soi
, 0, sizeof(soi
));
236 soi
.soinfo_size
= PRLDAP_SOCKETINFO_SIZE
;
237 if ( prldap_get_socket_info( s
, socketarg
, &soi
) != LDAP_SUCCESS
) {
241 ssoip
= (LDAPSSLSocketInfo
*)soi
.soinfo_appdata
;
242 sseip
= ssoip
->soi_sessioninfo
;
244 ldapssl_free_socket_info( (LDAPSSLSocketInfo
**)&soi
.soinfo_appdata
);
246 return( (*(sseip
->lssei_std_functions
.lssf_close_fn
))( s
, socketarg
));
250 do_ldapssl_connect(const char *hostlist
, int defport
, int timeout
,
251 unsigned long options
, struct lextiof_session_private
*sessionarg
,
252 struct lextiof_socket_private
**socketargp
, int clientauth
)
256 PRLDAPSessionInfo sei
;
257 PRLDAPSocketInfo soi
;
258 LDAPSSLSocketInfo
*ssoip
= NULL
;
259 LDAPSSLSessionInfo
*sseip
;
260 PRFileDesc
*sslfd
= NULL
;
266 struct ldap_x_hostlist_status
269 in6_addr_t addr_ipv6
;
272 LDAPHostEnt host_ent
;
275 #endif /* _SOLARIS_SDK */
278 * Determine if secure option is set. Also, clear secure bit in options
279 * the we pass to the standard connect() function (since it doesn't know
280 * how to handle the secure option).
282 if ( 0 != ( options
& LDAP_X_EXTIOF_OPT_SECURE
)) {
284 options
&= ~LDAP_X_EXTIOF_OPT_SECURE
;
290 * Retrieve session info. so we can store a pointer to our session info.
291 * in our socket info. later.
293 memset( &sei
, 0, sizeof(sei
));
294 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
295 if ( prldap_get_session_info( NULL
, sessionarg
, &sei
) != LDAP_SUCCESS
) {
298 sseip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
301 * Call the standard connect() callback to make the TCP connection.
302 * If it succeeds, *socketargp is set.
305 intfd
= (*(sseip
->lssei_std_functions
.lssf_connect_fn
))( hostlist
, defport
,
306 timeout
, options
, sessionarg
, socketargp
311 #endif /* _SOLARIS_SDK */
319 * Determine if the "host name" is an ip address. If so,
320 * we must look up the actual host name corresponding to
323 if ( NULL
== host
) {
324 goto close_socket_and_exit_with_error
;
327 if (strlen(host
) < INET6_ADDRSTRLEN
&&
328 inet_pton(AF_INET6
, host
, &addr_ipv6
) == 1) {
330 } else if (strlen(host
) < INET_ADDRSTRLEN
&&
331 inet_pton(AF_INET
, host
, &addr_ipv4
) == 1) {
334 if (type
== AF_INET
|| type
== AF_INET6
) {
335 host_buf
= malloc(HOST_BUF_SIZE
);
336 if (host_buf
== NULL
) {
337 /* will free host in close_socket_and_exit_with_error */
338 goto close_socket_and_exit_with_error
;
341 /* Call ldap layer's gethostbyaddr resolver */
342 hent
= _ns_gethostbyaddr(sseip
->ld
, host
, strlen(host
), type
,
343 &host_ent
, host_buf
, HOST_BUF_SIZE
, &stat
, NULL
);
345 /* If we are unable to lookup the host addr, we fail! */
348 "libldap: do_ldapssl_connect: "
349 "Unable to resolve '%s'", host
);
351 /* will free host in close_socket_and_exit_with_error */
352 goto close_socket_and_exit_with_error
;
354 /* We support only the primary host name */
356 if (hent
->ldaphe_name
!= NULL
)
357 name
= strdup(hent
->ldaphe_name
);
360 goto close_socket_and_exit_with_error
;
362 ldap_memfree(host
); host
= NULL
;
366 #endif /* _SOLARIS_SDK */
369 * Retrieve socket info. so we have the PRFileDesc.
371 memset( &soi
, 0, sizeof(soi
));
372 soi
.soinfo_size
= PRLDAP_SOCKETINFO_SIZE
;
373 if ( prldap_get_socket_info( intfd
, *socketargp
, &soi
) != LDAP_SUCCESS
) {
374 goto close_socket_and_exit_with_error
;
378 * Allocate a structure to hold our socket-specific data.
380 if ( NULL
== ( ssoip
= PR_Calloc( 1, sizeof( LDAPSSLSocketInfo
)))) {
381 goto close_socket_and_exit_with_error
;
383 ssoip
->soi_sessioninfo
= sseip
;
386 * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
388 if (( sslfd
= SSL_ImportFD( NULL
, soi
.soinfo_prfd
)) == NULL
) {
389 goto close_socket_and_exit_with_error
;
392 if ( SSL_OptionSet( sslfd
, SSL_SECURITY
, secure
) != SECSuccess
||
393 SSL_OptionSet( sslfd
, SSL_HANDSHAKE_AS_CLIENT
, secure
)
394 != SECSuccess
|| ( secure
&& SSL_ResetHandshake( sslfd
,
395 PR_FALSE
) != SECSuccess
)) {
396 goto close_socket_and_exit_with_error
;
400 * Let the standard NSPR to LDAP layer know about the new socket and
401 * our own socket-specific data.
403 soi
.soinfo_prfd
= sslfd
;
404 soi
.soinfo_appdata
= (void *)ssoip
;
405 if ( prldap_set_socket_info( intfd
, *socketargp
, &soi
) != LDAP_SUCCESS
) {
406 goto close_socket_and_exit_with_error
;
411 * Set hostname which will be retrieved (depending on ssl strength) when
412 * using client or server auth.
414 if (SSL_SetURL(sslfd
, host
) != SECSuccess
)
415 goto close_socket_and_exit_with_error
;
418 #endif /* _SOLARIS_SDK */
420 sslfd
= NULL
; /* so we don't close the socket twice upon error */
423 * Install certificate hook function.
425 SSL_AuthCertificateHook( soi
.soinfo_prfd
,
426 (SSLAuthCertificate
)ldapssl_AuthCertificate
,
429 if ( SSL_GetClientAuthDataHook( soi
.soinfo_prfd
,
430 get_clientauth_data
, clientauth
? sseip
: NULL
) != 0 ) {
431 goto close_socket_and_exit_with_error
;
434 return( intfd
); /* success */
436 close_socket_and_exit_with_error
:
438 if ( NULL
!= host
) ldap_memfree(host
);
439 #endif /* _SOLARIS_SDK */
440 if ( NULL
!= sslfd
) {
443 if ( NULL
!= ssoip
) {
444 ldapssl_free_socket_info( &ssoip
);
446 if ( intfd
>= 0 && NULL
!= *socketargp
) {
447 (*(sseip
->lssei_std_functions
.lssf_close_fn
))( intfd
, *socketargp
);
454 ldapssl_connect(const char *hostlist
, int defport
, int timeout
,
455 unsigned long options
, struct lextiof_session_private
*sessionarg
,
456 struct lextiof_socket_private
**socketargp
)
458 return( do_ldapssl_connect( hostlist
, defport
, timeout
, options
,
459 sessionarg
, socketargp
, 0 ));
464 ldapssl_clientauth_connect(const char *hostlist
, int defport
, int timeout
,
465 unsigned long options
, struct lextiof_session_private
*sessionarg
,
466 struct lextiof_socket_private
**socketargp
)
468 return( do_ldapssl_connect( hostlist
, defport
, timeout
, options
,
469 sessionarg
, socketargp
, 1 ));
474 ldapssl_disposehandle(LDAP
*ld
, struct lextiof_session_private
*sessionarg
)
476 PRLDAPSessionInfo sei
;
477 LDAPSSLSessionInfo
*sseip
;
478 LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK
*disposehdl_fn
;
480 memset( &sei
, 0, sizeof( sei
));
481 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
482 if ( prldap_get_session_info( ld
, NULL
, &sei
) == LDAP_SUCCESS
) {
483 sseip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
484 disposehdl_fn
= sseip
->lssei_std_functions
.lssf_disposehdl_fn
;
485 ldapssl_free_session_info( &sseip
);
486 (*disposehdl_fn
)( ld
, sessionarg
);
492 * Install I/O routines from libsec and NSPR into libldap to allow libldap
495 * We rely on libprldap to provide most of the functions, and then we override
496 * a few of them to support SSL.
500 ldapssl_install_routines( LDAP
*ld
)
502 #ifndef LDAP_SSLIO_HOOKS
503 ldap_set_lderrno( ld
, LDAP_LOCAL_ERROR
, NULL
, NULL
);
506 struct ldap_x_ext_io_fns iofns
;
507 LDAPSSLSessionInfo
*ssip
;
508 PRLDAPSessionInfo sei
;
511 * This is done within ldap_init() and
512 * ldap_init() is called from ldapssl_init()
515 if ( prldap_install_routines(
517 1 /* shared -- we have to assume it is */ )
521 #endif /*_SOLARIS_SDK*/
524 * Allocate our own session information.
526 if ( NULL
== ( ssip
= (LDAPSSLSessionInfo
*)PR_Calloc( 1,
527 sizeof( LDAPSSLSessionInfo
)))) {
528 ldap_set_lderrno( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
532 * Initialize session info.
533 * XXX: it would be nice to be able to set these on a per-session basis:
534 * lssei_using_pcks_fns
537 ssip
->lssei_ssl_strength
= default_ssl_strength
;
538 ssip
->lssei_using_pcks_fns
= using_pkcs_functions
;
539 ssip
->lssei_certdbh
= CERT_GetDefaultCertDB();
542 * This is part of a hack to allow the ssl portion of the
543 * library to call the ldap library gethostbyaddr resolver.
546 #endif /* _SOLARIS_SDK */
549 * override a few functions, saving a pointer to the standard function
550 * in each case so we can call it from our SSL savvy functions.
552 memset( &iofns
, 0, sizeof(iofns
));
553 iofns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
554 if ( ldap_get_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
) < 0 ) {
555 ldapssl_free_session_info( &ssip
);
559 /* override socket, connect, and ioctl */
560 ssip
->lssei_std_functions
.lssf_connect_fn
= iofns
.lextiof_connect
;
561 iofns
.lextiof_connect
= ldapssl_connect
;
562 ssip
->lssei_std_functions
.lssf_close_fn
= iofns
.lextiof_close
;
563 iofns
.lextiof_close
= ldapssl_close
;
564 ssip
->lssei_std_functions
.lssf_disposehdl_fn
= iofns
.lextiof_disposehandle
;
565 iofns
.lextiof_disposehandle
= ldapssl_disposehandle
;
567 if ( ldap_set_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
) < 0 ) {
568 ldapssl_free_session_info( &ssip
);
573 * Store session info. for later retrieval.
575 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
576 sei
.seinfo_appdata
= (void *)ssip
;
577 if ( prldap_set_session_info( ld
, NULL
, &sei
) != LDAP_SUCCESS
) {
587 * Set the SSL strength for an existing SSL-enabled LDAP session handle.
589 * See the description of ldapssl_serverauth_init() above for valid
590 * sslstrength values. If ld is NULL, the default for new LDAP session
593 * Returns 0 if all goes well and -1 if an error occurs.
597 ldapssl_set_strength( LDAP
*ld
, int sslstrength
)
599 int rc
= 0; /* assume success */
601 if ( sslstrength
!= LDAPSSL_AUTH_WEAK
&&
602 sslstrength
!= LDAPSSL_AUTH_CERT
&&
603 sslstrength
!= LDAPSSL_AUTH_CNCHECK
) {
606 if ( NULL
== ld
) { /* set default strength */
607 default_ssl_strength
= sslstrength
;
608 } else { /* set session-specific strength */
609 PRLDAPSessionInfo sei
;
610 LDAPSSLSessionInfo
*sseip
;
612 memset( &sei
, 0, sizeof( sei
));
613 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
614 if ( prldap_get_session_info( ld
, NULL
, &sei
) == LDAP_SUCCESS
)
616 sseip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
617 sseip
->lssei_ssl_strength
= sslstrength
;
629 ldapssl_enable_clientauth( LDAP
*ld
, char *keynickname
,
630 char *keypasswd
, char *certnickname
)
632 #ifndef LDAP_SSLIO_HOOKS
633 ldap_set_lderrno( ld
, LDAP_LOCAL_ERROR
, NULL
, NULL
);
636 struct ldap_x_ext_io_fns iofns
;
637 LDAPSSLSessionInfo
*ssip
;
638 PRLDAPSessionInfo sei
;
643 if ( certnickname
== NULL
|| keypasswd
== NULL
) {
644 ldap_set_lderrno( ld
, LDAP_PARAM_ERROR
, NULL
, NULL
);
649 * Update session info. data structure.
651 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
652 if ( prldap_get_session_info( ld
, NULL
, &sei
) != LDAP_SUCCESS
) {
655 ssip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
656 if ( NULL
== ssip
) {
657 ldap_set_lderrno( ld
, LDAP_PARAM_ERROR
, NULL
, NULL
);
660 ssip
->lssei_certnickname
= PL_strdup( certnickname
);
661 ssip
->lssei_keypasswd
= PL_strdup( keypasswd
);
663 if ( NULL
== ssip
->lssei_certnickname
|| NULL
== ssip
->lssei_keypasswd
) {
664 ldap_set_lderrno( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
668 if ( check_clientauth_nicknames_and_passwd( ld
, ssip
) != 0 ) {
673 * replace standard SSL CONNECT function with client auth aware one
675 memset( &iofns
, 0, sizeof(iofns
));
676 iofns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
677 if ( ldap_get_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
)
682 if ( iofns
.lextiof_connect
!= ldapssl_connect
) {
683 /* standard SSL setup has not done */
684 ldap_set_lderrno( ld
, LDAP_PARAM_ERROR
, NULL
, NULL
);
688 iofns
.lextiof_connect
= ldapssl_clientauth_connect
;
690 if ( ldap_set_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
)
701 ldapssl_free_session_info( LDAPSSLSessionInfo
**ssipp
)
703 if ( NULL
!= ssipp
&& NULL
!= *ssipp
) {
704 if ( NULL
!= (*ssipp
)->lssei_certnickname
) {
705 PL_strfree( (*ssipp
)->lssei_certnickname
);
706 (*ssipp
)->lssei_certnickname
= NULL
;
708 if ( NULL
!= (*ssipp
)->lssei_keypasswd
) {
709 PL_strfree( (*ssipp
)->lssei_keypasswd
);
710 (*ssipp
)->lssei_keypasswd
= NULL
;
719 ldapssl_free_socket_info( LDAPSSLSocketInfo
**soipp
)
721 if ( NULL
!= soipp
&& NULL
!= *soipp
) {
728 /* this function provides cert authentication. This is called during
729 * the SSL_Handshake process. Once the cert has been retrieved from
730 * the server, the it is checked, using VerifyCertNow(), then
731 * the cn is checked against the host name, set with SSL_SetURL()
735 ldapssl_AuthCertificate(void *sessionarg
, PRFileDesc
*fd
, PRBool checkSig
,
738 SECStatus rv
= SECFailure
;
739 LDAPSSLSessionInfo
*sseip
;
740 CERTCertificate
*cert
;
741 SECCertUsage certUsage
;
742 char *hostname
= (char *)0;
744 if (!sessionarg
|| !socket
)
747 sseip
= (LDAPSSLSessionInfo
*)sessionarg
;
749 if (LDAPSSL_AUTH_WEAK
== sseip
->lssei_ssl_strength
) { /* no check */
754 certUsage
= certUsageSSLClient
;
756 certUsage
= certUsageSSLServer
;
758 cert
= SSL_PeerCertificate( fd
);
760 rv
= CERT_VerifyCertNow(sseip
->lssei_certdbh
, cert
, checkSig
,
763 if ( rv
!= SECSuccess
|| isServer
)
766 if ( LDAPSSL_AUTH_CNCHECK
== sseip
->lssei_ssl_strength
)
768 /* cert is OK. This is the client side of an SSL connection.
769 * Now check the name field in the cert against the desired hostname.
770 * NB: This is our only defense against Man-In-The-Middle (MITM)
774 hostname
= SSL_RevealURL( fd
);
776 if (hostname
&& hostname
[0]) {
777 rv
= CERT_VerifyCertName(cert
, hostname
);
783 if (rv
!= SECSuccess
)
784 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN
);
792 * called during SSL client auth. when server wants our cert and key.
793 * return 0 if we succeeded and set *pRetCert and *pRetKey, -1 otherwise.
794 * if -1 is returned SSL will proceed without sending a cert.
798 get_clientauth_data( void *sessionarg
, PRFileDesc
*prfd
,
799 CERTDistNames
*caNames
, CERTCertificate
**pRetCert
,
800 SECKEYPrivateKey
**pRetKey
)
803 LDAPSSLSessionInfo
*ssip
;
805 if (( ssip
= (LDAPSSLSessionInfo
*)sessionarg
) == NULL
) {
806 return( -1 ); /* client auth. not enabled */
809 return( get_keyandcert( ssip
, pRetCert
, pRetKey
, NULL
));
813 get_keyandcert( LDAPSSLSessionInfo
*ssip
,
814 CERTCertificate
**pRetCert
, SECKEYPrivateKey
**pRetKey
,
817 CERTCertificate
*cert
;
818 SECKEYPrivateKey
*key
;
820 if (( cert
= PK11_FindCertFromNickname( ssip
->lssei_certnickname
, NULL
))
822 if ( errmsgp
!= NULL
) {
823 *errmsgp
= dgettext(TEXT_DOMAIN
, "unable to find certificate");
829 PK11_SetPasswordFunc( get_keypassword
);
834 if (( key
= PK11_FindKeyByAnyCert( cert
, (void *)ssip
)) == NULL
) {
835 CERT_DestroyCertificate( cert
);
836 if ( errmsgp
!= NULL
) {
837 *errmsgp
= dgettext(TEXT_DOMAIN
, "bad key or key password");
849 * This function returns the password to NSS.
850 * This function is enable through PK11_SetPasswordFunc
851 * only if pkcs functions are not being used.
855 get_keypassword( PK11SlotInfo
*slot
, PRBool retry
, void *sessionarg
)
857 LDAPSSLSessionInfo
*ssip
;
862 ssip
= (LDAPSSLSessionInfo
*)sessionarg
;
863 if ( NULL
== ssip
) {
867 return( ssip
->lssei_keypasswd
);
872 * performs some basic checks on clientauth cert and key/password
874 * XXXmcs: could perform additional checks... see servers/slapd/ssl.c
875 * 1) check expiration
876 * 2) check that public key in cert matches private key
877 * see ns/netsite/ldap/servers/slapd/ssl.c:slapd_ssl_init() for example code.
880 check_clientauth_nicknames_and_passwd( LDAP
*ld
, LDAPSSLSessionInfo
*ssip
)
883 CERTCertificate
*cert
= NULL
;
884 SECKEYPrivateKey
*key
= NULL
;
887 rv
= get_keyandcert( ssip
, &cert
, &key
, &errmsg
);
890 if ( errmsg
!= NULL
) {
891 errmsg
= strdup( errmsg
);
893 ldap_set_lderrno( ld
, LDAP_PARAM_ERROR
, NULL
, errmsg
);
897 if ( cert
!= NULL
) {
898 CERT_DestroyCertificate( cert
);
901 SECKEY_DestroyPrivateKey( key
);
907 #if 0 /* NOT_NEEDED_IN_LIBLDAP */
908 /* there are patches and kludges. this is both. force some linkers to
911 int stubs_o_stuff( void )
913 PRExplodedTime exploded
;
916 const char *name
="t";
917 PRUint32 size
= 0, align
= 0;
919 PR_ImplodeTime( &exploded
);
920 PL_InitArenaPool( &pool
, name
, size
, align
);
922 PR_fprintf((PRFileDesc
*)stderr
, "Bad IDEA!!");
927 #endif /* NOT_NEEDED_IN_LIBLDAP */
931 * Import the file descriptor corresponding to the socket of an already
932 * open LDAP connection into SSL, and update the socket and session
933 * information accordingly.
935 int ldapssl_import_fd ( LDAP
*ld
, int secure
)
937 PRLDAPSessionInfo sei
;
938 PRLDAPSocketInfo soi
;
939 LDAPSSLSocketInfo
*ssoip
= NULL
;
940 LDAPSSLSessionInfo
*sseip
;
941 PRFileDesc
*sslfd
= NULL
;
945 * Retrieve session info. so we can store a pointer to our session info.
946 * in our socket info. later.
948 memset( &sei
, 0, sizeof(sei
));
949 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
950 if ( prldap_get_session_info( ld
, NULL
, &sei
) != LDAP_SUCCESS
) {
953 sseip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
957 * Retrieve socket info. so we have the PRFileDesc.
959 memset( &soi
, 0, sizeof(soi
));
960 soi
.soinfo_size
= PRLDAP_SOCKETINFO_SIZE
;
961 if ( prldap_get_default_socket_info( ld
, &soi
) != LDAP_SUCCESS
) {
966 * Allocate a structure to hold our socket-specific data.
968 if ( NULL
== ( ssoip
= PR_Calloc( 1, sizeof( LDAPSSLSocketInfo
)))) {
969 goto reset_socket_and_exit_with_error
;
971 ssoip
->soi_sessioninfo
= sseip
;
974 * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
976 if (( sslfd
= SSL_ImportFD( NULL
, soi
.soinfo_prfd
)) == NULL
) {
977 goto reset_socket_and_exit_with_error
;
980 if ( SSL_OptionSet( sslfd
, SSL_SECURITY
, secure
) != SECSuccess
||
981 SSL_OptionSet( sslfd
, SSL_HANDSHAKE_AS_CLIENT
, secure
)
982 != SECSuccess
|| ( secure
&& SSL_ResetHandshake( sslfd
,
983 PR_FALSE
) != SECSuccess
)) {
984 goto reset_socket_and_exit_with_error
;
988 * Let the standard NSPR to LDAP layer know about the new socket and
989 * our own socket-specific data.
991 soi
.soinfo_prfd
= sslfd
;
992 soi
.soinfo_appdata
= (void *)ssoip
;
993 if ( prldap_set_default_socket_info( ld
, &soi
) != LDAP_SUCCESS
) {
994 goto reset_socket_and_exit_with_error
;
998 * Install certificate hook function.
1000 if ( SSL_AuthCertificateHook( soi
.soinfo_prfd
,
1001 (SSLAuthCertificate
)ldapssl_AuthCertificate
,
1002 (void *)CERT_GetDefaultCertDB()) != 0 ) {
1003 goto reset_socket_and_exit_with_error
;
1006 if ( SSL_GetClientAuthDataHook( soi
.soinfo_prfd
,
1007 get_clientauth_data
, sseip
->lssei_certnickname
? sseip
: NULL
)
1009 goto reset_socket_and_exit_with_error
;
1014 reset_socket_and_exit_with_error
:
1015 if ( NULL
!= sslfd
) {
1017 * "Unimport" the socket from SSL, i.e. get rid of the upper layer of
1018 * the file descriptor stack, which represents SSL.
1020 soi
.soinfo_prfd
= sslfd
;
1021 sslfd
= PR_PopIOLayer( soi
.soinfo_prfd
, PR_TOP_IO_LAYER
);
1022 sslfd
->dtor( sslfd
);
1024 if ( NULL
!= ssoip
) {
1025 ldapssl_free_socket_info( &ssoip
);
1026 soi
.soinfo_appdata
= NULL
;
1028 prldap_set_default_socket_info( ld
, &soi
);
1035 * Reset an LDAP session from SSL to a non-secure status.
1036 * Basically, this function undoes the work done by ldapssl_install_routines.
1038 int ldapssl_reset_to_nonsecure ( LDAP
*ld
)
1040 PRLDAPSessionInfo sei
;
1041 LDAPSSLSessionInfo
*sseip
;
1043 struct ldap_x_ext_io_fns iofns
;
1047 * Retrieve session info.
1049 memset( &sei
, 0, sizeof(sei
));
1050 sei
.seinfo_size
= PRLDAP_SESSIONINFO_SIZE
;
1051 if ( prldap_get_session_info( ld
, NULL
, &sei
) != LDAP_SUCCESS
) {
1054 sseip
= (LDAPSSLSessionInfo
*)sei
.seinfo_appdata
;
1056 if ( sseip
!= NULL
) {
1058 * Reset the standard extended io functions.
1060 memset( &iofns
, 0, sizeof(iofns
));
1061 iofns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
1062 if ( ldap_get_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
)
1065 goto free_session_info
;
1068 /* reset socket, connect, and ioctl */
1069 iofns
.lextiof_connect
= sseip
->lssei_std_functions
.lssf_connect_fn
;
1070 iofns
.lextiof_close
= sseip
->lssei_std_functions
.lssf_close_fn
;
1071 iofns
.lextiof_disposehandle
=
1072 sseip
->lssei_std_functions
.lssf_disposehdl_fn
;
1074 if ( ldap_set_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
)
1077 goto free_session_info
;
1081 ldapssl_free_session_info( &sseip
);
1082 sei
.seinfo_appdata
= NULL
;
1083 if ( prldap_set_session_info( ld
, NULL
, &sei
) != LDAP_SUCCESS
) {
1086 } /* if ( sseip && *sseip ) */
1088 if ( ldap_set_option( ld
, LDAP_OPT_SSL
, LDAP_OPT_OFF
) < 0 ) {
1098 _nss_initf_ipnodes(nss_db_params_t
*p
)
1100 static char *no_service
= "";
1102 p
->name
= NSS_DBNAM_IPNODES
;
1103 p
->flags
|= NSS_USE_DEFAULT_CONFIG
;
1104 p
->default_config
= host_service
== NULL
? no_service
: host_service
;
1108 _nss_initf_hosts(nss_db_params_t
*p
)
1110 static char *no_service
= "";
1112 p
->name
= NSS_DBNAM_HOSTS
;
1113 p
->flags
|= NSS_USE_DEFAULT_CONFIG
;
1114 p
->default_config
= host_service
== NULL
? no_service
: host_service
;
1117 static struct hostent
*
1118 _switch_gethostbyaddr_r(const char *addr
, int len
, int type
,
1119 struct hostent
*result
, char *buffer
, int buflen
,
1122 nss_XbyY_args_t arg
;
1125 void (*nss_initf
)();
1126 nss_db_root_t
*nss_db_root
;
1128 if (AF_INET
== type
) {
1129 str2ent
= str2hostent
;
1130 nss_initf
= _nss_initf_hosts
;
1131 nss_db_root
= &db_root_hosts
;
1132 } else if (AF_INET6
== type
) {
1133 str2ent
= str2hostent6
;
1134 nss_initf
= _nss_initf_ipnodes
;
1135 nss_db_root
= &db_root_ipnodes
;
1140 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2ent
);
1142 arg
.key
.hostaddr
.addr
= addr
;
1143 arg
.key
.hostaddr
.len
= len
;
1144 arg
.key
.hostaddr
.type
= type
;
1147 res
= nss_search(nss_db_root
, nss_initf
,
1148 NSS_DBOP_HOSTS_BYADDR
, &arg
);
1150 *h_errnop
= arg
.h_errno
;
1151 return (struct hostent
*)NSS_XbyY_FINI(&arg
);
1155 * ns_gethostbyaddr is used to be a substitute gethostbyaddr for
1156 * libldap when ssl will need to determine the fully qualified
1157 * host name from an address when it is unsafe to use the normal
1158 * nameservice functions.
1160 * Note that the ldap name service resolver calls this with the address as
1161 * a character string - which we must convert into address form.
1165 static LDAPHostEnt
*
1166 ns_gethostbyaddr(const char *addr
, int len
, int type
,
1167 LDAPHostEnt
*result
, char *buffer
, int buflen
, int *statusp
,
1170 LDAPHostEnt
*ldap_hent
;
1172 struct hostent h_ent
;
1173 struct hostent
*h_e
= NULL
;
1176 int inet_error
; /* error returned by inet_pton */
1179 if (addr
== NULL
|| result
== NULL
|| buffer
== NULL
||
1180 (type
!= AF_INET
&& type
!= AF_INET6
))
1184 (void) memset(&h_ent
, 0, sizeof (h_ent
));
1186 if (AF_INET
== type
) {
1187 if (inet_pton(type
, addr
, &a
.s_addr
) == 1) {
1188 h_e
= _switch_gethostbyaddr_r((char *)&a
,
1189 sizeof (a
.s_addr
), type
, &h_ent
,
1190 buffer
, buflen
, &h_errno
);
1192 } else if (AF_INET6
== type
) {
1193 if (inet_pton(type
, addr
, &a6
.s6_addr
) == 1) {
1194 h_e
= _switch_gethostbyaddr_r((char *)&a6
,
1195 sizeof (a6
.s6_addr
), type
, &h_ent
,
1196 buffer
, buflen
, &h_errno
);
1203 (void) memset(result
, 0, sizeof (LDAPHostEnt
));
1205 result
->ldaphe_name
= h_e
->h_name
;
1206 result
->ldaphe_aliases
= h_e
->h_aliases
;
1207 result
->ldaphe_addrtype
= h_e
->h_addrtype
;
1208 result
->ldaphe_length
= h_e
->h_length
;
1209 result
->ldaphe_addr_list
= h_e
->h_addr_list
;
1215 * ldapssl_install_gethostbyaddr attempts to prevent recursion in
1216 * gethostbyaddr calls when an ip address is given to ssl. This ip address
1217 * must be resolved to a host name.
1219 * For example, libsldap cannot use LDAP to resolve this address to a
1220 * name because of recursion. The caller is instructing libldap to skip
1221 * the specified name service when resolving addresses for the specified
1224 * Currently only ldap and dns name services always return fully qualified
1225 * names. The other name services (files, nis, and nisplus) will returned
1226 * fully qualified names if the host names are stored as fully qualified names
1227 * in these name services.
1231 * Since host_service applies to all connections, calling
1232 * ldapssl_install_gethostbyaddr with different name services to
1233 * skip will lead to unpredictable results.
1241 ldapssl_install_gethostbyaddr(LDAP
*ld
, const char *skip
)
1243 enum __nsw_parse_err pserr
;
1244 struct __nsw_switchconfig
*conf
;
1245 struct __nsw_lookup
*lkp
;
1246 struct ldap_dns_fns dns_fns
;
1247 char *name_list
= NULL
;
1251 boolean_t got_skip
= B_FALSE
;
1254 * db_root_hosts.lock mutex is used to ensure that the name list
1255 * is not in use by the name service switch while we are updating
1259 (void) mutex_lock(&db_root_hosts
.lock
);
1260 conf
= __nsw_getconfig("hosts", &pserr
);
1262 (void) mutex_unlock(&db_root_hosts
.lock
);
1266 /* check for ldap and count other backends */
1267 for (lkp
= conf
->lookups
; lkp
!= NULL
; lkp
= lkp
->next
) {
1268 name
= lkp
->service_name
;
1269 if (strcmp(name
, skip
) == 0) {
1273 if (name_list
== NULL
)
1274 name_list
= strdup(name
);
1276 len
= strlen(name_list
);
1277 tmp
= realloc(name_list
, len
+ strlen(name
) + 2);
1283 name_list
[len
++] = ' ';
1284 (void) strcpy(name_list
+len
, name
);
1287 if (name_list
== NULL
) { /* alloc error */
1288 (void) mutex_unlock(&db_root_hosts
.lock
);
1289 __nsw_freeconfig(conf
);
1293 __nsw_freeconfig(conf
);
1296 * Since skip name service not used for hosts, we do not need
1297 * to install our private address resolution function
1299 (void) mutex_unlock(&db_root_hosts
.lock
);
1300 if (name_list
!= NULL
)
1304 if (host_service
!= NULL
)
1306 host_service
= name_list
;
1307 (void) mutex_unlock(&db_root_hosts
.lock
);
1309 if (ldap_get_option(ld
, LDAP_OPT_DNS_FN_PTRS
, &dns_fns
) != 0)
1311 dns_fns
.lddnsfn_gethostbyaddr
= ns_gethostbyaddr
;
1312 if (ldap_set_option(ld
, LDAP_OPT_DNS_FN_PTRS
, &dns_fns
) != 0)
1316 #endif /* _SOLARIS_SDK */
1317 #endif /* NET_SSL */