mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-11 17:57:32 +09:00
Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1
This commit is contained in:
parent
23e0d82436
commit
e400f4130a
1564 changed files with 510348 additions and 0 deletions
737
ldap/xpcom/src/nsLDAPConnection.cpp
Normal file
737
ldap/xpcom/src/nsLDAPConnection.cpp
Normal file
|
|
@ -0,0 +1,737 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsLDAPInternal.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIDNSRecord.h"
|
||||
#include "nsLDAPConnection.h"
|
||||
#include "nsLDAPMessage.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIDNSService.h"
|
||||
#include "nsINetAddr.h"
|
||||
#include "nsIRequestObserver.h"
|
||||
#include "nsError.h"
|
||||
#include "nsLDAPOperation.h"
|
||||
#include "nsILDAPErrors.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsILDAPURL.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsLDAPUtils.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
const char kDNSServiceContractId[] = "@mozilla.org/network/dns-service;1";
|
||||
|
||||
// constructor
|
||||
//
|
||||
nsLDAPConnection::nsLDAPConnection()
|
||||
: mConnectionHandle(nullptr),
|
||||
mPendingOperationsMutex("nsLDAPConnection.mPendingOperationsMutex"),
|
||||
mPendingOperations(10),
|
||||
mSSL(false),
|
||||
mVersion(nsILDAPConnection::VERSION3),
|
||||
mDNSRequest(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
//
|
||||
nsLDAPConnection::~nsLDAPConnection()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
|
||||
if (obsServ)
|
||||
obsServ->RemoveObserver(this, "profile-change-net-teardown");
|
||||
Close();
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsLDAPConnection)
|
||||
NS_IMPL_RELEASE(nsLDAPConnection)
|
||||
NS_IMPL_CLASSINFO(nsLDAPConnection, NULL, nsIClassInfo::THREADSAFE,
|
||||
NS_LDAPCONNECTION_CID)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsLDAPConnection)
|
||||
NS_INTERFACE_MAP_ENTRY(nsILDAPConnection)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDNSListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsILDAPConnection)
|
||||
NS_IMPL_QUERY_CLASSINFO(nsLDAPConnection)
|
||||
NS_INTERFACE_MAP_END_THREADSAFE
|
||||
NS_IMPL_CI_INTERFACE_GETTER(nsLDAPConnection, nsILDAPConnection,
|
||||
nsISupportsWeakReference, nsIDNSListener,
|
||||
nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLDAPConnection::Init(nsILDAPURL *aUrl, const nsACString &aBindName,
|
||||
nsILDAPMessageListener *aMessageListener,
|
||||
nsISupports *aClosure, uint32_t aVersion)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aUrl);
|
||||
NS_ENSURE_ARG_POINTER(aMessageListener);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// We have to abort all LDAP pending operation before shutdown.
|
||||
obsServ->AddObserver(this, "profile-change-net-teardown", true);
|
||||
|
||||
// Save various items that we'll use later
|
||||
mBindName.Assign(aBindName);
|
||||
mClosure = aClosure;
|
||||
mInitListener = aMessageListener;
|
||||
|
||||
// Make sure we haven't called Init earlier, i.e. there's a DNS
|
||||
// request pending.
|
||||
NS_ASSERTION(!mDNSRequest, "nsLDAPConnection::Init() "
|
||||
"Connection was already initialized\n");
|
||||
|
||||
// Check and save the version number
|
||||
if (aVersion != nsILDAPConnection::VERSION2 &&
|
||||
aVersion != nsILDAPConnection::VERSION3) {
|
||||
NS_ERROR("nsLDAPConnection::Init(): illegal version");
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
mVersion = aVersion;
|
||||
|
||||
// Get the port number, SSL flag for use later, once the DNS server(s)
|
||||
// has resolved the host part.
|
||||
rv = aUrl->GetPort(&mPort);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t options;
|
||||
rv = aUrl->GetOptions(&options);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSSL = options & nsILDAPURL::OPT_SECURE;
|
||||
|
||||
nsCOMPtr<nsIThread> curThread = do_GetCurrentThread();
|
||||
if (!curThread) {
|
||||
NS_ERROR("nsLDAPConnection::Init(): couldn't get current thread");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Do the pre-resolve of the hostname, using the DNS service. This
|
||||
// will also initialize the LDAP connection properly, once we have
|
||||
// the IPs resolved for the hostname. This includes creating the
|
||||
// new thread for this connection.
|
||||
//
|
||||
// XXX - What return codes can we expect from the DNS service?
|
||||
//
|
||||
nsCOMPtr<nsIDNSService>
|
||||
pDNSService(do_GetService(kDNSServiceContractId, &rv));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("nsLDAPConnection::Init(): couldn't create the DNS Service object");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = aUrl->GetAsciiHost(mDNSHost);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// if the caller has passed in a space-delimited set of hosts, as the
|
||||
// ldap c-sdk allows, strip off the trailing hosts for now.
|
||||
// Soon, we'd like to make multiple hosts work, but now make
|
||||
// at least the first one work.
|
||||
LdapCompressWhitespace(mDNSHost);
|
||||
|
||||
int32_t spacePos = mDNSHost.FindChar(' ');
|
||||
// trim off trailing host(s)
|
||||
if (spacePos != kNotFound)
|
||||
mDNSHost.SetLength(spacePos);
|
||||
|
||||
rv = pDNSService->AsyncResolve(mDNSHost, 0, this, curThread,
|
||||
getter_AddRefs(mDNSRequest));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
switch (rv) {
|
||||
case NS_ERROR_OUT_OF_MEMORY:
|
||||
case NS_ERROR_UNKNOWN_HOST:
|
||||
case NS_ERROR_FAILURE:
|
||||
case NS_ERROR_OFFLINE:
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
mDNSHost.Truncate();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// this might get exposed to clients, so we've broken it
|
||||
// out of the destructor.
|
||||
void
|
||||
nsLDAPConnection::Close()
|
||||
{
|
||||
int rc;
|
||||
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug, ("unbinding\n"));
|
||||
|
||||
if (mConnectionHandle) {
|
||||
// note that the ldap_unbind() call in the 5.0 version of the LDAP C SDK
|
||||
// appears to be exactly identical to ldap_unbind_s(), so it may in fact
|
||||
// still be synchronous
|
||||
//
|
||||
rc = ldap_unbind(mConnectionHandle);
|
||||
#ifdef PR_LOGGING
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Warning,
|
||||
("nsLDAPConnection::Close(): %s\n",
|
||||
ldap_err2string(rc)));
|
||||
}
|
||||
#endif
|
||||
mConnectionHandle = nullptr;
|
||||
}
|
||||
|
||||
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug, ("unbound\n"));
|
||||
|
||||
NS_ASSERTION(!mThread || NS_SUCCEEDED(mThread->Shutdown()),
|
||||
"Failed to shutdown thread cleanly");
|
||||
|
||||
// Cancel the DNS lookup if needed, and also drop the reference to the
|
||||
// Init listener (if still there).
|
||||
//
|
||||
if (mDNSRequest) {
|
||||
mDNSRequest->Cancel(NS_ERROR_ABORT);
|
||||
mDNSRequest = nullptr;
|
||||
}
|
||||
mInitListener = nullptr;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLDAPConnection::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
const char16_t *aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "profile-change-net-teardown")) {
|
||||
// Abort all ldap requests.
|
||||
/* We cannot use enumerate function to abort operations because
|
||||
* nsILDAPOperation::AbandonExt() is modifying list of operations
|
||||
* and this leads to starvation.
|
||||
* We have to do a copy of pending operations.
|
||||
*/
|
||||
nsTArray<nsILDAPOperation*> pending_operations;
|
||||
{
|
||||
MutexAutoLock lock(mPendingOperationsMutex);
|
||||
for (auto iter = mPendingOperations.Iter(); !iter.Done(); iter.Next()) {
|
||||
pending_operations.AppendElement(iter.UserData());
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < pending_operations.Length(); i++) {
|
||||
pending_operations[i]->AbandonExt();
|
||||
}
|
||||
Close();
|
||||
} else {
|
||||
NS_NOTREACHED("unexpected topic");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLDAPConnection::GetClosure(nsISupports **_retval)
|
||||
{
|
||||
if (!_retval) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
NS_IF_ADDREF(*_retval = mClosure);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLDAPConnection::SetClosure(nsISupports *aClosure)
|
||||
{
|
||||
mClosure = aClosure;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// who we're binding as
|
||||
//
|
||||
// readonly attribute AUTF8String bindName
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsLDAPConnection::GetBindName(nsACString& _retval)
|
||||
{
|
||||
_retval.Assign(mBindName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// wrapper for ldap_get_lderrno
|
||||
// XXX should copy before returning
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsLDAPConnection::GetLdErrno(nsACString& matched, nsACString& errString,
|
||||
int32_t *_retval)
|
||||
{
|
||||
char *match, *err;
|
||||
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
|
||||
*_retval = ldap_get_lderrno(mConnectionHandle, &match, &err);
|
||||
matched.Assign(match);
|
||||
errString.Assign(err);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// return the error string corresponding to GetLdErrno.
|
||||
//
|
||||
// XXX - deal with optional params
|
||||
// XXX - how does ldap_perror know to look at the global errno?
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsLDAPConnection::GetErrorString(char16_t **_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
|
||||
// get the error string
|
||||
//
|
||||
char *rv = ldap_err2string(ldap_get_lderrno(mConnectionHandle, 0, 0));
|
||||
if (!rv) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// make a copy using the XPCOM shared allocator
|
||||
//
|
||||
*_retval = ToNewUnicode(NS_ConvertUTF8toUTF16(rv));
|
||||
if (!*_retval) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an nsILDAPOperation to the list of operations pending on
|
||||
* this connection. This is also mainly intended for use by the
|
||||
* nsLDAPOperation code.
|
||||
*/
|
||||
nsresult
|
||||
nsLDAPConnection::AddPendingOperation(uint32_t aOperationID, nsILDAPOperation *aOperation)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aOperation);
|
||||
|
||||
nsIRunnable* runnable = new nsLDAPConnectionRunnable(aOperationID, aOperation,
|
||||
this);
|
||||
{
|
||||
MutexAutoLock lock(mPendingOperationsMutex);
|
||||
mPendingOperations.Put((uint32_t)aOperationID, aOperation);
|
||||
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
|
||||
("pending operation added; total pending operations now = %d\n",
|
||||
mPendingOperations.Count()));
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
if (!mThread)
|
||||
{
|
||||
rv = NS_NewThread(getter_AddRefs(mThread), runnable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an nsILDAPOperation from the list of operations pending on this
|
||||
* connection. Mainly intended for use by the nsLDAPOperation code.
|
||||
*
|
||||
* @param aOperation operation to add
|
||||
* @exception NS_ERROR_INVALID_POINTER aOperation was NULL
|
||||
* @exception NS_ERROR_OUT_OF_MEMORY out of memory
|
||||
* @exception NS_ERROR_FAILURE could not delete the operation
|
||||
*
|
||||
* void removePendingOperation(in nsILDAPOperation aOperation);
|
||||
*/
|
||||
nsresult
|
||||
nsLDAPConnection::RemovePendingOperation(uint32_t aOperationID)
|
||||
{
|
||||
NS_ENSURE_TRUE(aOperationID > 0, NS_ERROR_UNEXPECTED);
|
||||
|
||||
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
|
||||
("nsLDAPConnection::RemovePendingOperation(): operation removed\n"));
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mPendingOperationsMutex);
|
||||
mPendingOperations.Remove(aOperationID);
|
||||
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
|
||||
("nsLDAPConnection::RemovePendingOperation(): operation "
|
||||
"removed; total pending operations now = %d\n",
|
||||
mPendingOperations.Count()));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class nsOnLDAPMessageRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
nsOnLDAPMessageRunnable(nsLDAPMessage *aMsg, bool aClear)
|
||||
: m_msg(aMsg)
|
||||
, m_clear(aClear)
|
||||
{}
|
||||
NS_DECL_NSIRUNNABLE
|
||||
private:
|
||||
RefPtr<nsLDAPMessage> m_msg;
|
||||
bool m_clear;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP nsOnLDAPMessageRunnable::Run()
|
||||
{
|
||||
// get the message listener object.
|
||||
nsLDAPOperation *nsoperation = static_cast<nsLDAPOperation *>(m_msg->mOperation.get());
|
||||
nsCOMPtr<nsILDAPMessageListener> listener;
|
||||
nsresult rv = nsoperation->GetMessageListener(getter_AddRefs(listener));
|
||||
|
||||
if (m_clear)
|
||||
{
|
||||
// try to break cycles
|
||||
nsoperation->Clear();
|
||||
}
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
NS_ERROR("nsLDAPConnection::InvokeMessageCallback(): probable "
|
||||
"memory corruption: GetMessageListener() returned nullptr");
|
||||
return rv;
|
||||
}
|
||||
|
||||
return listener->OnLDAPMessage(m_msg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLDAPConnection::InvokeMessageCallback(LDAPMessage *aMsgHandle,
|
||||
nsILDAPMessage *aMsg,
|
||||
int32_t aOperation,
|
||||
bool aRemoveOpFromConnQ)
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
// We only want this being logged for debug builds so as not to affect performance too much.
|
||||
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug, ("InvokeMessageCallback entered\n"));
|
||||
#endif
|
||||
|
||||
// Get the operation.
|
||||
nsCOMPtr<nsILDAPOperation> operation;
|
||||
{
|
||||
MutexAutoLock lock(mPendingOperationsMutex);
|
||||
mPendingOperations.Get((uint32_t)aOperation, getter_AddRefs(operation));
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(operation, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsLDAPMessage *msg = static_cast<nsLDAPMessage *>(aMsg);
|
||||
msg->mOperation = operation;
|
||||
|
||||
// proxy the listener callback to the ui thread.
|
||||
RefPtr<nsOnLDAPMessageRunnable> runnable =
|
||||
new nsOnLDAPMessageRunnable(msg, aRemoveOpFromConnQ);
|
||||
// invoke the callback
|
||||
NS_DispatchToMainThread(runnable);
|
||||
|
||||
// if requested (ie the operation is done), remove the operation
|
||||
// from the connection queue.
|
||||
if (aRemoveOpFromConnQ)
|
||||
{
|
||||
MutexAutoLock lock(mPendingOperationsMutex);
|
||||
mPendingOperations.Remove(aOperation);
|
||||
|
||||
MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug,
|
||||
("pending operation removed; total pending operations now ="
|
||||
" %d\n", mPendingOperations.Count()));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLDAPConnection::OnLookupComplete(nsICancelable *aRequest,
|
||||
nsIDNSRecord *aRecord,
|
||||
nsresult aStatus)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (aRecord) {
|
||||
// Build mResolvedIP list
|
||||
//
|
||||
mResolvedIP.Truncate();
|
||||
|
||||
int32_t index = 0;
|
||||
nsCString addrbuf;
|
||||
nsCOMPtr<nsINetAddr> addr;
|
||||
|
||||
while (NS_SUCCEEDED(aRecord->GetScriptableNextAddr(0, getter_AddRefs(addr)))) {
|
||||
// We can only use v4 addresses
|
||||
//
|
||||
uint16_t family = 0;
|
||||
bool v4mapped = false;
|
||||
addr->GetFamily(&family);
|
||||
addr->GetIsV4Mapped(&v4mapped);
|
||||
if (family == nsINetAddr::FAMILY_INET || v4mapped) {
|
||||
// If there are more IPs in the list, we separate them with
|
||||
// a space, as supported/used by the LDAP C-SDK.
|
||||
//
|
||||
if (index++)
|
||||
mResolvedIP.Append(' ');
|
||||
|
||||
// Convert the IPv4 address to a string, and append it to our
|
||||
// list of IPs. Strip leading '::FFFF:' (the IPv4-mapped-IPv6
|
||||
// indicator) if present.
|
||||
//
|
||||
addr->GetAddress(addrbuf);
|
||||
if (addrbuf[0] == ':' && addrbuf.Length() > 7)
|
||||
mResolvedIP.Append(Substring(addrbuf, 7));
|
||||
else
|
||||
mResolvedIP.Append(addrbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(aStatus)) {
|
||||
// The DNS service failed, lets pass something reasonable
|
||||
// back to the listener.
|
||||
//
|
||||
switch (aStatus) {
|
||||
case NS_ERROR_OUT_OF_MEMORY:
|
||||
case NS_ERROR_UNKNOWN_HOST:
|
||||
case NS_ERROR_FAILURE:
|
||||
case NS_ERROR_OFFLINE:
|
||||
rv = aStatus;
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
break;
|
||||
}
|
||||
} else if (!mResolvedIP.Length()) {
|
||||
// We have no host resolved, that is very bad, and should most
|
||||
// likely have been caught earlier.
|
||||
//
|
||||
NS_ERROR("nsLDAPConnection::OnStopLookup(): the resolved IP "
|
||||
"string is empty.\n");
|
||||
|
||||
rv = NS_ERROR_UNKNOWN_HOST;
|
||||
} else {
|
||||
// We've got the IP(s) for the hostname, now lets setup the
|
||||
// LDAP connection using this information. Note that if the
|
||||
// LDAP server returns a referral, the C-SDK will perform a
|
||||
// new, synchronous DNS lookup, which might hang (but hopefully
|
||||
// if we've come this far, DNS is working properly).
|
||||
//
|
||||
mConnectionHandle = ldap_init(mResolvedIP.get(),
|
||||
mPort == -1 ?
|
||||
(mSSL ? LDAPS_PORT : LDAP_PORT) : mPort);
|
||||
// Check that we got a proper connection, and if so, setup the
|
||||
// threading functions for this connection.
|
||||
//
|
||||
if ( !mConnectionHandle ) {
|
||||
rv = NS_ERROR_FAILURE; // LDAP C SDK API gives no useful error
|
||||
} else {
|
||||
#if defined(DEBUG_dmose) || defined(DEBUG_bienvenu)
|
||||
const int lDebug = 0;
|
||||
ldap_set_option(mConnectionHandle, LDAP_OPT_DEBUG_LEVEL, &lDebug);
|
||||
#endif
|
||||
|
||||
// the C SDK currently defaults to v2. if we're to use v3,
|
||||
// tell it so.
|
||||
//
|
||||
int version;
|
||||
switch (mVersion) {
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
version = LDAP_VERSION3;
|
||||
ldap_set_option(mConnectionHandle, LDAP_OPT_PROTOCOL_VERSION,
|
||||
&version);
|
||||
break;
|
||||
default:
|
||||
NS_ERROR("nsLDAPConnection::OnLookupComplete(): mVersion"
|
||||
" invalid");
|
||||
}
|
||||
|
||||
// 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, mDNSHost.get());
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("nsLDAPConnection::OnStopLookup(): Error"
|
||||
" installing secure LDAP routines for"
|
||||
" connection");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Drop the DNS request object, we no longer need it, and set the flag
|
||||
// indicating that DNS has finished.
|
||||
//
|
||||
mDNSRequest = nullptr;
|
||||
mDNSHost.Truncate();
|
||||
|
||||
// Call the listener, and then we can release our reference to it.
|
||||
//
|
||||
mInitListener->OnLDAPInit(this, rv);
|
||||
mInitListener = nullptr;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsLDAPConnectionRunnable::nsLDAPConnectionRunnable(int32_t aOperationID,
|
||||
nsILDAPOperation *aOperation,
|
||||
nsLDAPConnection *aConnection)
|
||||
: mOperationID(aOperationID), mConnection(aConnection)
|
||||
{
|
||||
}
|
||||
|
||||
nsLDAPConnectionRunnable::~nsLDAPConnectionRunnable()
|
||||
{
|
||||
if (mConnection) {
|
||||
NS_ReleaseOnMainThread(mConnection.forget());
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsLDAPConnectionRunnable, nsIRunnable)
|
||||
|
||||
NS_IMETHODIMP nsLDAPConnectionRunnable::Run()
|
||||
{
|
||||
if (!mOperationID) {
|
||||
NS_ERROR("mOperationID is null");
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
LDAPMessage *msgHandle;
|
||||
bool operationFinished = true;
|
||||
RefPtr<nsLDAPMessage> msg;
|
||||
|
||||
struct timeval timeout = { 0, 0 };
|
||||
|
||||
nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
|
||||
int32_t returnCode = ldap_result(mConnection->mConnectionHandle, mOperationID, LDAP_MSG_ONE, &timeout, &msgHandle);
|
||||
switch (returnCode)
|
||||
{
|
||||
// timeout
|
||||
case 0:
|
||||
// XXX do we need a timer?
|
||||
return thread->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
|
||||
case -1:
|
||||
NS_ERROR("We don't know what went wrong with the ldap operation");
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
case LDAP_RES_SEARCH_ENTRY:
|
||||
case LDAP_RES_SEARCH_REFERENCE:
|
||||
// XXX what should we do with LDAP_RES_SEARCH_EXTENDED
|
||||
operationFinished = false;
|
||||
MOZ_FALLTHROUGH;
|
||||
default:
|
||||
{
|
||||
msg = new nsLDAPMessage;
|
||||
if (!msg)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// initialize the message, using a protected method not available
|
||||
// through nsILDAPMessage (which is why we need the raw pointer)
|
||||
nsresult rv = msg->Init(mConnection, msgHandle);
|
||||
|
||||
switch (rv)
|
||||
{
|
||||
case NS_OK:
|
||||
{
|
||||
int32_t errorCode;
|
||||
msg->GetErrorCode(&errorCode);
|
||||
|
||||
// maybe a version error, e.g., using v3 on a v2 server.
|
||||
// if we're using v3, try v2.
|
||||
if (errorCode == LDAP_PROTOCOL_ERROR &&
|
||||
mConnection->mVersion == nsILDAPConnection::VERSION3)
|
||||
{
|
||||
nsAutoCString password;
|
||||
mConnection->mVersion = nsILDAPConnection::VERSION2;
|
||||
ldap_set_option(mConnection->mConnectionHandle,
|
||||
LDAP_OPT_PROTOCOL_VERSION, &mConnection->mVersion);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
// We don't want to notify callers that we are done, so
|
||||
// redispatch the runnable.
|
||||
// XXX do we need a timer?
|
||||
rv = thread->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// If we're midway through a SASL Bind, we need to continue
|
||||
// without letting our caller know what we're up to!
|
||||
//
|
||||
if (errorCode == LDAP_SASL_BIND_IN_PROGRESS) {
|
||||
struct berval *creds;
|
||||
ldap_parse_sasl_bind_result(
|
||||
mConnection->mConnectionHandle, msgHandle,
|
||||
&creds, 0);
|
||||
|
||||
nsCOMPtr<nsILDAPOperation> operation;
|
||||
{
|
||||
MutexAutoLock lock(mConnection->mPendingOperationsMutex);
|
||||
mConnection->mPendingOperations.Get((uint32_t)mOperationID, getter_AddRefs(operation));
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(operation, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsresult rv = operation->SaslStep(creds->bv_val, creds->bv_len);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return NS_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Error code handling in here
|
||||
default:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// invoke the callback on the nsILDAPOperation corresponding to
|
||||
// this message
|
||||
rv = mConnection->InvokeMessageCallback(msgHandle, msg, mOperationID,
|
||||
operationFinished);
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
NS_ERROR("CheckLDAPOperationResult(): error invoking message"
|
||||
" callback");
|
||||
// punt and hope things work out better next time around
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!operationFinished)
|
||||
{
|
||||
// XXX do we need a timer?
|
||||
rv = thread->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue