From 49752a8d2d37d6bcbdaa9c4b5d7e43b58197feef Mon Sep 17 00:00:00 2001 From: "dmose%netscape.com" Date: Wed, 10 Apr 2002 04:21:13 +0000 Subject: [PATCH] LDAP over SSL (bug 107411). UI changes thanks to srilatha@netscape.com nsLDAPSecurityGlue.cpp: r=mcs@netscape.com; Mac S/MIME build changes: r=javi@netscape.com; Mac Project changes: r=rdayal; all other files: r=bhuvan@netscape.com; entire patch: sr=sspitzer@netscape.com --- build/mac/build_scripts/MozillaBuildFlags.txt | 2 +- .../xpcom/base/public/nsILDAPConnection.idl | 6 +- directory/xpcom/base/src/Makefile.in | 7 + directory/xpcom/base/src/makefile.win | 10 +- directory/xpcom/base/src/nsLDAPChannel.cpp | 19 +- directory/xpcom/base/src/nsLDAPChannel.h | 2 +- directory/xpcom/base/src/nsLDAPConnection.cpp | 61 ++- directory/xpcom/base/src/nsLDAPConnection.h | 3 +- directory/xpcom/base/src/nsLDAPInternal.h | 1 - .../xpcom/base/src/nsLDAPSecurityGlue.cpp | 358 ++++++++++++++++++ directory/xpcom/base/src/nsLDAPService.cpp | 9 +- directory/xpcom/macbuild/mozldap.xml | 54 +++ .../pref/autoconfig/src/nsLDAPSyncQuery.cpp | 11 +- .../resources/content/pref-directory-add.js | 53 ++- .../resources/content/pref-directory-add.xul | 26 +- .../prefs/resources/content/pref-directory.js | 6 +- .../locale/en-US/pref-directory-add.dtd | 12 +- .../en-US/replicationProgress.properties | 14 +- .../addrbook/resources/content/abCommon.js | 2 +- .../addrbook/src/nsAbLDAPDirectoryQuery.cpp | 26 +- .../addrbook/src/nsAbLDAPReplicationQuery.cpp | 15 +- mailnews/addrbook/src/nsLDAPPrefsService.js | 20 +- mailnews/mime/macbuild/mimePrefix.h | 4 + mailnews/mime/macbuild/mimePrefixDebug.h | 4 + .../src/nsLDAPAutoCompleteSession.cpp | 14 +- 25 files changed, 672 insertions(+), 67 deletions(-) create mode 100644 directory/xpcom/base/src/nsLDAPSecurityGlue.cpp diff --git a/build/mac/build_scripts/MozillaBuildFlags.txt b/build/mac/build_scripts/MozillaBuildFlags.txt index a7ba4cacaf61..1b6d803362d4 100644 --- a/build/mac/build_scripts/MozillaBuildFlags.txt +++ b/build/mac/build_scripts/MozillaBuildFlags.txt @@ -54,7 +54,7 @@ wsp 0 MOZ_WSP inspector 1 mailextras 1 xptlink 0 -psm 0 ENABLE_SMIME +psm 0 MOZ_PSM embedding_test 1 embedding_chrome 0 embedding_xulprefs 0 diff --git a/directory/xpcom/base/public/nsILDAPConnection.idl b/directory/xpcom/base/public/nsILDAPConnection.idl index e3c81b4938eb..ba60301ab214 100644 --- a/directory/xpcom/base/public/nsILDAPConnection.idl +++ b/directory/xpcom/base/public/nsILDAPConnection.idl @@ -59,7 +59,9 @@ interface nsILDAPConnection : nsISupports * @param aHost server name for ldap_init() * @param aPort server port number for ldap_init() * -1 == default port (389) + * @param aSSL use SSL on this connection? * @param aBindName DN to bind as + * @param aMessageListener Callback for DNS resolution completion * * @exception NS_ERROR_ILLEGAL_VALUE null pointer passed in * @exception NS_ERROR_OUT_OF_MEMORY ran out of memory @@ -67,7 +69,8 @@ interface nsILDAPConnection : nsISupports * @exception NS_ERROR_FAILURE * @exception NS_ERROR_UNEXPECTED internal error */ - void init(in string aHost, in short aPort, in wstring aBindName, + void init(in string aHost, in short aPort, in boolean aSSL, + in wstring aBindName, in nsILDAPMessageListener aMessageListener); /** @@ -84,5 +87,4 @@ interface nsILDAPConnection : nsISupports * @return the error code, as defined in nsILDAPErrors.idl */ long getLdErrno(out wstring matched, out wstring s); - }; diff --git a/directory/xpcom/base/src/Makefile.in b/directory/xpcom/base/src/Makefile.in index 2227cdb08e81..c468f5c044c6 100644 --- a/directory/xpcom/base/src/Makefile.in +++ b/directory/xpcom/base/src/Makefile.in @@ -71,6 +71,13 @@ CPPSRCS += \ REQUIRES += mimetype endif +ifdef MOZ_PSM +DEFINES += -DMOZ_PSM +CPPSRCS += \ + nsLDAPSecurityGlue.cpp \ + $(NULL) +endif + EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) $(LDAP_LIBS) include $(topsrcdir)/config/rules.mk diff --git a/directory/xpcom/base/src/makefile.win b/directory/xpcom/base/src/makefile.win index 6dfe21da3d52..8f082d6d6a0c 100644 --- a/directory/xpcom/base/src/makefile.win +++ b/directory/xpcom/base/src/makefile.win @@ -44,6 +44,9 @@ CPP_OBJS = .\$(OBJDIR)\nsLDAPURL.obj \ !if defined(ENABLE_LDAP_EXPERIMENTAL) .\$(OBJDIR)\nsLDAPProtocolHandler.obj \ .\$(OBJDIR)\nsLDAPChannel.obj \ +!endif +!if defined(BUILD_PSM) || defined(BUILD_PSM2) + .\$(OBJDIR)\nsLDAPSecurityGlue.obj \ !endif $(NULL) @@ -56,11 +59,16 @@ LCFLAGS = \ !if defined(ENABLE_LDAP_EXPERIMENTAL) DEFINES = -DMOZ_LDAP_XPCOM_EXPERIMENTAL $(DEFINES) +!endif + +!if defined(BUILD_PSM) || defined(BUILD_PSM2) +DEFINES = -DMOZ_PSM $(DEFINES) +!endif + LCFLAGS = \ $(LCFLAGS) \ $(DEFINES) \ $(NULL) -!endif include <$(DEPTH)\config\rules.mak> diff --git a/directory/xpcom/base/src/nsLDAPChannel.cpp b/directory/xpcom/base/src/nsLDAPChannel.cpp index d493b584d3fc..1e229b7095bc 100644 --- a/directory/xpcom/base/src/nsLDAPChannel.cpp +++ b/directory/xpcom/base/src/nsLDAPChannel.cpp @@ -541,6 +541,7 @@ nsLDAPChannel::AsyncOpen(nsIStreamListener* aListener, nsresult rv; nsCAutoString host; PRInt32 port; + PRUint32 options; // slurp out relevant pieces of the URL // @@ -558,6 +559,20 @@ nsLDAPChannel::AsyncOpen(nsIStreamListener* aListener, if (port == -1) port = LDAP_PORT; + // QI to nsILDAPURL so that we can call one of the methods on that iface + // + nsCOMPtr mLDAPURL = do_QueryInterface(mURI, &rv); + if (NS_FAILED(rv)) { + NS_ERROR("nsLDAPChannel::AsyncRead(): QI to nsILDAPURL failed\n"); + return NS_ERROR_FAILURE; + } + + rv = mLDAPURL->GetOptions(&options); + if (NS_FAILED(rv)) { + NS_ERROR("nsLDAPChannel::AsyncRead(): mURI->GetOptions failed\n"); + return NS_ERROR_FAILURE; + } + rv = NS_CheckPortSafety(port, "ldap"); if (NS_FAILED(rv)) return rv; @@ -625,7 +640,9 @@ nsLDAPChannel::AsyncOpen(nsIStreamListener* aListener, // initialize it with the defaults // XXXdmose - need to deal with bind name // - rv = mConnection->Init(host.get(), port, 0, this); + rv = mConnection->Init(host.get(), port, + (options & nsILDAPURL::OPT_SECURE) ? PR_TRUE + : PR_FALSE, nsnull, this); switch (rv) { case NS_OK: break; diff --git a/directory/xpcom/base/src/nsLDAPChannel.h b/directory/xpcom/base/src/nsLDAPChannel.h index b6c1cbdb2dbf..c145fb40baf1 100644 --- a/directory/xpcom/base/src/nsLDAPChannel.h +++ b/directory/xpcom/base/src/nsLDAPChannel.h @@ -39,7 +39,6 @@ #include "nsIRunnable.h" #include "nsIThread.h" #include "nsIChannel.h" -#include "nsIURI.h" #include "nsILoadGroup.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" @@ -48,6 +47,7 @@ #include "nsIStreamListener.h" #include "nsILDAPMessageListener.h" #include "nsIProgressEventSink.h" +#include "nsILDAPURL.h" // if the code related to the following #define ever gets removed, also // be sure to remove mCallback as well as the most (but not all) of the diff --git a/directory/xpcom/base/src/nsLDAPConnection.cpp b/directory/xpcom/base/src/nsLDAPConnection.cpp index 5fad06b6de4b..0f986adec254 100644 --- a/directory/xpcom/base/src/nsLDAPConnection.cpp +++ b/directory/xpcom/base/src/nsLDAPConnection.cpp @@ -61,6 +61,7 @@ nsLDAPConnection::nsLDAPConnection() mBindName(0), mPendingOperations(0), mRunnable(0), + mSSL(PR_FALSE), mDNSRequest(0), mDNSFinished(PR_FALSE) { @@ -168,10 +169,9 @@ nsLDAPConnection::Release(void) NS_IMETHODIMP -nsLDAPConnection::Init(const char *aHost, PRInt16 aPort, - const PRUnichar *aBindName, +nsLDAPConnection::Init(const char *aHost, PRInt16 aPort, PRBool aSSL, + const PRUnichar *aBindName, nsILDAPMessageListener *aMessageListener) - { nsCOMPtr selfProxy; nsresult rv; @@ -204,6 +204,9 @@ nsLDAPConnection::Init(const char *aHost, PRInt16 aPort, // mPort = aPort; + // Save the SSL flag for later use + mSSL = aSSL; + // Save the Init listener reference, we need it when the async // DNS resolver has finished. // @@ -643,27 +646,42 @@ CheckLDAPOperationResult(nsHashKey *aKey, void *aData, void* aClosure) // the nsLDAPConnection to detect the error, and then // create a new connection. // + PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, + ("CheckLDAPOperationResult(): ldap_result returned" + " LDAP_SERVER_DOWN")); break; case LDAP_DECODING_ERROR: consoleSvc->LogStringMessage( NS_LITERAL_STRING("LDAP: WARNING: decoding error; possible corrupt data received").get()); - NS_WARNING("CheckLDAPOperationResult(): ldaperrno = " + NS_WARNING("CheckLDAPOperationResult(): ldaperrno = " "LDAP_DECODING_ERROR after ldap_result()"); break; case LDAP_NO_MEMORY: - NS_ERROR("CheckLDAPOperationResult(): Couldn't allocate memory" - " while getting async operation result"); + NS_ERROR("CheckLDAPOperationResult(): Couldn't allocate memory" + " while getting async operation result"); // punt and hope things work out better next time around break; - default: - NS_ERROR("CheckLDAPOperationResult(): ldaperrno set to " - "unexpected value after ldap_result() " - "call in nsLDAPConnection::Run()"); + case LDAP_PARAM_ERROR: + // I think it's possible to hit a race condition where we're + // continuing to poll for a result after the C SDK connection + // has removed the operation because the connection has gone + // dead. In theory we should fix this. Practically, it's + // unclear to me whether it matters. + // + NS_WARNING("CheckLDAPOperationResult(): ldap_result returned" + " LDAP_PARAM_ERROR"); break; + default: + NS_ERROR("CheckLDAPOperationResult(): lderrno set to " + "unexpected value after ldap_result() " + "call in nsLDAPConnection::Run()"); + PR_LOG(gLDAPLogModule, PR_LOG_ERROR, + ("lderrno = 0x%x", lderrno)); + break; } break; @@ -945,7 +963,6 @@ nsLDAPConnection::OnStopLookup(nsISupports *aContext, // mConnectionHandle = ldap_init(mResolvedIP.get(), mPort == -1 ? LDAP_PORT : mPort); - // Check that we got a proper connection, and if so, setup the // threading functions for this connection. // @@ -958,6 +975,28 @@ nsLDAPConnection::OnStopLookup(nsISupports *aContext, #endif } +#ifdef MOZ_PSM + // This code sets up the current connection to use PSM for SSL + // functionality. Making this use libssldap instead for + // non-browser user shouldn't be hard. + + extern nsresult nsLDAPInstallSSL(LDAP *ld, const char *aHostName); + + if (mSSL) { + if (ldap_set_option(mConnectionHandle, LDAP_OPT_SSL, LDAP_OPT_ON) + != LDAP_SUCCESS ) { + NS_ERROR("nsLDAPConnection::OnStopLookup(): Error configuring" + " connection to use SSL"); + rv = NS_ERROR_UNEXPECTED; + } + + rv = nsLDAPInstallSSL(mConnectionHandle, aHostName); + if (NS_FAILED(rv)) { + NS_ERROR("nsLDAPConnection::OnStopLookup(): Error installing" + " secure LDAP routines for connection"); + } + } +#endif // Create a new runnable object, and increment the refcnt. The // thread will also hold a strong ref to the runnable, but we need // to make sure it doesn't get destructed until we are done with diff --git a/directory/xpcom/base/src/nsLDAPConnection.h b/directory/xpcom/base/src/nsLDAPConnection.h index 9b4033cc43b1..4ddab5fe0e19 100644 --- a/directory/xpcom/base/src/nsLDAPConnection.h +++ b/directory/xpcom/base/src/nsLDAPConnection.h @@ -119,7 +119,8 @@ class nsLDAPConnection : public nsILDAPConnection, nsSupportsHashtable *mPendingOperations; // keep these around for callbacks nsLDAPConnectionLoop *mRunnable; // nsIRunnable object - PRInt16 mPort; // The LDAP port we're binding to + PRInt16 mPort; // The LDAP port we're binding to + PRBool mSSL; // the options nsCString mResolvedIP; // Preresolved list of host IPs nsCOMPtr mInitListener; // Init callback diff --git a/directory/xpcom/base/src/nsLDAPInternal.h b/directory/xpcom/base/src/nsLDAPInternal.h index 67cc9caa0c8a..f9977c733980 100644 --- a/directory/xpcom/base/src/nsLDAPInternal.h +++ b/directory/xpcom/base/src/nsLDAPInternal.h @@ -32,7 +32,6 @@ * GPL. */ #include "nsLDAP.h" -#include "nspr.h" #ifdef PR_LOGGING extern PRLogModuleInfo *gLDAPLogModule; // defn in nsLDAPProtocolModule.cpp diff --git a/directory/xpcom/base/src/nsLDAPSecurityGlue.cpp b/directory/xpcom/base/src/nsLDAPSecurityGlue.cpp new file mode 100644 index 000000000000..ddd4529e848c --- /dev/null +++ b/directory/xpcom/base/src/nsLDAPSecurityGlue.cpp @@ -0,0 +1,358 @@ +/* + * 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-2002 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Mark Smith + * Michael Hein + * Dan Mosedale + * Seth Spitzer + */ + +// Only build this code if PSM is being built also +// +#ifdef MOZ_PSM + +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsISSLSocketProvider.h" +#include "nsIInterfaceRequestor.h" +#include "nsISSLSocketControl.h" +#include "nsMemory.h" +#include "nsLDAPInternal.h" +#include "plstr.h" +#include "ldap.h" +#include "ldappr.h" + +// LDAP per-session data structure. +// +typedef struct { + char *hostname; + LDAP_X_EXTIOF_CLOSE_CALLBACK *realClose; + LDAP_X_EXTIOF_CONNECT_CALLBACK *realConnect; + LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK *realDisposeHandle; +} nsLDAPSSLSessionClosure; + +// LDAP per-socket data structure. +// +typedef struct { + nsLDAPSSLSessionClosure *sessionClosure; /* session info */ +} nsLDAPSSLSocketClosure; + +// free the per-socket data structure as necessary +// +static void +nsLDAPSSLFreeSocketClosure(nsLDAPSSLSocketClosure **aClosure) +{ + if (aClosure && *aClosure) { + nsMemory::Free(*aClosure); + *aClosure = nsnull; + } +} + +// Replacement close() function, which cleans up local stuff associated +// with this socket, and then calls the real close function. +// +static int +nsLDAPSSLClose(int s, struct lextiof_socket_private *socketarg) +{ + PRLDAPSocketInfo socketInfo; + nsLDAPSSLSocketClosure *socketClosure; + nsLDAPSSLSessionClosure *sessionClosure; + + // get the socketInfo associated with this socket + // + memset(&socketInfo, 0, sizeof(socketInfo)); + socketInfo.soinfo_size = PRLDAP_SOCKETINFO_SIZE; + if (prldap_get_socket_info(s, socketarg, &socketInfo) != LDAP_SUCCESS) { + NS_ERROR("nsLDAPSSLClose(): prldap_get_socket_info() failed\n"); + return -1; + } + + // save off the session closure data in an automatic, since we're going to + // need to call through it + // + socketClosure = NS_REINTERPRET_CAST(nsLDAPSSLSocketClosure *, + socketInfo.soinfo_appdata); + sessionClosure = socketClosure->sessionClosure; + + // free the socket closure data + // + nsLDAPSSLFreeSocketClosure( + NS_REINTERPRET_CAST(nsLDAPSSLSocketClosure **, + &socketInfo.soinfo_appdata)); + + // call the real close function + // + return (*(sessionClosure->realClose))(s, socketarg); +} + +// Replacement connection function. Calls the real connect function, +// +static int LDAP_CALLBACK +nsLDAPSSLConnect(const char *hostlist, int defport, int timeout, + unsigned long options, + struct lextiof_session_private *sessionarg, + struct lextiof_socket_private **socketargp ) +{ + PRLDAPSocketInfo socketInfo; + PRLDAPSessionInfo sessionInfo; + nsLDAPSSLSocketClosure *socketClosure = nsnull; + nsLDAPSSLSessionClosure *sessionClosure; + int intfd = -1; + nsCOMPtr securityInfo; + nsCOMPtr tlsSocketProvider; + nsCOMPtr sslSocketControl; + nsresult rv; + + // Ensure 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). + // + NS_ASSERTION(options & LDAP_X_EXTIOF_OPT_SECURE, + "nsLDAPSSLConnect(): called for non-secure connection"); + options &= ~LDAP_X_EXTIOF_OPT_SECURE; + + // Retrieve session info. so we can store a pointer to our session info. + // in our socket info. later. + // + memset(&sessionInfo, 0, sizeof(sessionInfo)); + sessionInfo.seinfo_size = PRLDAP_SESSIONINFO_SIZE; + if (prldap_get_session_info(nsnull, sessionarg, &sessionInfo) + != LDAP_SUCCESS) { + NS_ERROR("nsLDAPSSLConnect(): unable to get session info"); + return -1; + } + sessionClosure = NS_REINTERPRET_CAST(nsLDAPSSLSessionClosure *, + sessionInfo.seinfo_appdata); + + // Call the real connect() callback to make the TCP connection. If it + // succeeds, *socketargp is set. + // + intfd = (*(sessionClosure->realConnect))(hostlist, defport, timeout, + options, sessionarg, socketargp); + if ( intfd < 0 ) { + PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, + ("nsLDAPSSLConnect(): standard connect() function returned %d", + intfd)); + return intfd; + } + + // Retrieve socket info from the newly created socket so that we + // have the PRFileDesc onto which we will be layering SSL. + // + memset(&socketInfo, 0, sizeof(socketInfo)); + socketInfo.soinfo_size = PRLDAP_SOCKETINFO_SIZE; + if (prldap_get_socket_info(intfd, *socketargp, &socketInfo) + != LDAP_SUCCESS) { + NS_ERROR("nsLDAPSSLConnect(): unable to get socket info"); + goto close_socket_and_exit_with_error; + } + + // Allocate a structure to hold our socket-specific data. + // + socketClosure = NS_STATIC_CAST(nsLDAPSSLSocketClosure *, + nsMemory::Alloc( + sizeof(nsLDAPSSLSocketClosure))); + if (!socketClosure) { + NS_WARNING("nsLDAPSSLConnect(): unable to allocate socket closure"); + goto close_socket_and_exit_with_error; + } + memset(socketClosure, 0, sizeof(nsLDAPSSLSocketClosure)); + socketClosure->sessionClosure = sessionClosure; + + // Add the NSPR layer for SSL provided by PSM to this socket. + // + tlsSocketProvider = do_GetService(NS_TLSSTEPUPSOCKETPROVIDER_CONTRACTID, + &rv); + if (NS_FAILED(rv)) { + NS_ERROR("nsLDAPSSLConnect(): unable to get socket provider service"); + goto close_socket_and_exit_with_error; + } + // XXXdmose: Note that hostlist can be a list of hosts (in the + // current XPCOM SDK code, it will always be a list of IP + // addresses). Because of this, we need to use + // sessionClosure->hostname which was passed in separately to tell + // AddToSocket what to match the name in the certificate against. + // What exactly happen will happen when this is used with some IP + // address in the list other than the first one is not entirely + // clear, and I suspect it may depend on the format of the name in + // the certificate. Need to investigate. + // + rv = tlsSocketProvider->AddToSocket(sessionClosure->hostname, defport, + nsnull, 0, socketInfo.soinfo_prfd, + getter_AddRefs(securityInfo)); + if (NS_FAILED(rv)) { + NS_ERROR("nsLDAPSSLConnect(): unable to add SSL layer to socket"); + goto close_socket_and_exit_with_error; + } + + // If possible we want to avoid using SSLv2, as this can confuse + // some directory servers (notably the netscape 4.1 ds). The only + // way that PSM provides for us to do this is to invoke TLSStepUp. + // (Thanks to Brian Ryner for helping figure this out). + // + sslSocketControl = do_QueryInterface(securityInfo, &rv); + if (NS_FAILED(rv)) { + NS_WARNING("nsLDAPSSLConnect(): unable to QI to nsISSLSocketControl"); + } else { + rv = sslSocketControl->TLSStepUp(); + if (NS_FAILED(rv)) { + NS_WARNING("nsLDAPSSLConnect(): TLSStepUp failed"); + } + } + + // Attach our closure to the socketInfo. + // + socketInfo.soinfo_appdata = NS_REINTERPRET_CAST(prldap_socket_private *, + socketClosure); + if (prldap_set_socket_info(intfd, *socketargp, &socketInfo) + != LDAP_SUCCESS ) { + NS_ERROR("nsLDAPSSLConnect(): unable to set socket info"); + } + return intfd; // success + +close_socket_and_exit_with_error: + if (socketInfo.soinfo_prfd) { + PR_Close(socketInfo.soinfo_prfd); + } + if (socketClosure) { + nsLDAPSSLFreeSocketClosure(&socketClosure); + } + if ( intfd >= 0 && *socketargp ) { + (*(sessionClosure->realClose))(intfd, *socketargp); + } + return -1; + +} + +// Free data associated with this session (LDAP *) as necessary. +// +static void +nsLDAPSSLFreeSessionClosure(nsLDAPSSLSessionClosure **aSessionClosure) +{ + if (aSessionClosure && *aSessionClosure) { + + // free the hostname + // + if ( (*aSessionClosure)->hostname ) { + PL_strfree((*aSessionClosure)->hostname); + (*aSessionClosure)->hostname = nsnull; + } + + // free the structure itself + // + nsMemory::Free(*aSessionClosure); + *aSessionClosure = nsnull; + } +} + +// Replacement session handle disposal code. First cleans up our local +// stuff, then calls the original session handle disposal function. +// +static void +nsLDAPSSLDisposeHandle(LDAP *ld, struct lextiof_session_private *sessionarg) +{ + PRLDAPSessionInfo sessionInfo; + nsLDAPSSLSessionClosure *sessionClosure; + LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK *disposehdl_fn; + + memset(&sessionInfo, 0, sizeof(sessionInfo)); + sessionInfo.seinfo_size = PRLDAP_SESSIONINFO_SIZE; + if (prldap_get_session_info(ld, nsnull, &sessionInfo) == LDAP_SUCCESS) { + sessionClosure = NS_REINTERPRET_CAST(nsLDAPSSLSessionClosure *, + sessionInfo.seinfo_appdata); + disposehdl_fn = sessionClosure->realDisposeHandle; + nsLDAPSSLFreeSessionClosure(&sessionClosure); + (*disposehdl_fn)(ld, sessionarg); + } +} + +// Installs appropriate routines and data for making this connection +// handle SSL. The aHostName is ultimately passed to PSM and is used to +// validate certificates. +// +nsresult +nsLDAPInstallSSL( LDAP *ld, const char *aHostName) +{ + struct ldap_x_ext_io_fns iofns; + nsLDAPSSLSessionClosure *sessionClosure; + PRLDAPSessionInfo sessionInfo; + + // Allocate our own session information. + // + sessionClosure = NS_STATIC_CAST(nsLDAPSSLSessionClosure *, + nsMemory::Alloc( + sizeof(nsLDAPSSLSessionClosure))); + if (!sessionClosure) { + return NS_ERROR_OUT_OF_MEMORY; + } + memset(sessionClosure, 0, sizeof(nsLDAPSSLSessionClosure)); + + // Override a few functions, saving a pointer to the original function + // in each case so we can call it from our SSL savvy functions. + // + memset(&iofns, 0, sizeof(iofns)); + iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; + if (ldap_get_option(ld, LDAP_X_OPT_EXTIO_FN_PTRS, + NS_STATIC_CAST(void *, &iofns)) != LDAP_SUCCESS) { + NS_ERROR("nsLDAPInstallSSL(): unexpected error getting" + " LDAP_X_OPT_EXTIO_FN_PTRS"); + nsLDAPSSLFreeSessionClosure(&sessionClosure); + return NS_ERROR_UNEXPECTED; + } + + // Make a copy of the hostname to pass to AddToSocket later + // + sessionClosure->hostname = PL_strdup(aHostName); + if (!sessionClosure->hostname) { + NS_ERROR("nsLDAPInstallSSL(): PL_strdup failed\n"); + nsLDAPSSLFreeSessionClosure(&sessionClosure); + return NS_ERROR_OUT_OF_MEMORY; + } + + // Override functions + // + sessionClosure->realClose = iofns.lextiof_close; + iofns.lextiof_close = nsLDAPSSLClose; + sessionClosure->realConnect = iofns.lextiof_connect; + iofns.lextiof_connect = nsLDAPSSLConnect; + sessionClosure->realDisposeHandle = iofns.lextiof_disposehandle; + iofns.lextiof_disposehandle = nsLDAPSSLDisposeHandle; + + if (ldap_set_option(ld, LDAP_X_OPT_EXTIO_FN_PTRS, + NS_STATIC_CAST(void *, &iofns)) != LDAP_SUCCESS) { + NS_ERROR("nsLDAPInstallSSL(): error setting LDAP_X_OPT_EXTIO_FN_PTRS"); + nsLDAPSSLFreeSessionClosure(&sessionClosure); + return NS_ERROR_FAILURE; + } + + // Store session info. for later retrieval. + // + sessionInfo.seinfo_size = PRLDAP_SESSIONINFO_SIZE; + sessionInfo.seinfo_appdata = NS_REINTERPRET_CAST(prldap_session_private *, + sessionClosure); + if (prldap_set_session_info(ld, nsnull, &sessionInfo) != LDAP_SUCCESS) { + NS_ERROR("nsLDAPInstallSSL(): error setting prldap session info"); + nsMemory::Free(sessionClosure); + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +#endif diff --git a/directory/xpcom/base/src/nsLDAPService.cpp b/directory/xpcom/base/src/nsLDAPService.cpp index f212b06812be..3dec44693ae4 100644 --- a/directory/xpcom/base/src/nsLDAPService.cpp +++ b/directory/xpcom/base/src/nsLDAPService.cpp @@ -720,6 +720,7 @@ nsLDAPService::EstablishConnection(nsLDAPServiceEntry *aEntry, nsXPIDLString binddn; nsXPIDLString password; PRInt32 port; + PRUint32 options; nsresult rv; server = getter_AddRefs(aEntry->GetServer()); @@ -753,6 +754,10 @@ nsLDAPService::EstablishConnection(nsLDAPServiceEntry *aEntry, return NS_ERROR_FAILURE; } + rv = url->GetOptions(&options); + if (NS_FAILED(rv)) { + return NS_ERROR_FAILURE; + } // Create a new connection for this server. // conn = do_CreateInstance(kLDAPConnectionCID, &rv); @@ -764,7 +769,9 @@ nsLDAPService::EstablishConnection(nsLDAPServiceEntry *aEntry, // Here we need to provide the binddn, see bug #75990 // - rv = conn->Init(host.get(), port, 0, this); + rv = conn->Init(host.get(), port, + (options & nsILDAPURL::OPT_SECURE) ? PR_TRUE : PR_FALSE, + nsnull, this); if (NS_FAILED(rv)) { switch (rv) { // Only pass along errors we are aware of diff --git a/directory/xpcom/macbuild/mozldap.xml b/directory/xpcom/macbuild/mozldap.xml index 4e1a6d6e32f1..d4fcf9491b53 100644 --- a/directory/xpcom/macbuild/mozldap.xml +++ b/directory/xpcom/macbuild/mozldap.xml @@ -1065,6 +1065,13 @@ Text + + Name + nsLDAPSecurityGlue.cpp + MacOS + Text + Debug + @@ -1137,6 +1144,11 @@ nsLDAPService.cpp MacOS + + Name + nsLDAPSecurityGlue.cpp + MacOS + @@ -2151,6 +2163,13 @@ Text + + Name + nsLDAPSecurityGlue.cpp + MacOS + Text + Debug + @@ -2223,6 +2242,11 @@ nsLDAPService.cpp MacOS + + Name + nsLDAPSecurityGlue.cpp + MacOS + @@ -3251,6 +3275,13 @@ Text + + Name + nsLDAPSecurityGlue.cpp + MacOS + Text + Debug + @@ -3333,6 +3364,11 @@ nsLDAPServer.cpp MacOS + + Name + nsLDAPSecurityGlue.cpp + MacOS + @@ -4361,6 +4397,13 @@ Text + + Name + nsLDAPSecurityGlue.cpp + MacOS + Text + Debug + @@ -4443,6 +4486,11 @@ nsLDAPServer.cpp MacOS + + Name + nsLDAPSecurityGlue.cpp + MacOS + @@ -4510,6 +4558,12 @@ nsLDAPURL.cpp MacOS + + mozldapDebug.shlb + Name + nsLDAPSecurityGlue.cpp + MacOS + NS Libraries Optimized diff --git a/extensions/pref/autoconfig/src/nsLDAPSyncQuery.cpp b/extensions/pref/autoconfig/src/nsLDAPSyncQuery.cpp index ea53ca07c5b8..aff7982e956c 100644 --- a/extensions/pref/autoconfig/src/nsLDAPSyncQuery.cpp +++ b/extensions/pref/autoconfig/src/nsLDAPSyncQuery.cpp @@ -402,6 +402,13 @@ nsresult nsLDAPSyncQuery::InitConnection() return NS_ERROR_FAILURE; } + PRUint32 options; + rv = mServerURL->GetOptions(&options); + if (NS_FAILED(rv)) { + FinishLDAPQuery(); + return NS_ERROR_FAILURE; + } + // get a proxy object so the callback happens on the main thread // rv = NS_GetProxyForObject(NS_CURRENT_EVENTQ, @@ -416,7 +423,9 @@ nsresult nsLDAPSyncQuery::InitConnection() return NS_ERROR_FAILURE; } - rv = mConnection->Init(host.get(), port, 0, selfProxy); + rv = mConnection->Init(host.get(), port, + (options & nsILDAPURL::OPT_SECURE) + ? PR_TRUE : PR_FALSE, 0, selfProxy); if (NS_FAILED(rv)) { FinishLDAPQuery(); return NS_ERROR_UNEXPECTED; // this should never happen diff --git a/mailnews/addrbook/prefs/resources/content/pref-directory-add.js b/mailnews/addrbook/prefs/resources/content/pref-directory-add.js index 7a30537955d2..6798a6165308 100644 --- a/mailnews/addrbook/prefs/resources/content/pref-directory-add.js +++ b/mailnews/addrbook/prefs/resources/content/pref-directory-add.js @@ -3,10 +3,12 @@ var gPref_string_desc = ""; var gPrefInt = null; var gCurrentDirectory = null; var gCurrentDirectoryString = null; -var gPortNumber = 389; -var gMaxHits = 100; var gLdapService = null; +const kDefaultMaxHits = 100; +const kDefaultLDAPPort = 389; +const kDefaultSecureLDAPPort = 636; + function Startup() { if ( "arguments" in window && window.arguments[0] ) { @@ -91,21 +93,39 @@ function fillSettings() default: sub.radioGroup.selectedItem = sub; break; } + if (ldapUrl.options & ldapUrl.OPT_SECURE) + document.getElementById("secure").setAttribute("checked", "true"); } try { prefValue = gPrefInt.getIntPref(gCurrentDirectoryString+ ".maxHits"); } catch(ex) { - prefValue = gMaxHits; + prefValue = kDefaultMaxHits; } document.getElementById("results").value = prefValue; + try{ + prefValue = gPrefInt.getBoolPref(gCurrentDirectoryString +".auth.enabled"); + } + catch(ex){ + prefValue = false; + } + document.getElementById("login").setAttribute("checked", prefValue); } } +function onSecure() +{ + var port = document.getElementById("port"); + if (document.getElementById("secure").checked) + port.value = kDefaultSecureLDAPPort; + else + port.value = kDefaultLDAPPort; +} + function fillDefaultSettings() { - document.getElementById("port").value = gPortNumber; - document.getElementById("results").value = gMaxHits; + document.getElementById("port").value = kDefaultLDAPPort; + document.getElementById("results").value = kDefaultMaxHits; var sub = document.getElementById("sub"); sub.radioGroup.selectedItem = sub; } @@ -210,6 +230,8 @@ function onAccept() var description = document.getElementById("description").value; var hostname = document.getElementById("hostname").value; var port = document.getElementById("port").value; + var secure = document.getElementById("secure"); + var login = document.getElementById("login"); var results = document.getElementById("results").value; var errorValue = null; gPref_string_desc = description; @@ -260,8 +282,12 @@ function onAccept() UCS2toUTF8(document.getElementById("search").value); ldapUrl.filter = pref_string_content; } - if (!port) - ldapUrl.port = gPortNumber; + if (!port) { + if (secure.checked) + ldapUrl.port = kDefaultSecureLDAPPort; + else + ldapUrl.port = kDefaultLDAPPort; + } else ldapUrl.port = port; if (document.getElementById("one").selected) @@ -271,11 +297,13 @@ function onAccept() else { ldapUrl.scope = 2; } + if (secure.checked) + ldapUrl.options |= ldapUrl.OPT_SECURE; pref_string_title = gPref_string_desc + ".uri"; gPrefInt.setCharPref(pref_string_title, ldapUrl.spec); pref_string_content = results; pref_string_title = gPref_string_desc + ".maxHits"; - if (pref_string_content != gMaxHits) { + if (pref_string_content != kDefaultMaxHits) { gPrefInt.setIntPref(pref_string_title, pref_string_content); } else @@ -286,12 +314,9 @@ function onAccept() catch(ex) {} } pref_string_title = gPref_string_desc + ".auth.enabled"; - try{ - pref_string_content = gPrefInt.getBoolPref(pref_string_title); - } - catch(ex) { - pref_string_content = false; - } + pref_string_content = login.checked; + gPrefInt.setBoolPref(pref_string_title, pref_string_content); + window.opener.gNewServer = description; window.opener.gNewServerString = gPref_string_desc; // set window.opener.gUpdate to true so that LDAP Directory Servers diff --git a/mailnews/addrbook/prefs/resources/content/pref-directory-add.xul b/mailnews/addrbook/prefs/resources/content/pref-directory-add.xul index 31cd0148a78d..cf0565b54744 100644 --- a/mailnews/addrbook/prefs/resources/content/pref-directory-add.xul +++ b/mailnews/addrbook/prefs/resources/content/pref-directory-add.xul @@ -28,7 +28,7 @@ + @@ -77,8 +78,23 @@