#if defined(NET_SSL)
#if defined( _WINDOWS )
#include <windows.h>
#include "proto-ntutil.h"
#endif
#include <nspr.h>
#include <plstr.h>
#include <synch.h>
#include <cert.h>
#include <key.h>
#include <ssl.h>
#include <sslproto.h>
#include <ldap.h>
#include <ldappr.h>
#include <solaris-int.h>
#include <nss.h>
#ifdef OSF1V4D
#ifndef __STDC__
# define __STDC__
#endif
#endif
#ifndef FILE_PATHSEP
#define FILE_PATHSEP '/'
#endif
#define START_TLS_OID "1.3.6.1.4.1.1466.20037"
static PRStatus local_SSLPLCY_Install(void);
static int inited = 0;
#ifdef _SOLARIS_SDK
mutex_t inited_mutex = DEFAULTMUTEX;
#else
static mutex_t inited_mutex = DEFAULTMUTEX;
#endif
#if 0
static char tokDes[34] = "Internal (Software) Database ";
static char ptokDes[34] = "Internal (Software) Token ";
#endif
static int
splitpath(char *string, char *dir, char *prefix, char *key) {
char *k;
char *s;
char *d = string;
char *l;
int len = 0;
if (string == NULL)
return (-1);
len = PL_strlen(string);
l = string + len - 1;
while (l != string && *l != '/' && *l != '\\')
l--;
if ((k = PL_strstr(l, ".db")) != NULL) {
while (k != l && *k != 'c' && *k != 'k')
k--;
if (k != d && k > d)
s = k - 1;
while (s != d && *s != '/' && *s != '\\')
s--;
if (s + 1 == k) {
prefix = '\0';
PL_strcpy(key, k);
*k = '\0';
PL_strcpy(dir, d);
} else {
PL_strcpy(key, k);
*k = '\0';
PL_strcpy(prefix, ++s);
*s = '\0';
PL_strcpy(dir, d);
}
} else {
return (-1);
}
return (0);
}
static PRStatus local_SSLPLCY_Install(void)
{
return NSS_SetDomesticPolicy() ? PR_FAILURE : PR_SUCCESS;
}
static void
ldapssl_basic_init( void )
{
#ifndef _SOLARIS_SDK
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
#endif
PR_SetConcurrency( 4 );
}
static void *
ldapssl_malloc( size_t size )
{
void *p;
p = malloc( size );
return p;
}
static void *
ldapssl_calloc( int nelem, size_t elsize )
{
void *p;
p = calloc( nelem, elsize );
return p;
}
static char *
ldapssl_strdup( const char *s )
{
char *scopy;
if ( NULL == s ) {
scopy = NULL;
} else {
scopy = strdup( s );
}
return scopy;
}
static void
ldapssl_free( void **pp )
{
if ( NULL != pp && NULL != *pp ) {
free( (void *)*pp );
*pp = NULL;
}
}
#ifdef _SOLARIS_SDK
static int
update_nss_strict_fork_env(char **enval)
{
char *temps = getenv("NSS_STRICT_NOFORK");
if (temps == NULL) {
*enval = NULL;
} else if (strncmp(temps, "DISABLED", 9) == 0) {
*enval = NULL;
return (1);
} else {
if ((*enval = ldapssl_strdup(temps)) == NULL)
return (-1);
}
return (setenv("NSS_STRICT_NOFORK", "DISABLED", 1));
}
static int
reset_nss_strict_fork_env(char *enval)
{
if (enval != NULL) {
return (setenv("NSS_STRICT_NOFORK", enval, 1));
} else {
return (unsetenv("NSS_STRICT_NOFORK"));
}
}
#endif
static char *
buildDBName(const char *basename, const char *dbname)
{
char *result;
PRUint32 len, pathlen, addslash;
if (basename)
{
if (( len = PL_strlen( basename )) > 3
&& PL_strcasecmp( ".db", basename + len - 3 ) == 0 ) {
return (ldapssl_strdup(basename));
}
pathlen = len;
len = pathlen + PL_strlen(dbname) + 1;
addslash = ( pathlen > 0 &&
(( *(basename + pathlen - 1) != FILE_PATHSEP ) ||
( *(basename + pathlen - 1) != '\\' )));
if ( addslash ) {
++len;
}
if (( result = ldapssl_malloc( len )) != NULL ) {
PL_strcpy( result, basename );
if ( addslash ) {
*(result+pathlen) = FILE_PATHSEP;
++pathlen;
}
PL_strcpy(result+pathlen, dbname);
}
}
return result;
}
char *
GetCertDBName(void *alias, int dbVersion)
{
char *source;
char dbname[128];
source = (char *)alias;
if (!source)
{
source = "";
}
sprintf(dbname, "cert%d.db",dbVersion);
return(buildDBName(source, dbname));
}
static char *
GetDBName(const char *dbname, const char *path)
{
char *result;
PRUint32 len, pathlen;
int addslash;
if ( dbname == NULL ) {
dbname = "";
}
if ((path == NULL) || (*path == 0)) {
result = ldapssl_strdup(dbname);
} else {
pathlen = PL_strlen(path);
len = pathlen + PL_strlen(dbname) + 1;
addslash = ( path[pathlen - 1] != '/' );
if ( addslash ) {
++len;
}
if (( result = ldapssl_malloc( len )) != NULL ) {
PL_strcpy( result, path );
if ( addslash ) {
*(result+pathlen) = '/';
++pathlen;
}
PL_strcpy(result+pathlen, dbname);
}
}
return result;
}
int
LDAP_CALL
ldapssl_clientauth_init( const char *certdbpath, void *certdbhandle,
const int needkeydb, const char *keydbpath, void *keydbhandle )
{
int rc;
#ifdef _SOLARIS_SDK
char *enval;
int rcenv = 0;
#endif
mutex_lock(&inited_mutex);
if ( inited ) {
mutex_unlock(&inited_mutex);
return( 0 );
}
ldapssl_basic_init();
#ifdef _SOLARIS_SDK
if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
mutex_unlock(&inited_mutex);
return (-1);
}
#endif
rc = NSS_Init(certdbpath);
#ifdef _SOLARIS_SDK
if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
ldapssl_free(&enval);
mutex_unlock(&inited_mutex);
return (-1);
}
ldapssl_free(&enval);
#endif
if (rc != 0) {
if ((rc = PR_GetError()) >= 0)
rc = -1;
mutex_unlock(&inited_mutex);
return (rc);
}
if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
|| SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
if (( rc = PR_GetError()) >= 0 ) {
rc = -1;
}
mutex_unlock(&inited_mutex);
return( rc );
}
if (local_SSLPLCY_Install() == PR_FAILURE) {
mutex_unlock(&inited_mutex);
return( -1 );
}
inited = 1;
mutex_unlock(&inited_mutex);
return( 0 );
}
int
LDAP_CALL
ldapssl_advclientauth_init(
const char *certdbpath, void *certdbhandle,
const int needkeydb, const char *keydbpath, void *keydbhandle,
const int needsecmoddb, const char *secmoddbpath,
const int sslstrength )
{
int rc;
#ifdef _SOLARIS_SDK
char *enval;
int rcenv = 0;
#endif
mutex_lock(&inited_mutex);
if ( inited ) {
mutex_unlock(&inited_mutex);
return( 0 );
}
ldapssl_basic_init();
#ifdef _SOLARIS_SDK
if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
mutex_unlock(&inited_mutex);
return (-1);
}
#endif
rc = NSS_Init(certdbpath);
#ifdef _SOLARIS_SDK
if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
ldapssl_free(&enval);
mutex_unlock(&inited_mutex);
return (-1);
}
ldapssl_free(&enval);
#endif
if (rc != 0) {
if ((rc = PR_GetError()) >= 0)
rc = -1;
mutex_unlock(&inited_mutex);
return (rc);
}
if (local_SSLPLCY_Install() == PR_FAILURE) {
mutex_unlock(&inited_mutex);
return( -1 );
}
inited = 1;
mutex_unlock(&inited_mutex);
return( ldapssl_set_strength( NULL, sslstrength));
}
void set_using_pkcs_functions( int val );
int
LDAP_CALL
ldapssl_pkcs_init( const struct ldapssl_pkcs_fns *pfns )
{
char *certdbName, *s, *keydbpath;
char *certdbPrefix, *keydbPrefix;
char *confDir, *keydbName;
static char *secmodname = "secmod.db";
int rc;
#ifdef _SOLARIS_SDK
char *enval;
int rcenv = 0;
#endif
mutex_lock(&inited_mutex);
if ( inited ) {
mutex_unlock(&inited_mutex);
return( 0 );
}
set_using_pkcs_functions( 1 );
ldapssl_basic_init();
pfns->pkcs_getcertpath( NULL, &s);
confDir = ldapssl_strdup( s );
certdbPrefix = ldapssl_strdup( s );
certdbName = ldapssl_strdup( s );
*certdbPrefix = 0;
splitpath(s, confDir, certdbPrefix, certdbName);
pfns->pkcs_getkeypath( NULL, &s);
keydbpath = ldapssl_strdup( s );
keydbPrefix = ldapssl_strdup( s );
keydbName = ldapssl_strdup( s );
*keydbPrefix = 0;
splitpath(s, keydbpath, keydbPrefix, keydbName);
ldapssl_free((void **)&certdbName);
ldapssl_free((void **)&keydbName);
ldapssl_free((void **)&keydbpath);
#ifdef _SOLARIS_SDK
if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
mutex_unlock(&inited_mutex);
return (-1);
}
#endif
rc = NSS_Initialize(confDir,certdbPrefix,keydbPrefix,secmodname,
NSS_INIT_READONLY);
ldapssl_free((void **)&certdbPrefix);
ldapssl_free((void **)&keydbPrefix);
ldapssl_free((void **)&confDir);
#ifdef _SOLARIS_SDK
if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
ldapssl_free(&enval);
mutex_unlock(&inited_mutex);
return (-1);
}
ldapssl_free(&enval);
#endif
if (rc != 0) {
if ((rc = PR_GetError()) >= 0)
rc = -1;
mutex_unlock(&inited_mutex);
return (rc);
}
#if 0
PK11_ConfigurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 );
#endif
if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
|| SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
if (( rc = PR_GetError()) >= 0 ) {
rc = -1;
}
mutex_unlock(&inited_mutex);
return( rc );
}
if (local_SSLPLCY_Install() == PR_FAILURE) {
mutex_unlock(&inited_mutex);
return( -1 );
}
inited = 1;
if ( certdbName != NULL ) {
ldapssl_free((void **) &certdbName );
}
return( ldapssl_set_strength( NULL, LDAPSSL_AUTH_CNCHECK));
}
int
LDAP_CALL
ldapssl_client_init(const char* certdbpath, void *certdbhandle )
{
return( ldapssl_clientauth_init( certdbpath, certdbhandle,
0, NULL, NULL ));
}
int
LDAP_CALL
ldapssl_serverauth_init(const char* certdbpath,
void *certdbhandle,
const int sslstrength )
{
if ( ldapssl_set_strength( NULL, sslstrength ) != 0) {
return ( -1 );
}
return( ldapssl_clientauth_init( certdbpath, certdbhandle,
0, NULL, NULL ));
}
static int ldapssl_tls_start(LDAP *ld, int *msgidp)
{
int version, rc;
BerValue extreq_data;
extreq_data.bv_val = NULL;
extreq_data.bv_len = 0;
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
rc = ldap_extended_operation( ld, START_TLS_OID, &extreq_data,
NULL, NULL, msgidp );
return rc;
}
static int ldapssl_enableSSL_on_open_connection(LDAP *ld, int defsecure,
char *certdbpath, char *keydbpath)
{
PRLDAPSocketInfo soi;
if ( ldapssl_clientauth_init( certdbpath, NULL, 1, keydbpath, NULL ) < 0 ) {
goto ssl_setup_failure;
}
memset( &soi, 0, sizeof(soi));
soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
if ( prldap_get_default_socket_info( ld, &soi ) < 0 ) {
goto ssl_setup_failure;
}
if ( ldapssl_install_routines( ld ) < 0 ) {
goto ssl_setup_failure;
}
if (soi.soinfo_prfd == NULL) {
int sd;
ldap_get_option( ld, LDAP_OPT_DESC, &sd );
soi.soinfo_prfd = (PRFileDesc *) PR_ImportTCPSocket( sd );
}
if ( prldap_set_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) {
goto ssl_setup_failure;
}
if ( ldap_set_option( ld, LDAP_OPT_SSL,
defsecure ? LDAP_OPT_ON : LDAP_OPT_OFF ) < 0 ) {
goto ssl_setup_failure;
}
if ( ldapssl_import_fd( ld, defsecure ) < 0 ) {
goto ssl_setup_failure;
}
return 0;
ssl_setup_failure:
ldapssl_reset_to_nonsecure( ld );
return( -1 );
}
int
LDAP_CALL
ldapssl_tls_start_s(LDAP *ld,int defsecure, char *certdbpath, char *keydbpath,
char ***referralsp)
{
int rc, resultCode, msgid;
char *extresp_oid;
BerValue *extresp_data;
LDAPMessage *res;
rc = ldapssl_tls_start( ld, &msgid );
if ( rc != LDAP_SUCCESS ) {
return rc;
}
rc = ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res );
if ( rc != LDAP_RES_EXTENDED ) {
ldap_msgfree( res );
return( -1 );
}
rc = ldap_parse_extended_result( ld, res, &extresp_oid, &extresp_data, 0 );
if ( rc != LDAP_SUCCESS ) {
ldap_msgfree( res );
return rc;
}
if ( strcasecmp( extresp_oid, START_TLS_OID ) != 0 ) {
ldap_msgfree( res );
return -1;
}
resultCode = ldap_get_lderrno( ld, NULL, NULL );
switch (resultCode) {
case LDAP_REFERRAL:
{
rc = ldap_parse_result( ld, res, NULL, NULL, NULL, referralsp, NULL, 0 );
if ( rc != LDAP_SUCCESS ) {
ldap_msgfree( res );
return rc;
}
}
case LDAP_OPERATIONS_ERROR:
case LDAP_PROTOCOL_ERROR:
case LDAP_UNAVAILABLE:
goto free_msg_and_return;
case LDAP_SUCCESS:
{
if ( ldapssl_enableSSL_on_open_connection( ld, defsecure,
certdbpath, keydbpath ) < 0 ) {
resultCode = -1;
}
}
default:
goto free_msg_and_return;
}
free_msg_and_return:
ldap_msgfree( res );
return resultCode;
}
#endif