/*
*/
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/*
*/
#if defined(NET_SSL)
#if defined( _WINDOWS )
#include <windows.h>
#endif
/* XXX:mhein The following is a workaround for the redefinition of */
/* const problem on OSF. Fix to be provided by NSS */
/* This is a pretty benign workaround for us which */
/* should not cause problems in the future even if */
/* we forget to take it out :-) */
#ifdef OSF1V4D
#ifndef __STDC__
# define __STDC__
#endif /* __STDC__ */
#endif /* OSF1V4D */
#include <errno.h>
#include <nspr.h>
#include <cert.h>
#include <key.h>
#include <ssl.h>
#include <sslproto.h>
#include <sslerr.h>
#include <prnetdb.h>
#include <ldap.h>
#include <ldappr.h>
#include <pk11func.h>
#ifdef _SOLARIS_SDK
#include "solaris-int.h"
#include <libintl.h>
#include <syslog.h>
#include <nsswitch.h>
#include <synch.h>
#include <nss_dbdefs.h>
#ifndef INADDR_NONE
#endif
extern int
int buflen);
extern int
int buflen);
extern LDAPHostEnt *
void *extradata);
static DEFINE_NSS_DB_ROOT(db_root_hosts);
static DEFINE_NSS_DB_ROOT(db_root_ipnodes);
#endif
/*
* Data structure to hold the standard NSPR I/O function pointers set by
* libprldap. We save them in our session data structure so we can call
* them from our own I/O functions (we add functionality to support SSL
* while using libprldap's functions as much as possible).
*/
typedef struct ldapssl_std_functions {
/*
* LDAP session data structure.
*/
typedef struct ldapssl_session_info {
int lssei_using_pcks_fns;
int lssei_ssl_strength;
char *lssei_certnickname;
char *lssei_keypasswd;
#ifdef _SOLARIS_SDK
/*
* This is a hack.
* ld is used so that we can use libldap's gethostbyaddr
* resolver. This is needed to prevent recursion with libsldap.
*/
#endif /* _SOLARIS_SDK */
/*
* LDAP socket data structure.
*/
typedef struct ldapssl_socket_info {
/*
* XXXceb This is a hack until the new IO functions are done.
* this function MUST be called before ldap_enable_clienauth.
* right now, this function is called in ldapssl_pkcs_init();
*/
static int using_pkcs_functions = 0;
{
}
/*
* Utility functions:
*/
/*
* SSL Stuff
*/
/*
* client auth stuff
*/
SECKEYPrivateKey **pRetKey );
char **errmsgp );
void *sessionarg );
/*
* Static variables.
*/
#ifdef _SOLARIS_SDK
#else
#endif
/*
* Like ldap_init(), except also install I/O routines from libsec so we
* can support SSL. If defsecure is non-zero, SSL is enabled for the
* default connection as well.
*/
LDAP *
{
#ifndef LDAP_SSLIO_HOOKS
return( NULL );
#else
if (0 ==defport)
return( NULL );
}
ldap_unbind( ld );
return( NULL );
}
return( ld );
#endif
}
static int
{
return( -1 );
}
}
static int
{
#ifdef _SOLARIS_SDK
int port;
int parse_err;
char *name;
struct ldap_x_hostlist_status
char *host_buf;
int stat;
int type;
#endif /* _SOLARIS_SDK */
/*
* Determine if secure option is set. Also, clear secure bit in options
* the we pass to the standard connect() function (since it doesn't know
* how to handle the secure option).
*/
if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
} else {
}
/*
* Retrieve session info. so we can store a pointer to our session info.
* in our socket info. later.
*/
return( -1 );
}
/*
* Call the standard connect() callback to make the TCP connection.
* If it succeeds, *socketargp is set.
*/
#ifdef _SOLARIS_SDK
, &host );
#else
);
#endif /* _SOLARIS_SDK */
if ( intfd < 0 ) {
return( intfd );
}
#ifdef _SOLARIS_SDK
/*
* Determine if the "host name" is an ip address. If so,
* we must look up the actual host name corresponding to
* it.
*/
}
}
/* will free host in close_socket_and_exit_with_error */
}
/* Call ldap layer's gethostbyaddr resolver */
/* If we are unable to lookup the host addr, we fail! */
"libldap: do_ldapssl_connect: "
"Unable to resolve '%s'", host);
/* will free host in close_socket_and_exit_with_error */
}
/* We support only the primary host name */
else {
else
}
}
#endif /* _SOLARIS_SDK */
/*
* Retrieve socket info. so we have the PRFileDesc.
*/
}
/*
* Allocate a structure to hold our socket-specific data.
*/
}
/*
* Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
*/
}
PR_FALSE ) != SECSuccess )) {
}
/*
* Let the standard NSPR to LDAP layer know about the new socket and
* our own socket-specific data.
*/
}
#ifdef _SOLARIS_SDK
/*
* Set hostname which will be retrieved (depending on ssl strength) when
* using client or server auth.
*/
#endif /* _SOLARIS_SDK */
/*
* Install certificate hook function.
*/
(void *)sseip);
}
return( intfd ); /* success */
#ifdef _SOLARIS_SDK
#endif /* _SOLARIS_SDK */
}
}
}
return( -1 );
}
static int
struct lextiof_socket_private **socketargp )
{
sessionarg, socketargp, 0 ));
}
static int
struct lextiof_socket_private **socketargp )
{
}
static void
{
}
}
/*
* Install I/O routines from libsec and NSPR into libldap to allow libldap
* to do SSL.
*
* We rely on libprldap to provide most of the functions, and then we override
* a few of them to support SSL.
*/
int
{
#ifndef LDAP_SSLIO_HOOKS
return( -1 );
#else
struct ldap_x_ext_io_fns iofns;
/*
* This is done within ldap_init() and
* ldap_init() is called from ldapssl_init()
*/
#ifndef _SOLARIS_SDK
if ( prldap_install_routines(
ld,
1 /* shared -- we have to assume it is */ )
!= LDAP_SUCCESS ) {
return( -1 );
}
#endif /*_SOLARIS_SDK*/
/*
* Allocate our own session information.
*/
sizeof( LDAPSSLSessionInfo )))) {
return( -1 );
}
/*
* Initialize session info.
* XXX: it would be nice to be able to set these on a per-session basis:
* lssei_using_pcks_fns
* lssei_certdbh
*/
#ifdef _SOLARIS_SDK
/*
* This is part of a hack to allow the ssl portion of the
* library to call the ldap library gethostbyaddr resolver.
*/
#endif /* _SOLARIS_SDK */
/*
* override a few functions, saving a pointer to the standard function
* in each case so we can call it from our SSL savvy functions.
*/
return( -1 );
}
/* override socket, connect, and ioctl */
return( -1 );
}
/*
* Store session info. for later retrieval.
*/
return( -1 );
}
return( 0 );
#endif
}
/*
* Set the SSL strength for an existing SSL-enabled LDAP session handle.
*
* See the description of ldapssl_serverauth_init() above for valid
* sslstrength values. If ld is NULL, the default for new LDAP session
* handles is set.
*
* Returns 0 if all goes well and -1 if an error occurs.
*/
int
{
if ( sslstrength != LDAPSSL_AUTH_WEAK &&
sslstrength != LDAPSSL_AUTH_CERT &&
sslstrength != LDAPSSL_AUTH_CNCHECK ) {
rc = -1;
} else {
} else { /* set session-specific strength */
{
} else {
rc = -1;
}
}
}
return( rc );
}
int
char *keypasswd, char *certnickname )
{
#ifndef LDAP_SSLIO_HOOKS
return( -1 );
#else
struct ldap_x_ext_io_fns iofns;
/*
* Check parameters
*/
return( -1 );
}
/*
* Update session info. data structure.
*/
return( -1 );
}
return( -1 );
}
return( -1 );
}
return( -1 );
}
/*
* replace standard SSL CONNECT function with client auth aware one
*/
!= 0 ) {
return( -1 );
}
/* standard SSL setup has not done */
return( -1 );
}
!= 0 ) {
return( -1 );
}
return( 0 );
#endif
}
static void
{
}
}
}
}
static void
{
}
}
/* this function provides cert authentication. This is called during
* the SSL_Handshake process. Once the cert has been retrieved from
* the server, the it is checked, using VerifyCertNow(), then
* the cn is checked against the host name, set with SSL_SetURL()
*/
static int
{
char *hostname = (char *)0;
if (!sessionarg || !socket)
return rv;
return SECSuccess;
}
if ( isServer ) {
} else {
}
return rv;
{
/* cert is OK. This is the client side of an SSL connection.
* Now check the name field in the cert against the desired hostname.
* NB: This is our only defense against Man-In-The-Middle (MITM)
* attacks!
*/
} else {
rv = SECFailure;
}
if (hostname)
if (rv != SECSuccess)
}
return((int)rv);
}
/*
* called during SSL client auth. when server wants our cert and key.
* return 0 if we succeeded and set *pRetCert and *pRetKey, -1 otherwise.
* if -1 is returned SSL will proceed without sending a cert.
*/
static int
{
return( -1 ); /* client auth. not enabled */
}
}
static int
char **errmsgp )
{
== NULL ) {
}
return( -1 );
}
{
}
}
return( -1 );
}
return( 0 );
}
/*
* This function returns the password to NSS.
* This function is enable through PK11_SetPasswordFunc
* only if pkcs functions are not being used.
*/
static char *
{
if ( retry)
return (NULL);
return( NULL );
}
return( ssip->lssei_keypasswd );
}
/*
*
* 1) check expiration
* 2) check that public key in cert matches private key
*/
static int
{
int rv;
if ( rv != 0 ) {
}
return( -1 );
}
}
}
return( 0 );
}
#if 0 /* NOT_NEEDED_IN_LIBLDAP */
/* there are patches and kludges. this is both. force some linkers to
* link this stuff in
*/
int stubs_o_stuff( void )
{
const char *name ="t";
PR_ImplodeTime( &exploded );
PR_Cleanup();
return 0;
}
#endif /* NOT_NEEDED_IN_LIBLDAP */
/*
* Import the file descriptor corresponding to the socket of an already
* open LDAP connection into SSL, and update the socket and session
* information accordingly.
*/
{
/*
* Retrieve session info. so we can store a pointer to our session info.
* in our socket info. later.
*/
return( -1 );
}
/*
* Retrieve socket info. so we have the PRFileDesc.
*/
return( -1 );
}
/*
* Allocate a structure to hold our socket-specific data.
*/
}
/*
* Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
*/
}
PR_FALSE ) != SECSuccess )) {
}
/*
* Let the standard NSPR to LDAP layer know about the new socket and
* our own socket-specific data.
*/
}
/*
* Install certificate hook function.
*/
(void *)CERT_GetDefaultCertDB()) != 0 ) {
}
!= 0 ) {
}
return 0;
/*
* "Unimport" the socket from SSL, i.e. get rid of the upper layer of
* the file descriptor stack, which represents SSL.
*/
}
}
return( -1 );
}
/*
* Reset an LDAP session from SSL to a non-secure status.
* Basically, this function undoes the work done by ldapssl_install_routines.
*/
{
int rc = 0;
/*
* Retrieve session info.
*/
return( -1 );
}
/*
* Reset the standard extended io functions.
*/
< 0) {
rc = -1;
goto free_session_info;
}
/* reset socket, connect, and ioctl */
< 0) {
rc = -1;
goto free_session_info;
}
rc = -1;
}
} /* if ( sseip && *sseip ) */
return (-1);
}
return rc;
}
#ifdef _SOLARIS_SDK
static void
{
p->name = NSS_DBNAM_IPNODES;
p->flags |= NSS_USE_DEFAULT_CONFIG;
}
static void
{
p->name = NSS_DBNAM_HOSTS;
p->flags |= NSS_USE_DEFAULT_CONFIG;
}
static struct hostent *
int *h_errnop)
{
int (*str2ent)();
void (*nss_initf)();
} else {
return NULL;
}
}
/*
* ns_gethostbyaddr is used to be a substitute gethostbyaddr for
* libldap when ssl will need to determine the fully qualified
* host name from an address when it is unsafe to use the normal
* nameservice functions.
*
* Note that the ldap name service resolver calls this with the address as
* a character string - which we must convert into address form.
*/
/*ARGSUSED*/
static LDAPHostEnt *
void *extradata)
{
int h_errno;
struct in_addr a;
return (NULL);
h_e = _switch_gethostbyaddr_r((char *)&a,
}
}
}
} else {
}
return (ldap_hent);
}
/*
* ldapssl_install_gethostbyaddr attempts to prevent recursion in
* gethostbyaddr calls when an ip address is given to ssl. This ip address
* must be resolved to a host name.
*
* For example, libsldap cannot use LDAP to resolve this address to a
* name because of recursion. The caller is instructing libldap to skip
* the specified name service when resolving addresses for the specified
* ldap connection.
*
* Currently only ldap and dns name services always return fully qualified
* names. The other name services (files and nis) will returned fully
* qualified names if the host names are stored as fully qualified names
* in these name services.
*
* Note:
*
* Since host_service applies to all connections, calling
* ldapssl_install_gethostbyaddr with different name services to
* skip will lead to unpredictable results.
*
* Returns:
* 0 if success
* -1 if failure
*/
int
{
char *tmp;
const char *name;
int len;
/*
* db_root_hosts.lock mutex is used to ensure that the name list
* is not in use by the name service switch while we are updating
* the host_service
*/
return (0);
}
/* check for ldap and count other backends */
continue;
}
else {
} else {
}
}
return (-1);
}
}
if (!got_skip) {
/*
* Since skip name service not used for hosts, we do not need
* to install our private address resolution function
*/
return (0);
}
if (host_service != NULL)
return (-1);
return (-1);
return (0);
}
#endif /* _SOLARIS_SDK */
#endif /* NET_SSL */