--- a/directory/xpcom/base/public/nsILDAPOperation.idl
+++ b/directory/xpcom/base/public/nsILDAPOperation.idl
@@ -17,16 +17,17 @@
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dan Mosedale <dmose@mozilla.org>
+ * Simon Wilkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -34,32 +35,33 @@
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
#include "nsILDAPConnection.idl"
+#include "nsIAuthModule.idl"
interface nsILDAPMessage;
interface nsILDAPMessageListener;
interface nsILDAPModification;
interface nsIMutableArray;
interface nsIArray;
%{C++
#define NS_LDAPOPERATION_CONTRACTID "@mozilla.org/network/ldap-operation;1"
%}
// XXXdmose check to make sure ctl-related err codes documented
typedef PRUint32 PRIntervalTime;
-[scriptable, uuid(b9a7ed9d-adf9-4612-8cb7-cdb5c4ef16fd)]
+[scriptable, uuid(40cc61c6-539b-4157-b0f0-ed81ecd29b8e)]
interface nsILDAPOperation : nsISupports
{
/**
* The connection this operation is on.
*
* @exception NS_ERROR_ILLEGAL_VALUE a NULL pointer was passed in
*/
readonly attribute nsILDAPConnection connection;
@@ -125,16 +127,36 @@ interface nsILDAPOperation : nsISupports
* @exception NS_ERROR_LDAP_SERVER_DOWN server down (XXX rebinds?)
* @exception NS_ERROR_LDAP_CONNECT_ERROR connection failed or lost
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_UNEXPECTED internal error
*/
void simpleBind(in AUTF8String passwd);
/**
+ * Asynchronously perform a SASL bind against the LDAP server
+ *
+ * @param service the host name of the service being connected to
+ * @param mechanism the name of the SASL mechanism in use
+ * @param authModule the nsIAuthModule to be used to perform the operation
+ *
+ */
+ void saslBind(in ACString service, in ACString mechanism,
+ in nsIAuthModule authModule);
+
+ /**
+ * Continue a SASL bind operation
+ *
+ * @param token the next SASL token to send to the server
+ * @param tokenLen the length of the token to send
+ *
+ */
+ void saslStep(in string token, in unsigned long tokenLen);
+
+ /**
* Kicks off an asynchronous add request. The "ext" stands for
* "extensions", and is intended to convey that this method will
* eventually support the extensions described in the
* draft-ietf-ldapext-ldap-c-api-04.txt Internet Draft.
*
* @param aBaseDn Base DN to add
* @param aModCount Number of modifications
* @param aMods Array of modifications
--- a/directory/xpcom/base/src/nsLDAPConnection.cpp
+++ b/directory/xpcom/base/src/nsLDAPConnection.cpp
@@ -22,16 +22,17 @@
*
* Contributor(s):
* Dan Mosedale <dmose@mozilla.org> (original author)
* Leif Hedstrom <leif@netscape.com>
* Kipp Hickman <kipp@netscape.com>
* Warren Harris <warren@netscape.com>
* Dan Matejka <danm@netscape.com>
* David Bienvenu <bienvenu@mozilla.org>
+ * Simon Wilkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -713,16 +714,21 @@ CheckLDAPOperationResult(nsHashKey *aKey
break;
}
// initialize the message, using a protected method not available
// through nsILDAPMessage (which is why we need the raw pointer)
//
rv = rawMsg->Init(loop->mRawConn, msgHandle);
+ // now let the scoping mechanisms provided by nsCOMPtr manage
+ // the reference for us.
+ //
+ msg = rawMsg;
+
switch (rv) {
case NS_OK: {
PRInt32 errorCode;
rawMsg->GetErrorCode(&errorCode);
// maybe a version error, e.g., using v3 on a v2 server.
// if we're using v3, try v2.
//
@@ -739,16 +745,35 @@ CheckLDAPOperationResult(nsHashKey *aKey
//
rv = operation->SimpleBind(password);
if (NS_SUCCEEDED(rv)) {
operationFinished = PR_FALSE;
// we don't want to notify callers that we're done...
return PR_TRUE;
}
}
+
+ // 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(
+ loop->mRawConn->mConnectionHandle, msgHandle,
+ &creds, 0);
+
+ nsCOMPtr <nsILDAPOperation> operation =
+ static_cast<nsILDAPOperation *>
+ (static_cast<nsISupports *>(aData));
+
+ rv = operation->SaslStep(creds->bv_val, creds->bv_len);
+ if (NS_SUCCEEDED(rv)) {
+ return PR_TRUE;
+ }
+ }
}
break;
case NS_ERROR_LDAP_DECODING_ERROR:
consoleSvc->LogStringMessage(
NS_LITERAL_STRING("LDAP: WARNING: decoding error; possible corrupt data received").get());
NS_WARNING("CheckLDAPOperationResult(): ldaperrno = "
"LDAP_DECODING_ERROR after ldap_result()");
@@ -765,21 +790,16 @@ CheckLDAPOperationResult(nsHashKey *aKey
//
NS_ERROR("CheckLDAPOperationResult(): nsLDAPMessage::Init() "
"returned unexpected value.");
// punt and hope things work out better next time around
return PR_TRUE;
}
- // now let the scoping mechanisms provided by nsCOMPtr manage
- // the reference for us.
- //
- msg = rawMsg;
-
// invoke the callback on the nsILDAPOperation corresponding to
// this message
//
rv = loop->mRawConn->InvokeMessageCallback(msgHandle, msg,
operationFinished);
if (NS_FAILED(rv)) {
NS_ERROR("CheckLDAPOperationResult(): error invoking message"
" callback");
--- a/directory/xpcom/base/src/nsLDAPOperation.cpp
+++ b/directory/xpcom/base/src/nsLDAPOperation.cpp
@@ -17,16 +17,17 @@
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dan Mosedale <dmose@mozilla.org>
+ * Simon Wilkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -45,16 +46,17 @@
#include "nsILDAPModification.h"
#include "nsIComponentManager.h"
#include "nsReadableUtils.h"
#include "nspr.h"
#include "nsISimpleEnumerator.h"
#include "nsLDAPControl.h"
#include "nsILDAPErrors.h"
#include "nsIClassInfoImpl.h"
+#include "nsIAuthModule.h"
#include "nsArrayUtils.h"
// Helper function
static nsresult TranslateLDAPErrorToNSError(const int ldapError)
{
switch (ldapError) {
case LDAP_SUCCESS:
return NS_OK;
@@ -189,16 +191,110 @@ nsLDAPOperation::GetMessageListener(nsIL
}
*aMessageListener = mMessageListener;
NS_IF_ADDREF(*aMessageListener);
return NS_OK;
}
+NS_IMETHODIMP
+nsLDAPOperation::SaslBind(const nsACString &service,
+ const nsACString &mechanism,
+ nsIAuthModule *authModule)
+{
+ nsresult rv;
+ nsCAutoString bindName;
+ struct berval creds;
+ unsigned int credlen;
+
+ mAuthModule = authModule;
+ mMechanism.Assign(mechanism);
+
+ rv = mConnection->GetBindName(bindName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ creds.bv_val = NULL;
+ mAuthModule->Init(PromiseFlatCString(service).get(),
+ nsIAuthModule::REQ_DEFAULT, nsnull,
+ NS_ConvertUTF8toUTF16(bindName).get(), nsnull);
+
+ rv = mAuthModule->GetNextToken(nsnull, 0, (void **)&creds.bv_val,
+ &credlen);
+ if (NS_FAILED(rv) || !creds.bv_val)
+ return rv;
+
+ creds.bv_len = credlen;
+ const int lderrno = ldap_sasl_bind(mConnectionHandle, bindName.get(),
+ mMechanism.get(), &creds, NULL, NULL,
+ &mMsgID);
+ nsMemory::Free(creds.bv_val);
+
+ if (lderrno != LDAP_SUCCESS)
+ return TranslateLDAPErrorToNSError(lderrno);
+
+ // make sure the connection knows where to call back once the messages
+ // for this operation start coming in
+ rv = static_cast<nsLDAPConnection *>
+ (static_cast<nsILDAPConnection *>(mConnection.get()))
+ ->AddPendingOperation(this);
+
+ if (NS_FAILED(rv))
+ (void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsLDAPOperation::SaslStep(const char *token, PRUint32 tokenLen)
+{
+ nsresult rv;
+ nsCAutoString bindName;
+ struct berval clientCreds;
+ struct berval serverCreds;
+ unsigned int credlen;
+
+ rv = static_cast<nsLDAPConnection *>
+ (static_cast<nsILDAPConnection *>(mConnection.get()))
+ ->RemovePendingOperation(this);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ serverCreds.bv_val = (char *) token;
+ serverCreds.bv_len = tokenLen;
+
+ rv = mConnection->GetBindName(bindName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = mAuthModule->GetNextToken(serverCreds.bv_val, serverCreds.bv_len,
+ (void **) &clientCreds.bv_val, &credlen);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ clientCreds.bv_len = credlen;
+
+ const int lderrno = ldap_sasl_bind(mConnectionHandle, bindName.get(),
+ mMechanism.get(), &clientCreds, NULL,
+ NULL, &mMsgID);
+
+ nsMemory::Free(clientCreds.bv_val);
+
+ if (lderrno != LDAP_SUCCESS)
+ return TranslateLDAPErrorToNSError(lderrno);
+
+ // make sure the connection knows where to call back once the messages
+ // for this operation start coming in
+ rv = static_cast<nsLDAPConnection *>
+ (static_cast<nsILDAPConnection *>(mConnection.get()))
+ ->AddPendingOperation(this);
+ if (NS_FAILED(rv))
+ (void)ldap_abandon_ext(mConnectionHandle, mMsgID, 0, 0);
+
+ return rv;
+}
+
+
// wrapper for ldap_simple_bind()
//
NS_IMETHODIMP
nsLDAPOperation::SimpleBind(const nsACString& passwd)
{
nsresult rv;
nsCAutoString bindName;
PRBool originalMsgID = mMsgID;
--- a/directory/xpcom/base/src/nsLDAPOperation.h
+++ b/directory/xpcom/base/src/nsLDAPOperation.h
@@ -17,16 +17,17 @@
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dan Mosedale <dmose@mozilla.org>
+ * Simon Wilkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -119,15 +120,17 @@ class nsLDAPOperation : public nsILDAPOp
static nsresult CopyValues(nsILDAPModification* aMod, berval*** aBValues);
nsCOMPtr<nsILDAPMessageListener> mMessageListener; // results go here
nsCOMPtr<nsISupports> mClosure; // private parameter (anything caller desires)
nsCOMPtr<nsILDAPConnection> mConnection; // connection this op is on
LDAP *mConnectionHandle; // cache connection handle
nsCString mSavePassword;
+ nsCString mMechanism;
+ nsCOMPtr<nsIAuthModule> mAuthModule;
PRInt32 mMsgID; // opaque handle to outbound message for this op
nsCOMPtr<nsIMutableArray> mClientControls;
nsCOMPtr<nsIMutableArray> mServerControls;
};
#endif // _nsLDAPOperation_h
--- a/mail/components/addrbook/content/abCommon.js
+++ b/mail/components/addrbook/content/abCommon.js
@@ -19,16 +19,17 @@
# the Initial Developer. All Rights Reserved.
#
# Original Author:
# Paul Hangas <hangas@netscape.com>
#
# Contributor(s):
# Seth Spitzer <sspitzer@netscape.com>
# Mark Banner <mark@standard8.demon.co.uk>
+# Simon Wilkinson <simon@sxw.org.uk>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
@@ -728,16 +729,24 @@ function setupLdapAutocompleteSession()
//
try {
LDAPSession.login =gPrefs.getComplexValue(
autocompleteDirectory + ".auth.dn",
Components.interfaces.nsISupportsString).data;
} catch (ex) {
// if we don't have this pref, no big deal
}
+
+ try {
+ LDAPSession.saslMechanism = gPrefs.getComplexValue(
+ autocompleteDirectory + ".auth.saslmech",
+ Components.interfaces.nsISupportsString).data;
+ } catch (ex) {
+ // if we don't have a mechanism, we'll just use simple binds
+ }
// don't search on non-CJK strings shorter than this
//
try {
LDAPSession.minStringLength = gPrefs.getIntPref(
autocompleteDirectory + ".autoComplete.minStringLength");
} catch (ex) {
// if this pref isn't there, no big deal. just let
--- a/mail/components/compose/content/MsgComposeCommands.js
+++ b/mail/components/compose/content/MsgComposeCommands.js
@@ -18,16 +18,17 @@
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 1998-1999
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# David Bienvenu <bienvenu@nventure.com>
# Olivier Parniere BT Global Services / Etat francais Ministere de la Defense
+# Simon Wilkinson <simon@sxw.org.uk>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
@@ -858,16 +859,23 @@ function setupLdapAutocompleteSession()
// get the login to authenticate as, if there is one
//
try {
LDAPSession.login = getPref(autocompleteDirectory + ".auth.dn", true);
} catch (ex) {
// if we don't have this pref, no big deal
}
+ try {
+ LDAPSession.saslMechanism = getPref(autocompleteDirectory +
+ ".auth.saslmech", true);
+ } catch (ex) {
+ // don't care if we don't have this pref
+ }
+
// set the LDAP protocol version correctly
var protocolVersion;
try {
protocolVersion = getPref(autocompleteDirectory +
".protocolVersion");
} catch (ex) {
// if we don't have this pref, no big deal
}
--- a/mail/locales/en-US/chrome/messenger/addressbook/pref-directory-add.dtd
+++ b/mail/locales/en-US/chrome/messenger/addressbook/pref-directory-add.dtd
@@ -60,13 +60,20 @@
<!ENTITY scopeOneLevel.label "One Level">
<!ENTITY scopeOneLevel.accesskey "L">
<!ENTITY scopeSubtree.label "Subtree">
<!ENTITY scopeSubtree.accesskey "S">
<!ENTITY return.label "Don't return more than">
<!ENTITY return.accesskey "r">
<!ENTITY results.label "results">
<!ENTITY offlineText.label "You can download a local copy of this directory so that it is available for use when you are working offline.">
+<!ENTITY saslMechanism.label "Login method: ">
+<!ENTITY saslMechanism.accesskey "m">
+<!ENTITY saslOff.label "Simple">
+<!ENTITY saslOff.accesskey "l">
+<!ENTITY saslGSSAPI.label "Kerberos (GSSAPI)">
+<!ENTITY saslGSSAPI.accesskey "K">
+
<!-- Localization note: this is here because the width of the dialog
is determined by the width of the base DN box; and that is likely
to vary somewhat with the language.
-->
<!ENTITY newDirectoryWidth "36em">
--- a/mailnews/addrbook/prefs/resources/content/pref-directory-add.js
+++ b/mailnews/addrbook/prefs/resources/content/pref-directory-add.js
@@ -195,16 +195,26 @@ function fillSettings()
switch(ldapUrl.scope) {
case Components.interfaces.nsILDAPURL.SCOPE_ONELEVEL:
sub.radioGroup.selectedItem = document.getElementById("one");
break;
default:
sub.radioGroup.selectedItem = sub;
break;
}
+
+ var sasl = document.getElementById("saslMechanism");
+ switch (gCurrentDirectory.saslMechanism) {
+ case "GSSAPI":
+ sasl.selectedItem = document.getElementById("GSSAPI");
+ break;
+ default:
+ sasl.selectedItem = document.getElementById("Simple");
+ break;
+ }
var secure = ldapUrl.options & ldapUrl.OPT_SECURE
if (secure)
document.getElementById("secure").setAttribute("checked", "true");
if (ldapUrl.port == -1)
document.getElementById("port").value =
(secure ? kDefaultSecureLDAPPort : kDefaultLDAPPort);
@@ -292,16 +302,17 @@ function onAccept()
var pref_string_title = "";
var description = document.getElementById("description").value;
var hostname = document.getElementById("hostname").value;
var port = document.getElementById("port").value;
var secure = document.getElementById("secure");
var results = document.getElementById("results").value;
var errorValue = null;
+ var saslMechanism = "";
if ((!description) || hasOnlyWhitespaces(description))
errorValue = "invalidName";
else if ((!hostname) || hasOnlyWhitespaces(hostname))
errorValue = "invalidHostname";
// XXX write isValidDn and call it on the dn string here?
else if (port && hasCharacters(port))
errorValue = "invalidPortNumber";
else if (results && hasCharacters(results))
@@ -309,27 +320,30 @@ function onAccept()
if (!errorValue) {
// XXX Due to the LDAP c-sdk pass a dummy url to the IO service, then
// update the parts (bug 473351).
var ldapUrl = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI((secure.checked ? "ldaps://" : "ldap://") + "localhost/dc=???",
null, null)
.QueryInterface(Components.interfaces.nsILDAPURL);
-
+
ldapUrl.host = hostname;
ldapUrl.port = port ? port :
(secure.checked ? kDefaultSecureLDAPPort :
kDefaultLDAPPort);
ldapUrl.dn = document.getElementById("basedn").value;
ldapUrl.scope = document.getElementById("one").selected ?
Components.interfaces.nsILDAPURL.SCOPE_ONELEVEL :
Components.interfaces.nsILDAPURL.SCOPE_SUBTREE;
ldapUrl.filter = document.getElementById("search").value;
+ if (document.getElementById("GSSAPI").selected) {
+ saslMechanism = "GSSAPI";
+ }
// check if we are modifying an existing directory or adding a new directory
if (gCurrentDirectory) {
gCurrentDirectory.dirName = description;
gCurrentDirectory.lDAPURL = ldapUrl.QueryInterface(Components.interfaces.nsILDAPURL);
window.opener.gNewServerString = gCurrentDirectory.dirPrefId;
}
else { // adding a new directory
@@ -345,16 +359,17 @@ function onAccept()
// give us back the new directory we just created - so go find it from
// rdf so we can set a few final things up on it.
var theDirectory = RDF.GetResource("moz-abldapdirectory://" +
window.opener.gNewServerString)
.QueryInterface(Components.interfaces.nsIAbLDAPDirectory);
theDirectory.maxHits = results;
theDirectory.authDn = document.getElementById("login").value;
+ theDirectory.saslMechanism = saslMechanism;
window.opener.gNewServer = description;
// set window.opener.gUpdate to true so that LDAP Directory Servers
// dialog gets updated
window.opener.gUpdate = true;
} else {
var addressBookBundle = document.getElementById("bundle_addressBook");
--- a/mailnews/addrbook/prefs/resources/content/pref-directory-add.xul
+++ b/mailnews/addrbook/prefs/resources/content/pref-directory-add.xul
@@ -161,16 +161,29 @@
</radiogroup>
</row>
<row>
<label value="&searchFilter.label;"
accesskey="&searchFilter.accesskey;"
control="search"/>
<textbox id="search" multiline="true" flex="1" disableiflocked="true"/>
</row>
+ <row>
+ <label value="&saslMechanism.label;" control="saslMechanism" accesskey="&saslMechanism.accesskey;"/>
+ <menulist id="saslMechanism">
+ <menupopup>
+ <menuitem id="Simple" value=""
+ label="&saslOff.label;"
+ accesskey="&saslOff.accesskey;"/>
+ <menuitem id="GSSAPI" value="GSSAPI"
+ label="&saslGSSAPI.label;"
+ accesskey="&saslGSSAPI.accesskey;"/>
+ </menupopup>
+ </menulist>
+ </row>
</rows>
</grid>
</tabpanels>
</tabbox>
</vbox>
</dialog>
--- a/mailnews/addrbook/public/nsIAbLDAPDirectory.idl
+++ b/mailnews/addrbook/public/nsIAbLDAPDirectory.idl
@@ -17,16 +17,17 @@
* The Initial Developer of the Original Code is
* Oracle Corporation
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dan Mosedale <dan.mosedale@oracle.com>
* Jeremy Laine <jeremy.laine@m4x.org>
+ * Simon Wilkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -49,17 +50,17 @@ interface nsILDAPURL;
#define kLDAPDirectoryRoot "moz-abldapdirectory://"
#define kLDAPDirectoryRootLen 22
%}
/**
* XXX This should really inherit from nsIAbDirectory, and some day it will.
* But for now, doing that complicates implementation.
*/
-[scriptable, uuid(2f689622-3d73-43aa-8580-6a7ba232be2b)]
+[scriptable, uuid(90dde295-e354-4d58-Add8-f9b29a95942d)]
interface nsIAbLDAPDirectory : nsISupports
{
/**
* If set, these arrays of nsILDAPControls are passed through to the
* nsILDAPOperation that searchExt is called on.
*/
attribute nsIMutableArray searchServerControls;
attribute nsIMutableArray searchClientControls;
@@ -70,16 +71,24 @@ interface nsIAbLDAPDirectory : nsISuppor
attribute ACString replicationFileName;
/**
* The version of LDAP protocol in use.
*/
attribute unsigned long protocolVersion;
/**
+ * The SASL mechanism to use to authenticate to the LDAP server
+ * If this is an empty string, then a simple bind will be performed
+ * A non-zero string is assumed to be the name of the SASL mechanism.
+ * Currently the only supported mechanism is GSSAPI
+ */
+ attribute ACString saslMechanism;
+
+ /**
* The AuthDN to use to access the server.
*/
attribute AUTF8String authDn;
/**
* The maximum number of matches that the server will return per a search.
*/
attribute long maxHits;
--- a/mailnews/addrbook/public/nsILDAPAutoCompleteSession.idl
+++ b/mailnews/addrbook/public/nsILDAPAutoCompleteSession.idl
@@ -17,16 +17,17 @@
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dan Mosedale <dmose@netscape.com> (Original Author)
+ * Simon Wilkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -44,17 +45,17 @@
interface nsILDAPURL;
interface nsILDAPAutoCompFormatter;
interface nsIMutableArray;
/**
* Extends nsIAutoCompleteSession to have various LDAP-specific parameters.
* and output format.
*/
-[scriptable, uuid(aced5f6f-013d-4e21-97a6-9da3779c8663)]
+[scriptable, uuid(d6a64827-6206-4070-9bf9-24578df0afe2)]
interface nsILDAPAutoCompleteSession : nsIAutoCompleteSession {
/**
* A template used to construct the RFC 1960 LDAP search filter to use
* while autocompleting.
*
* The authoritative documentation for the format in use can be found at
* at <http://docs.iplanet.com/docs/manuals/dirsdk/csdk41/html/filter.htm>.
@@ -121,16 +122,25 @@ interface nsILDAPAutoCompleteSession : n
/**
* "Login as..." this ID. Currently, this must be specified as a DN.
* In the future, we may support userid and/or email address as well.
* If unset, bind anonymously.
*/
attribute AUTF8String login;
/**
+ * SASL Mechanism to use to perform bind. If unset, a simple bind will
+ * be performed.
+ *
+ * @exception NS_ERROR_OUT_OF_MEMORY Getter couldn't allocate string
+ * @exception NS_ERROR_NULL_POINTER null pointer passed to getter
+ */
+ attribute ACString saslMechanism;
+
+ /**
* What version of the LDAP protocol should be used? Allowed version
* number constants are defined in nsILDAPConnection.idl.
*
* @exception NS_ERROR_ILLEGAL_VALUE illegal version num passed to setter
* @exception NS_ERROR_NULL_POINTER null pointer passed to getter
*/
attribute unsigned long version;
--- a/mailnews/addrbook/src/nsAbLDAPDirectory.cpp
+++ b/mailnews/addrbook/src/nsAbLDAPDirectory.cpp
@@ -20,16 +20,17 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Seth Spitzer <sspitzer@netscape.com>
* Dan Mosedale <dmose@netscape.com>
* Paul Sandoz <paul.sandoz@sun.com>
* Mark Banner <bugzilla@standard8.plus.com>
* Jeremy Laine <jeremy.laine@m4x.org>
+ * Simon Wilkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -641,16 +642,26 @@ NS_IMETHODIMP nsAbLDAPDirectory::GetAuth
NS_IMETHODIMP nsAbLDAPDirectory::SetAuthDn(const nsACString &aAuthDn)
{
// XXX We should cancel any existing LDAP connections here and
// be ready to re-initialise them with the new auth details.
return SetStringValue("auth.dn", aAuthDn);
}
+NS_IMETHODIMP nsAbLDAPDirectory::GetSaslMechanism(nsACString &aSaslMechanism)
+{
+ return GetStringValue("auth.saslmech", EmptyCString(), aSaslMechanism);
+}
+
+NS_IMETHODIMP nsAbLDAPDirectory::SetSaslMechanism(const nsACString &aSaslMechanism)
+{
+ return SetStringValue("auth.saslmech", aSaslMechanism);
+}
+
NS_IMETHODIMP nsAbLDAPDirectory::GetLastChangeNumber(PRInt32 *aLastChangeNumber)
{
return GetIntValue("lastChangeNumber", -1, aLastChangeNumber);
}
NS_IMETHODIMP nsAbLDAPDirectory::SetLastChangeNumber(PRInt32 aLastChangeNumber)
{
return SetIntValue("lastChangeNumber", aLastChangeNumber);
--- a/mailnews/addrbook/src/nsAbLDAPDirectoryQuery.cpp
+++ b/mailnews/addrbook/src/nsAbLDAPDirectoryQuery.cpp
@@ -20,16 +20,17 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Seth Spitzer <sspitzer@netscape.com>
* Dan Mosedale <dmose@netscape.com>
* Paul Sandoz <paul.sandoz@sun.com>
* Mark Banner <bugzilla@standard8.plus.com>
* Jeremy Laine <jeremy.laine@m4x.org>
+ * Simon Wilkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -73,16 +74,17 @@ public:
nsAbQueryLDAPMessageListener(nsIAbDirectoryQueryResultListener* resultListener,
nsILDAPURL* directoryUrl,
nsILDAPURL* searchUrl,
nsILDAPConnection* connection,
nsIAbDirectoryQueryArguments* queryArguments,
nsIMutableArray* serverSearchControls,
nsIMutableArray* clientSearchControls,
const nsACString &login,
+ const nsACString &mechanism,
const PRInt32 resultLimit = -1,
const PRInt32 timeOut = 0);
virtual ~nsAbQueryLDAPMessageListener ();
// nsILDAPMessageListener
NS_IMETHOD OnLDAPMessage(nsILDAPMessage *aMessage);
protected:
@@ -116,29 +118,31 @@ nsAbQueryLDAPMessageListener::nsAbQueryL
nsIAbDirectoryQueryResultListener *resultListener,
nsILDAPURL* directoryUrl,
nsILDAPURL* searchUrl,
nsILDAPConnection* connection,
nsIAbDirectoryQueryArguments* queryArguments,
nsIMutableArray* serverSearchControls,
nsIMutableArray* clientSearchControls,
const nsACString &login,
+ const nsACString &mechanism,
const PRInt32 resultLimit,
const PRInt32 timeOut) :
nsAbLDAPListenerBase(directoryUrl, connection, login, timeOut),
mSearchUrl(searchUrl),
mResultListener(resultListener),
mQueryArguments(queryArguments),
mResultLimit(resultLimit),
mFinished(PR_FALSE),
mCanceled(PR_FALSE),
mWaitingForPrevQueryToFinish(PR_FALSE),
mServerSearchControls(serverSearchControls),
mClientSearchControls(clientSearchControls)
{
+ mSaslMechanism.Assign(mechanism);
}
nsAbQueryLDAPMessageListener::~nsAbQueryLDAPMessageListener ()
{
}
nsresult nsAbQueryLDAPMessageListener::Cancel ()
{
@@ -375,31 +379,36 @@ NS_IMETHODIMP nsAbLDAPDirectoryQuery::Do
nsCOMPtr<nsILDAPURL> currentUrl;
rv = directory->GetLDAPURL(getter_AddRefs(currentUrl));
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString login;
rv = directory->GetAuthDn(login);
NS_ENSURE_SUCCESS(rv, rv);
+ nsCAutoString saslMechanism;
+ rv = directory->GetSaslMechanism(saslMechanism);
+ NS_ENSURE_SUCCESS(rv, rv);
+
PRUint32 protocolVersion;
rv = directory->GetProtocolVersion(&protocolVersion);
NS_ENSURE_SUCCESS(rv, rv);
// To do:
// Ensure query is stopped
// If connection params have changed re-create connection
// else reuse existing connection
PRBool redoConnection = PR_FALSE;
if (!mConnection || !mDirectoryUrl)
{
mDirectoryUrl = currentUrl;
mCurrentLogin = login;
+ mCurrentMechanism = saslMechanism;
mCurrentProtocolVersion = protocolVersion;
redoConnection = PR_TRUE;
}
else
{
PRBool equal;
rv = mDirectoryUrl->Equals(currentUrl, &equal);
NS_ENSURE_SUCCESS(rv, rv);
@@ -407,26 +416,30 @@ NS_IMETHODIMP nsAbLDAPDirectoryQuery::Do
nsCString spec;
mDirectoryUrl->GetSpec(spec);
currentUrl->GetSpec(spec);
if (!equal)
{
mDirectoryUrl = currentUrl;
mCurrentLogin = login;
+ mCurrentMechanism = saslMechanism;
mCurrentProtocolVersion = protocolVersion;
redoConnection = PR_TRUE;
}
else
{
// Has login or version changed?
- if (login != mCurrentLogin || protocolVersion != mCurrentProtocolVersion)
+ if (login != mCurrentLogin ||
+ saslMechanism != mCurrentMechanism ||
+ protocolVersion != mCurrentProtocolVersion)
{
redoConnection = PR_TRUE;
mCurrentLogin = login;
+ mCurrentMechanism = saslMechanism;
mCurrentProtocolVersion = protocolVersion;
}
}
}
nsCOMPtr<nsIURI> uri;
rv = mDirectoryUrl->Clone(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
@@ -575,17 +588,18 @@ NS_IMETHODIMP nsAbLDAPDirectoryQuery::Do
do_QueryInterface((nsIAbDirectoryQuery*)this, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Initiate LDAP message listener
nsAbQueryLDAPMessageListener* _messageListener =
new nsAbQueryLDAPMessageListener(resultListener, mDirectoryUrl, url,
mConnection, aArguments,
serverSearchControls, clientSearchControls,
- mCurrentLogin, aResultLimit, aTimeOut);
+ mCurrentLogin, mCurrentMechanism,
+ aResultLimit, aTimeOut);
if (_messageListener == NULL)
return NS_ERROR_OUT_OF_MEMORY;
mListener = _messageListener;
*_retval = 1;
// Now lets initialize the LDAP connection properly. We'll kick
// off the bind operation in the callback function, |OnLDAPInit()|.
--- a/mailnews/addrbook/src/nsAbLDAPDirectoryQuery.h
+++ b/mailnews/addrbook/src/nsAbLDAPDirectoryQuery.h
@@ -63,14 +63,15 @@ public:
protected:
nsCOMPtr<nsILDAPMessageListener> mListener;
private:
nsCOMPtr<nsILDAPConnection> mConnection;
nsCOMPtr<nsILDAPURL> mDirectoryUrl;
nsCOMArray<nsIAbDirSearchListener> mListeners;
nsCString mCurrentLogin;
+ nsCString mCurrentMechanism;
PRUint32 mCurrentProtocolVersion;
PRBool mInitialized;
};
#endif // nsAbLDAPDirectoryQuery_h__
--- a/mailnews/addrbook/src/nsAbLDAPListenerBase.cpp
+++ b/mailnews/addrbook/src/nsAbLDAPListenerBase.cpp
@@ -18,16 +18,17 @@
* Sun Microsystems, Inc.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Paul Sandoz <paul.sandoz@sun.com>
* Dan Mosedale <dmose@mozilla.org>
* Mark Banner <mark@standard8.demon.co.uk>
+ * Simon Wilkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -102,17 +103,17 @@ NS_IMETHODIMP nsAbLDAPListenerBase::OnLD
if (NS_FAILED(aStatus))
{
InitFailed();
return NS_OK;
}
// If mLogin is set, we're expected to use it to get a password.
//
- if (!mLogin.IsEmpty())
+ if (!mLogin.IsEmpty() && !mSaslMechanism.Equals(NS_LITERAL_CSTRING("GSSAPI")))
{
// get the string bundle service
//
nsCOMPtr<nsIStringBundleService> stringBundleSvc =
do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
@@ -289,16 +290,40 @@ NS_IMETHODIMP nsAbLDAPListenerBase::OnLD
rv = mOperation->Init(mConnection, proxyListener, nsnull);
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): failed to Initialise operation");
InitFailed();
return rv;
}
+ // Try non-password mechanisms first
+ if (mSaslMechanism.Equals(NS_LITERAL_CSTRING("GSSAPI")))
+ {
+ nsCAutoString service;
+ rv = mDirectoryUrl->GetAsciiHost(service);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ service.Insert(NS_LITERAL_CSTRING("ldap@"), 0);
+
+ nsCOMPtr<nsIAuthModule> authModule =
+ do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "sasl-gssapi", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = mOperation->SaslBind(service, mSaslMechanism, authModule);
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): "
+ "failed to perform GSSAPI bind");
+ mOperation = 0; // Break Listener -> Operation -> Listener ref cycle
+ InitFailed();
+ }
+ return rv;
+ }
+
// Bind
rv = mOperation->SimpleBind(NS_ConvertUTF16toUTF8(passwd));
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): failed to perform bind operation");
mOperation = 0; // Break Listener->Operation->Listener reference cycle
InitFailed();
}
--- a/mailnews/addrbook/src/nsAbLDAPListenerBase.h
+++ b/mailnews/addrbook/src/nsAbLDAPListenerBase.h
@@ -71,16 +71,17 @@ protected:
// Called to start off the required task after a bind.
virtual nsresult DoTask() = 0;
nsCOMPtr<nsILDAPURL> mDirectoryUrl;
nsCOMPtr<nsILDAPOperation> mOperation; // current ldap op
nsILDAPConnection* mConnection;
nsCString mLogin;
+ nsCString mSaslMechanism;
PRInt32 mTimeOut;
PRBool mBound;
PRBool mInitialized;
PRLock* mLock;
};
#endif
--- a/mailnews/addrbook/src/nsAbLDAPReplicationData.cpp
+++ b/mailnews/addrbook/src/nsAbLDAPReplicationData.cpp
@@ -17,16 +17,17 @@
* The Initial Developer of the Original Code is
* Rajiv Dayal <rdayal@netscape.com>
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dan Mosedale <dan.mosedale@oracle.com>
* Mark Banner <bugzilla@standard8.demon.co.uk>
+ * Simon Willkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -97,16 +98,22 @@ NS_IMETHODIMP nsAbLDAPProcessReplication
return rv;
}
rv = mDirectory->GetAuthDn(mLogin);
if (NS_FAILED(rv)) {
mQuery = nsnull;
return rv;
}
+
+ rv = mDirectory->GetSaslMechanism(mSaslMechanism);
+ if (NS_FAILED(rv)) {
+ mQuery = nsnull;
+ return rv;
+ }
mInitialized = PR_TRUE;
return rv;
}
NS_IMETHODIMP nsAbLDAPProcessReplicationData::GetReplicationState(PRInt32 *aReplicationState)
{
--- a/mailnews/addrbook/src/nsLDAPAutoCompleteSession.cpp
+++ b/mailnews/addrbook/src/nsLDAPAutoCompleteSession.cpp
@@ -18,16 +18,17 @@
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dan Mosedale <dmose@netscape.com> (Original Author)
* Leif Hedstrom <leif@netscape.com>
+ * Simon Wilkinson <simon@sxw.org.uk>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -1242,16 +1243,31 @@ nsLDAPAutoCompleteSession::SetLogin(cons
}
NS_IMETHODIMP
nsLDAPAutoCompleteSession::GetLogin(nsACString & aLogin)
{
aLogin = mLogin;
return NS_OK;
}
+// attribute ACString saslMechanism
+
+NS_IMETHODIMP
+nsLDAPAutoCompleteSession::SetSaslMechanism(const nsACString & aSaslMechanism)
+{
+ mSaslMechanism.Assign(aSaslMechanism);
+ return NS_OK;
+}
+NS_IMETHODIMP
+nsLDAPAutoCompleteSession::GetSaslMechanism(nsACString & aSaslMechanism)
+{
+ aSaslMechanism.Assign(mSaslMechanism);
+ return NS_OK;
+}
+
// attribute unsigned long version;
NS_IMETHODIMP
nsLDAPAutoCompleteSession::GetVersion(PRUint32 *aVersion)
{
if (!aVersion) {
return NS_ERROR_NULL_POINTER;
}
--- a/mailnews/compose/resources/content/MsgComposeCommands.js
+++ b/mailnews/compose/resources/content/MsgComposeCommands.js
@@ -844,16 +844,24 @@ function setupLdapAutocompleteSession()
//
try {
LDAPSession.login = sPrefs.getComplexValue(
autocompleteDirectory + ".auth.dn",
Components.interfaces.nsISupportsString).data;
} catch (ex) {
// if we don't have this pref, no big deal
}
+
+ try {
+ LDAPSession.saslMechanism = sPrefs.getComplexValue(
+ autocompleteDirectory + ".auth.saslmech",
+ Components.interfaces.nsISupportsString).data;
+ } catch (ex) {
+ // don't care if we don't have this pref
+ }
// set the LDAP protocol version correctly
var protocolVersion;
try {
protocolVersion = sPrefs.getCharPref(autocompleteDirectory +
".protocolVersion");
} catch (ex) {
// if we don't have this pref, no big deal
--- a/suite/locales/en-US/chrome/mailnews/pref/pref-directory-add.dtd
+++ b/suite/locales/en-US/chrome/mailnews/pref/pref-directory-add.dtd
@@ -60,13 +60,20 @@
<!ENTITY scopeOneLevel.label "One Level">
<!ENTITY scopeOneLevel.accesskey "L">
<!ENTITY scopeSubtree.label "Subtree">
<!ENTITY scopeSubtree.accesskey "S">
<!ENTITY return.label "Don't return more than">
<!ENTITY return.accesskey "r">
<!ENTITY results.label "results">
<!ENTITY offlineText.label "You can download a local copy of this directory so that it is available for use when you are working offline.">
+<!ENTITY saslMechanism.label "Login method: ">
+<!ENTITY saslMechanism.accesskey "m">
+<!ENTITY saslOff.label "Simple">
+<!ENTITY saslOff.accesskey "l">
+<!ENTITY saslGSSAPI.label "Kerberos (GSSAPI)">
+<!ENTITY saslGSSAPI.accesskey "K">
+
<!-- Localization note: this is here because the width of the dialog
is determined by the width of the base DN box; and that is likely
to vary somewhat with the language.
-->
<!ENTITY newDirectoryWidth "36em">