1N/A/*
1N/A * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
1N/A */
1N/A
1N/A/*
1N/A * The contents of this file are subject to the Netscape Public
1N/A * License Version 1.1 (the "License"); you may not use this file
1N/A * except in compliance with the License. You may obtain a copy of
1N/A * the License at http://www.mozilla.org/NPL/
1N/A *
1N/A * Software distributed under the License is distributed on an "AS
1N/A * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
1N/A * implied. See the License for the specific language governing
1N/A * rights and limitations under the License.
1N/A *
1N/A * The Original Code is Mozilla Communicator client code, released
1N/A * March 31, 1998.
1N/A *
1N/A * The Initial Developer of the Original Code is Netscape
1N/A * Communications Corporation. Portions created by Netscape are
1N/A * Copyright (C) 1998-1999 Netscape Communications Corporation. All
1N/A * Rights Reserved.
1N/A *
1N/A * Contributor(s):
1N/A */
1N/A
1N/A/*
1N/A * clientinit.c
1N/A */
1N/A
1N/A#if defined(NET_SSL)
1N/A
1N/A
1N/A#if defined( _WINDOWS )
1N/A#include <windows.h>
1N/A#include "proto-ntutil.h"
1N/A#endif
1N/A
1N/A#include <nspr.h>
1N/A#include <plstr.h>
1N/A#include <synch.h>
1N/A#include <cert.h>
1N/A#include <key.h>
1N/A#include <ssl.h>
1N/A#include <sslproto.h>
1N/A#include <ldap.h>
1N/A#include <ldappr.h>
1N/A#include <solaris-int.h>
1N/A
1N/A
1N/A#include <nss.h>
1N/A
1N/A/* XXX:mhein The following is a workaround for the redefinition of */
1N/A/* const problem on OSF. Fix to be provided by NSS */
1N/A/* This is a pretty benign workaround for us which */
1N/A/* should not cause problems in the future even if */
1N/A/* we forget to take it out :-) */
1N/A
1N/A#ifdef OSF1V4D
1N/A#ifndef __STDC__
1N/A# define __STDC__
1N/A#endif /* __STDC__ */
1N/A#endif /* OSF1V4D */
1N/A
1N/A#ifndef FILE_PATHSEP
1N/A#define FILE_PATHSEP '/'
1N/A#endif
1N/A
1N/A/*
1N/A * StartTls()
1N/A */
1N/A
1N/A#define START_TLS_OID "1.3.6.1.4.1.1466.20037"
1N/A
1N/Astatic PRStatus local_SSLPLCY_Install(void);
1N/A
1N/A/*
1N/A * This little tricky guy keeps us from initializing twice
1N/A */
1N/Astatic int inited = 0;
1N/A#ifdef _SOLARIS_SDK
1N/Amutex_t inited_mutex = DEFAULTMUTEX;
1N/A#else
1N/Astatic mutex_t inited_mutex = DEFAULTMUTEX;
1N/A#endif /* _SOLARIS_SDK */
1N/A#if 0 /* UNNEEDED BY LIBLDAP */
1N/Astatic char tokDes[34] = "Internal (Software) Database ";
1N/Astatic char ptokDes[34] = "Internal (Software) Token ";
1N/A#endif /* UNNEEDED BY LIBLDAP */
1N/A
1N/A
1N/A/* IN: */
1N/A/* string: /u/mhein/.netscape/mykey3.db */
1N/A/* OUT: */
1N/A/* dir: /u/mhein/.netscape/ */
1N/A/* prefix: my */
1N/A/* key: key3.db */
1N/A
1N/Astatic int
1N/Asplitpath(char *string, char *dir, char *prefix, char *key) {
1N/A char *k;
1N/A char *s;
1N/A char *d = string;
1N/A char *l;
1N/A int len = 0;
1N/A
1N/A
1N/A if (string == NULL)
1N/A return (-1);
1N/A
1N/A /* goto the end of the string, and walk backwards until */
1N/A /* you get to the first pathseparator */
1N/A len = PL_strlen(string);
1N/A l = string + len - 1;
1N/A while (l != string && *l != '/' && *l != '\\')
1N/A l--;
1N/A /* search for the .db */
1N/A if ((k = PL_strstr(l, ".db")) != NULL) {
1N/A /* now we are sitting on . of .db */
1N/A
1N/A /* move backward to the first 'c' or 'k' */
1N/A /* indicating cert or key */
1N/A while (k != l && *k != 'c' && *k != 'k')
1N/A k--;
1N/A
1N/A /* move backwards to the first path separator */
1N/A if (k != d && k > d)
1N/A s = k - 1;
1N/A while (s != d && *s != '/' && *s != '\\')
1N/A s--;
1N/A
1N/A /* if we are sitting on top of a path */
1N/A /* separator there is no prefix */
1N/A if (s + 1 == k) {
1N/A /* we know there is no prefix */
1N/A prefix = '\0';
1N/A PL_strcpy(key, k);
1N/A *k = '\0';
1N/A PL_strcpy(dir, d);
1N/A } else {
1N/A /* grab the prefix */
1N/A PL_strcpy(key, k);
1N/A *k = '\0';
1N/A PL_strcpy(prefix, ++s);
1N/A *s = '\0';
1N/A PL_strcpy(dir, d);
1N/A }
1N/A } else {
1N/A /* neither *key[0-9].db nor *cert[0=9].db found */
1N/A return (-1);
1N/A }
1N/A
1N/A return (0);
1N/A}
1N/A
1N/A
1N/Astatic PRStatus local_SSLPLCY_Install(void)
1N/A{
1N/A SECStatus s;
1N/A
1N/A#ifdef NS_DOMESTIC
1N/A s = NSS_SetDomesticPolicy();
1N/A#elif NS_EXPORT
1N/A s = NSS_SetExportPolicy();
1N/A#else
1N/A s = PR_FAILURE;
1N/A#endif
1N/A return s?PR_FAILURE:PR_SUCCESS;
1N/A}
1N/A
1N/A
1N/A
1N/Astatic void
1N/Aldapssl_basic_init( void )
1N/A{
1N/A#ifndef _SOLARIS_SDK
1N/A /*
1N/A * NSPR is initialized in .init on SOLARIS
1N/A */
1N/A /* PR_Init() must to be called before everything else... */
1N/A PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
1N/A#endif
1N/A
1N/A PR_SetConcurrency( 4 ); /* work around for NSPR 3.x I/O hangs */
1N/A}
1N/A
1N/A
1N/A
1N/A/*
1N/A * Cover functions for malloc(), calloc(), strdup() and free() that are
1N/A * compatible with the NSS libraries (they seem to use the C runtime
1N/A * library malloc/free so these functions are quite simple right now).
1N/A */
1N/Astatic void *
1N/Aldapssl_malloc( size_t size )
1N/A{
1N/A void *p;
1N/A
1N/A p = malloc( size );
1N/A return p;
1N/A}
1N/A
1N/A
1N/Astatic void *
1N/Aldapssl_calloc( int nelem, size_t elsize )
1N/A{
1N/A void *p;
1N/A
1N/A p = calloc( nelem, elsize );
1N/A return p;
1N/A}
1N/A
1N/A
1N/Astatic char *
1N/Aldapssl_strdup( const char *s )
1N/A{
1N/A char *scopy;
1N/A
1N/A if ( NULL == s ) {
1N/A scopy = NULL;
1N/A } else {
1N/A scopy = strdup( s );
1N/A }
1N/A return scopy;
1N/A}
1N/A
1N/A
1N/Astatic void
1N/Aldapssl_free( void **pp )
1N/A{
1N/A if ( NULL != pp && NULL != *pp ) {
1N/A free( (void *)*pp );
1N/A *pp = NULL;
1N/A }
1N/A}
1N/A
1N/A
1N/A#ifdef _SOLARIS_SDK
1N/A/*
1N/A * Disable strict fork detection of NSS library to allow safe fork of
1N/A * consumers. Otherwise NSS will not work after fork because it was not
1N/A * deinitialized before fork and there is no safe way how to do it after fork.
1N/A *
1N/A * Return values:
1N/A * 1 - DISABLED was already set, no modification to environment
1N/A * 0 - successfully modified environment, old value saved to enval if there
1N/A * was some
1N/A * -1 - setenv or strdup failed, the environment was left unchanged
1N/A *
1N/A */
1N/Astatic int
1N/Aupdate_nss_strict_fork_env(char **enval)
1N/A{
1N/A char *temps = getenv("NSS_STRICT_NOFORK");
1N/A if (temps == NULL) {
1N/A *enval = NULL;
1N/A } else if (strncmp(temps, "DISABLED", 9) == 0) {
1N/A /* Do not need to set as DISABLED, it is already set. */
1N/A *enval = NULL;
1N/A return (1);
1N/A } else {
1N/A if ((*enval = ldapssl_strdup(temps)) == NULL)
1N/A return (-1);
1N/A }
1N/A return (setenv("NSS_STRICT_NOFORK", "DISABLED", 1));
1N/A}
1N/A
1N/A/*
1N/A * Reset environment variable NSS_STRICT_NOFORK to value before
1N/A * update_nss_strict_fork_env() call or remove it from environment if it did
1N/A * not exist.
1N/A * NSS_STRICT_NOFORK=DISABLED is needed only during NSS initialization to
1N/A * disable activation of atfork handler in NSS which is invalidating
1N/A * initialization in child process after fork.
1N/A */
1N/Astatic int
1N/Areset_nss_strict_fork_env(char *enval)
1N/A{
1N/A if (enval != NULL) {
1N/A return (setenv("NSS_STRICT_NOFORK", enval, 1));
1N/A } else {
1N/A return (unsetenv("NSS_STRICT_NOFORK"));
1N/A }
1N/A}
1N/A#endif
1N/A
1N/A
1N/Astatic char *
1N/AbuildDBName(const char *basename, const char *dbname)
1N/A{
1N/A char *result;
1N/A PRUint32 len, pathlen, addslash;
1N/A
1N/A if (basename)
1N/A {
1N/A if (( len = PL_strlen( basename )) > 3
1N/A && PL_strcasecmp( ".db", basename + len - 3 ) == 0 ) {
1N/A return (ldapssl_strdup(basename));
1N/A }
1N/A
1N/A pathlen = len;
1N/A len = pathlen + PL_strlen(dbname) + 1;
1N/A addslash = ( pathlen > 0 &&
1N/A (( *(basename + pathlen - 1) != FILE_PATHSEP ) ||
1N/A ( *(basename + pathlen - 1) != '\\' )));
1N/A
1N/A if ( addslash ) {
1N/A ++len;
1N/A }
1N/A if (( result = ldapssl_malloc( len )) != NULL ) {
1N/A PL_strcpy( result, basename );
1N/A if ( addslash ) {
1N/A *(result+pathlen) = FILE_PATHSEP; /* replaces '\0' */
1N/A ++pathlen;
1N/A }
1N/A PL_strcpy(result+pathlen, dbname);
1N/A }
1N/A
1N/A }
1N/A
1N/A
1N/A return result;
1N/A}
1N/A
1N/Achar *
1N/AGetCertDBName(void *alias, int dbVersion)
1N/A{
1N/A char *source;
1N/A char dbname[128];
1N/A
1N/A source = (char *)alias;
1N/A
1N/A if (!source)
1N/A {
1N/A source = "";
1N/A }
1N/A
1N/A sprintf(dbname, "cert%d.db",dbVersion);
1N/A return(buildDBName(source, dbname));
1N/A
1N/A
1N/A}
1N/A
1N/A/*
1N/A * return database name by appending "dbname" to "path".
1N/A * this code doesn't need to be terribly efficient (not called often).
1N/A */
1N/A/* XXXceb this is the old function. To be removed eventually */
1N/Astatic char *
1N/AGetDBName(const char *dbname, const char *path)
1N/A{
1N/A char *result;
1N/A PRUint32 len, pathlen;
1N/A int addslash;
1N/A
1N/A if ( dbname == NULL ) {
1N/A dbname = "";
1N/A }
1N/A
1N/A if ((path == NULL) || (*path == 0)) {
1N/A result = ldapssl_strdup(dbname);
1N/A } else {
1N/A pathlen = PL_strlen(path);
1N/A len = pathlen + PL_strlen(dbname) + 1;
1N/A addslash = ( path[pathlen - 1] != '/' );
1N/A if ( addslash ) {
1N/A ++len;
1N/A }
1N/A if (( result = ldapssl_malloc( len )) != NULL ) {
1N/A PL_strcpy( result, path );
1N/A if ( addslash ) {
1N/A *(result+pathlen) = '/'; /* replaces '\0' */
1N/A ++pathlen;
1N/A }
1N/A PL_strcpy(result+pathlen, dbname);
1N/A }
1N/A }
1N/A
1N/A return result;
1N/A}
1N/A
1N/A/*
1N/A * Initialize ns/security so it can be used for SSL client authentication.
1N/A * It is safe to call this more than once.
1N/A *
1N/A * If needkeydb == 0, no key database is opened and SSL server authentication
1N/A * is supported but not client authentication.
1N/A *
1N/A * If "certdbpath" is NULL or "", the default cert. db is used (typically
1N/A * ~/.netscape/cert7.db).
1N/A *
1N/A * If "certdbpath" ends with ".db" (case-insensitive compare), then
1N/A * it is assumed to be a full path to the cert. db file; otherwise,
1N/A * it is assumed to be a directory that contains a file called
1N/A * "cert7.db" or "cert.db".
1N/A *
1N/A * If certdbhandle is non-NULL, it is assumed to be a pointer to a
1N/A * SECCertDBHandle structure. It is fine to pass NULL since this
1N/A * routine will allocate one for you (CERT_GetDefaultDB() can be
1N/A * used to retrieve the cert db handle).
1N/A *
1N/A * If "keydbpath" is NULL or "", the default key db is used (typically
1N/A * ~/.netscape/key3.db).
1N/A *
1N/A * If "keydbpath" ends with ".db" (case-insensitive compare), then
1N/A * it is assumed to be a full path to the key db file; otherwise,
1N/A * it is assumed to be a directory that contains a file called
1N/A * "key3.db"
1N/A *
1N/A * If certdbhandle is non-NULL< it is assumed to be a pointed to a
1N/A * SECKEYKeyDBHandle structure. It is fine to pass NULL since this
1N/A * routine will allocate one for you (SECKEY_GetDefaultDB() can be
1N/A * used to retrieve the cert db handle).
1N/A */
1N/Aint
1N/ALDAP_CALL
1N/Aldapssl_clientauth_init( const char *certdbpath, void *certdbhandle,
1N/A const int needkeydb, const char *keydbpath, void *keydbhandle )
1N/A
1N/A{
1N/A int rc;
1N/A#ifdef _SOLARIS_SDK
1N/A char *enval;
1N/A int rcenv = 0;
1N/A#endif
1N/A
1N/A /*
1N/A * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_clientauth_init\n",0 ,0 ,0);
1N/A */
1N/A
1N/A mutex_lock(&inited_mutex);
1N/A if ( inited ) {
1N/A mutex_unlock(&inited_mutex);
1N/A return( 0 );
1N/A }
1N/A
1N/A ldapssl_basic_init();
1N/A
1N/A#ifdef _SOLARIS_SDK
1N/A if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
1N/A mutex_unlock(&inited_mutex);
1N/A return (-1);
1N/A }
1N/A#endif
1N/A
1N/A /* Open the certificate database */
1N/A rc = NSS_Init(certdbpath);
1N/A#ifdef _SOLARIS_SDK
1N/A /* Error from NSS_Init() more important! */
1N/A if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
1N/A ldapssl_free(&enval);
1N/A mutex_unlock(&inited_mutex);
1N/A return (-1);
1N/A }
1N/A ldapssl_free(&enval);
1N/A#endif
1N/A if (rc != 0) {
1N/A if ((rc = PR_GetError()) >= 0)
1N/A rc = -1;
1N/A mutex_unlock(&inited_mutex);
1N/A return (rc);
1N/A }
1N/A
1N/A if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
1N/A || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
1N/A if (( rc = PR_GetError()) >= 0 ) {
1N/A rc = -1;
1N/A }
1N/A mutex_unlock(&inited_mutex);
1N/A return( rc );
1N/A }
1N/A
1N/A
1N/A
1N/A#if defined(NS_DOMESTIC)
1N/A if (local_SSLPLCY_Install() == PR_FAILURE) {
1N/A mutex_unlock(&inited_mutex);
1N/A return( -1 );
1N/A }
1N/A#elif(NS_EXPORT)
1N/A if (local_SSLPLCY_Install() == PR_FAILURE) {
1N/A mutex_unlock(&inited_mutex);
1N/A return( -1 );
1N/A }
1N/A#else
1N/A mutex_unlock(&inited_mutex);
1N/A return( -1 );
1N/A#endif
1N/A
1N/A inited = 1;
1N/A mutex_unlock(&inited_mutex);
1N/A
1N/A return( 0 );
1N/A
1N/A}
1N/A
1N/A/*
1N/A * Initialize ns/security so it can be used for SSL client authentication.
1N/A * It is safe to call this more than once.
1N/A *
1N/A * If needkeydb == 0, no key database is opened and SSL server authentication
1N/A * is supported but not client authentication.
1N/A *
1N/A * If "certdbpath" is NULL or "", the default cert. db is used (typically
1N/A * ~/.netscape/cert7.db).
1N/A *
1N/A * If "certdbpath" ends with ".db" (case-insensitive compare), then
1N/A * it is assumed to be a full path to the cert. db file; otherwise,
1N/A * it is assumed to be a directory that contains a file called
1N/A * "cert7.db" or "cert.db".
1N/A *
1N/A * If certdbhandle is non-NULL, it is assumed to be a pointer to a
1N/A * SECCertDBHandle structure. It is fine to pass NULL since this
1N/A * routine will allocate one for you (CERT_GetDefaultDB() can be
1N/A * used to retrieve the cert db handle).
1N/A *
1N/A * If "keydbpath" is NULL or "", the default key db is used (typically
1N/A * ~/.netscape/key3.db).
1N/A *
1N/A * If "keydbpath" ends with ".db" (case-insensitive compare), then
1N/A * it is assumed to be a full path to the key db file; otherwise,
1N/A * it is assumed to be a directory that contains a file called
1N/A * "key3.db"
1N/A *
1N/A * If certdbhandle is non-NULL< it is assumed to be a pointed to a
1N/A * SECKEYKeyDBHandle structure. It is fine to pass NULL since this
1N/A * routine will allocate one for you (SECKEY_GetDefaultDB() can be
1N/A * used to retrieve the cert db handle). */
1N/Aint
1N/ALDAP_CALL
1N/Aldapssl_advclientauth_init(
1N/A const char *certdbpath, void *certdbhandle,
1N/A const int needkeydb, const char *keydbpath, void *keydbhandle,
1N/A const int needsecmoddb, const char *secmoddbpath,
1N/A const int sslstrength )
1N/A{
1N/A int rc;
1N/A#ifdef _SOLARIS_SDK
1N/A char *enval;
1N/A int rcenv = 0;
1N/A#endif
1N/A
1N/A mutex_lock(&inited_mutex);
1N/A if ( inited ) {
1N/A mutex_unlock(&inited_mutex);
1N/A return( 0 );
1N/A }
1N/A
1N/A /*
1N/A * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_advclientauth_init\n",0 ,0 ,0);
1N/A */
1N/A
1N/A ldapssl_basic_init();
1N/A
1N/A#ifdef _SOLARIS_SDK
1N/A if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
1N/A mutex_unlock(&inited_mutex);
1N/A return (-1);
1N/A }
1N/A#endif
1N/A
1N/A rc = NSS_Init(certdbpath);
1N/A#ifdef _SOLARIS_SDK
1N/A /* Error from NSS_Init() more important! */
1N/A if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
1N/A ldapssl_free(&enval);
1N/A mutex_unlock(&inited_mutex);
1N/A return (-1);
1N/A }
1N/A ldapssl_free(&enval);
1N/A#endif
1N/A if (rc != 0) {
1N/A if ((rc = PR_GetError()) >= 0)
1N/A rc = -1;
1N/A mutex_unlock(&inited_mutex);
1N/A return (rc);
1N/A }
1N/A
1N/A#if defined(NS_DOMESTIC)
1N/A if (local_SSLPLCY_Install() == PR_FAILURE) {
1N/A mutex_unlock(&inited_mutex);
1N/A return( -1 );
1N/A }
1N/A#elif(NS_EXPORT)
1N/A if (local_SSLPLCY_Install() == PR_FAILURE) {
1N/A mutex_unlock(&inited_mutex);
1N/A return( -1 );
1N/A }
1N/A#else
1N/A mutex_unlock(&inited_mutex);
1N/A return( -1 );
1N/A#endif
1N/A
1N/A inited = 1;
1N/A mutex_unlock(&inited_mutex);
1N/A
1N/A return( ldapssl_set_strength( NULL, sslstrength));
1N/A
1N/A}
1N/A
1N/A
1N/A/*
1N/A * Initialize ns/security so it can be used for SSL client authentication.
1N/A * It is safe to call this more than once.
1N/A */
1N/A
1N/A/*
1N/A * XXXceb This is a hack until the new IO functions are done.
1N/A * this function lives in ldapsinit.c
1N/A */
1N/Avoid set_using_pkcs_functions( int val );
1N/A
1N/Aint
1N/ALDAP_CALL
1N/Aldapssl_pkcs_init( const struct ldapssl_pkcs_fns *pfns )
1N/A{
1N/A
1N/A char *certdbName, *s, *keydbpath;
1N/A char *certdbPrefix, *keydbPrefix;
1N/A char *confDir, *keydbName;
1N/A static char *secmodname = "secmod.db";
1N/A int rc;
1N/A#ifdef _SOLARIS_SDK
1N/A char *enval;
1N/A int rcenv = 0;
1N/A#endif
1N/A
1N/A mutex_lock(&inited_mutex);
1N/A if ( inited ) {
1N/A mutex_unlock(&inited_mutex);
1N/A return( 0 );
1N/A }
1N/A/*
1N/A * XXXceb This is a hack until the new IO functions are done.
1N/A * this function MUST be called before ldap_enable_clienauth.
1N/A *
1N/A */
1N/A set_using_pkcs_functions( 1 );
1N/A
1N/A /*
1N/A * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_pkcs_init\n",0 ,0 ,0);
1N/A */
1N/A
1N/A
1N/A ldapssl_basic_init();
1N/A
1N/A pfns->pkcs_getcertpath( NULL, &s);
1N/A confDir = ldapssl_strdup( s );
1N/A certdbPrefix = ldapssl_strdup( s );
1N/A certdbName = ldapssl_strdup( s );
1N/A *certdbPrefix = 0;
1N/A splitpath(s, confDir, certdbPrefix, certdbName);
1N/A
1N/A pfns->pkcs_getkeypath( NULL, &s);
1N/A keydbpath = ldapssl_strdup( s );
1N/A keydbPrefix = ldapssl_strdup( s );
1N/A keydbName = ldapssl_strdup( s );
1N/A *keydbPrefix = 0;
1N/A splitpath(s, keydbpath, keydbPrefix, keydbName);
1N/A
1N/A
1N/A /* verify confDir == keydbpath and adjust as necessary */
1N/A ldapssl_free((void **)&certdbName);
1N/A ldapssl_free((void **)&keydbName);
1N/A ldapssl_free((void **)&keydbpath);
1N/A
1N/A#ifdef _SOLARIS_SDK
1N/A if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
1N/A mutex_unlock(&inited_mutex);
1N/A return (-1);
1N/A }
1N/A#endif
1N/A
1N/A rc = NSS_Initialize(confDir,certdbPrefix,keydbPrefix,secmodname,
1N/A NSS_INIT_READONLY);
1N/A
1N/A ldapssl_free((void **)&certdbPrefix);
1N/A ldapssl_free((void **)&keydbPrefix);
1N/A ldapssl_free((void **)&confDir);
1N/A
1N/A#ifdef _SOLARIS_SDK
1N/A /* Error from NSS_Initialize() more important! */
1N/A if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
1N/A ldapssl_free(&enval);
1N/A mutex_unlock(&inited_mutex);
1N/A return (-1);
1N/A }
1N/A ldapssl_free(&enval);
1N/A#endif
1N/A
1N/A if (rc != 0) {
1N/A if ((rc = PR_GetError()) >= 0)
1N/A rc = -1;
1N/A mutex_unlock(&inited_mutex);
1N/A return (rc);
1N/A }
1N/A
1N/A
1N/A#if 0 /* UNNEEDED BY LIBLDAP */
1N/A /* this is odd */
1N/A PK11_ConfigurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 );
1N/A#endif /* UNNEEDED BY LIBLDAP */
1N/A
1N/A if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
1N/A || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
1N/A if (( rc = PR_GetError()) >= 0 ) {
1N/A rc = -1;
1N/A }
1N/A
1N/A mutex_unlock(&inited_mutex);
1N/A return( rc );
1N/A }
1N/A
1N/A#if defined(NS_DOMESTIC)
1N/A if (local_SSLPLCY_Install() == PR_FAILURE) {
1N/A mutex_unlock(&inited_mutex);
1N/A return( -1 );
1N/A }
1N/A#elif(NS_EXPORT)
1N/A if (local_SSLPLCY_Install() == PR_FAILURE) {
1N/A mutex_unlock(&inited_mutex);
1N/A return( -1 );
1N/A }
1N/A#else
1N/A mutex_unlock(&inited_mutex);
1N/A return( -1 );
1N/A#endif
1N/A
1N/A inited = 1;
1N/A
1N/A if ( certdbName != NULL ) {
1N/A ldapssl_free((void **) &certdbName );
1N/A }
1N/A
1N/A return( ldapssl_set_strength( NULL, LDAPSSL_AUTH_CNCHECK));
1N/A}
1N/A
1N/A
1N/A/*
1N/A * ldapssl_client_init() is a server-authentication only version of
1N/A * ldapssl_clientauth_init().
1N/A */
1N/Aint
1N/ALDAP_CALL
1N/Aldapssl_client_init(const char* certdbpath, void *certdbhandle )
1N/A{
1N/A return( ldapssl_clientauth_init( certdbpath, certdbhandle,
1N/A 0, NULL, NULL ));
1N/A}
1N/A/*
1N/A * ldapssl_serverauth_init() is a server-authentication only version of
1N/A * ldapssl_clientauth_init(). This function allows the sslstrength
1N/A * to be passed in. The sslstrength can take one of the following
1N/A * values:
1N/A * LDAPSSL_AUTH_WEAK: indicate that you accept the server's
1N/A * certificate without checking the CA who
1N/A * issued the certificate
1N/A * LDAPSSL_AUTH_CERT: indicates that you accept the server's
1N/A * certificate only if you trust the CA who
1N/A * issued the certificate
1N/A * LDAPSSL_AUTH_CNCHECK:
1N/A indicates that you accept the server's
1N/A * certificate only if you trust the CA who
1N/A * issued the certificate and if the value
1N/A * of the cn attribute in the DNS hostname
1N/A * of the server
1N/A */
1N/Aint
1N/ALDAP_CALL
1N/Aldapssl_serverauth_init(const char* certdbpath,
1N/A void *certdbhandle,
1N/A const int sslstrength )
1N/A{
1N/A if ( ldapssl_set_strength( NULL, sslstrength ) != 0) {
1N/A return ( -1 );
1N/A }
1N/A
1N/A return( ldapssl_clientauth_init( certdbpath, certdbhandle,
1N/A 0, NULL, NULL ));
1N/A}
1N/A
1N/A/*
1N/A * Function that makes an asynchronous Start TLS extended operation request.
1N/A */
1N/Astatic int ldapssl_tls_start(LDAP *ld, int *msgidp)
1N/A{
1N/A int version, rc;
1N/A BerValue extreq_data;
1N/A
1N/A /* Start TLS extended operation requires an absent "requestValue" field. */
1N/A
1N/A extreq_data.bv_val = NULL;
1N/A extreq_data.bv_len = 0;
1N/A
1N/A /* Make sure version is set to LDAPv3 for extended operations to be
1N/A supported. */
1N/A
1N/A version = LDAP_VERSION3;
1N/A ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
1N/A
1N/A /* Send the Start TLS request (OID: 1.3.6.1.4.1.1466.20037) */
1N/A rc = ldap_extended_operation( ld, START_TLS_OID, &extreq_data,
1N/A NULL, NULL, msgidp );
1N/A
1N/A return rc;
1N/A}
1N/A
1N/A
1N/A/*
1N/A * Function that enables SSL on an already open non-secured LDAP connection.
1N/A * (i.e. the connection is henceforth secured)
1N/A */
1N/Astatic int ldapssl_enableSSL_on_open_connection(LDAP *ld, int defsecure,
1N/A char *certdbpath, char *keydbpath)
1N/A{
1N/A PRLDAPSocketInfo soi;
1N/A
1N/A
1N/A if ( ldapssl_clientauth_init( certdbpath, NULL, 1, keydbpath, NULL ) < 0 ) {
1N/A goto ssl_setup_failure;
1N/A }
1N/A
1N/A /*
1N/A * Retrieve socket info. so we have the PRFileDesc.
1N/A */
1N/A memset( &soi, 0, sizeof(soi));
1N/A soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
1N/A if ( prldap_get_default_socket_info( ld, &soi ) < 0 ) {
1N/A goto ssl_setup_failure;
1N/A }
1N/A
1N/A if ( ldapssl_install_routines( ld ) < 0 ) {
1N/A goto ssl_setup_failure;
1N/A }
1N/A
1N/A
1N/A if (soi.soinfo_prfd == NULL) {
1N/A int sd;
1N/A ldap_get_option( ld, LDAP_OPT_DESC, &sd );
1N/A soi.soinfo_prfd = (PRFileDesc *) PR_ImportTCPSocket( sd );
1N/A }
1N/A /* set the socket information back into the connection handle,
1N/A * because ldapssl_install_routines() resets the socket_arg info in the
1N/A * socket buffer. */
1N/A if ( prldap_set_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) {
1N/A goto ssl_setup_failure;
1N/A }
1N/A
1N/A if ( ldap_set_option( ld, LDAP_OPT_SSL,
1N/A defsecure ? LDAP_OPT_ON : LDAP_OPT_OFF ) < 0 ) {
1N/A goto ssl_setup_failure;
1N/A }
1N/A
1N/A if ( ldapssl_import_fd( ld, defsecure ) < 0 ) {
1N/A goto ssl_setup_failure;
1N/A }
1N/A
1N/A return 0;
1N/A
1N/Assl_setup_failure:
1N/A ldapssl_reset_to_nonsecure( ld );
1N/A
1N/A /* we should here warn the server that we switch back to a non-secure
1N/A connection */
1N/A
1N/A return( -1 );
1N/A}
1N/A
1N/A
1N/A/*
1N/A * ldapssl_tls_start_s() performs a synchronous Start TLS extended operation
1N/A * request.
1N/A *
1N/A * The function returns the result code of the extended operation response
1N/A * sent by the server.
1N/A *
1N/A * In case of a successfull response (LDAP_SUCCESS returned), by the time
1N/A * this function returns the LDAP session designed by ld will have been
1N/A * secured, i.e. the connection will have been imported into SSL.
1N/A *
1N/A * Should the Start TLS request be rejected by the server, the result code
1N/A * returned will be one of the following:
1N/A * LDAP_OPERATIONS_ERROR,
1N/A * LDAP_PROTOCOL_ERROR,
1N/A * LDAP_REFERRAL,
1N/A * LDAP_UNAVAILABLE.
1N/A *
1N/A * Any other error code returned will be due to a failure in the course
1N/A * of operations done on the client side.
1N/A *
1N/A * "certdbpath" and "keydbpath" should contain the path to the client's
1N/A * certificate and key databases respectively. Either the path to the
1N/A * directory containing "default name" databases (i.e. cert7.db and key3.db)
1N/A * can be specified or the actual filenames can be included.
1N/A * If any of these parameters is NULL, the function will assume the database
1N/A * is the same used by Netscape Communicator, which is usually under
1N/A * ~/.netsca /)
1N/A *
1N/A * "referralsp" is a pointer to a list of referrals the server might
1N/A * eventually send back with an LDAP_REFERRAL result code.
1N/A *
1N/A */
1N/A
1N/Aint
1N/ALDAP_CALL
1N/Aldapssl_tls_start_s(LDAP *ld,int defsecure, char *certdbpath, char *keydbpath,
1N/A char ***referralsp)
1N/A{
1N/A int rc, resultCode, msgid;
1N/A char *extresp_oid;
1N/A BerValue *extresp_data;
1N/A LDAPMessage *res;
1N/A
1N/A rc = ldapssl_tls_start( ld, &msgid );
1N/A if ( rc != LDAP_SUCCESS ) {
1N/A return rc;
1N/A }
1N/A
1N/A rc = ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res );
1N/A if ( rc != LDAP_RES_EXTENDED ) {
1N/A
1N/A /* the first response received must be an extended response to an
1N/A Start TLS request */
1N/A
1N/A ldap_msgfree( res );
1N/A return( -1 );
1N/A
1N/A }
1N/A
1N/A rc = ldap_parse_extended_result( ld, res, &extresp_oid, &extresp_data, 0 );
1N/A
1N/A if ( rc != LDAP_SUCCESS ) {
1N/A ldap_msgfree( res );
1N/A return rc;
1N/A }
1N/A
1N/A if ( strcasecmp( extresp_oid, START_TLS_OID ) != 0 ) {
1N/A
1N/A /* the extended response received doesn't correspond to the
1N/A Start TLS request */
1N/A
1N/A ldap_msgfree( res );
1N/A return -1;
1N/A }
1N/A
1N/A resultCode = ldap_get_lderrno( ld, NULL, NULL );
1N/A
1N/A /* Analyze the server's response */
1N/A switch (resultCode) {
1N/A case LDAP_REFERRAL:
1N/A {
1N/A rc = ldap_parse_result( ld, res, NULL, NULL, NULL, referralsp, NULL, 0 );
1N/A if ( rc != LDAP_SUCCESS ) {
1N/A ldap_msgfree( res );
1N/A return rc;
1N/A }
1N/A }
1N/A case LDAP_OPERATIONS_ERROR:
1N/A
1N/A case LDAP_PROTOCOL_ERROR:
1N/A
1N/A case LDAP_UNAVAILABLE:
1N/A goto free_msg_and_return;
1N/A case LDAP_SUCCESS:
1N/A {
1N/A /*
1N/A * If extended response successfull, get connection ready for
1N/A * communicating with the server over SSL/TLS.
1N/A */
1N/A
1N/A if ( ldapssl_enableSSL_on_open_connection( ld, defsecure,
1N/A certdbpath, keydbpath ) < 0 ) {
1N/A resultCode = -1;
1N/A }
1N/A
1N/A } /* case LDAP_SUCCESS */
1N/A default:
1N/A goto free_msg_and_return;
1N/A } /* switch */
1N/A
1N/Afree_msg_and_return:
1N/A ldap_msgfree( res );
1N/A return resultCode;
1N/A}
1N/A
1N/A#endif /* NET_SSL */