зеркало из https://github.com/mozilla/pjs.git
fixes bug 224653 "provide cross-platform NTLM auth implementation" r=kaie sr=bryner
This commit is contained in:
Родитель
a579ee29b7
Коммит
5fb0075b24
|
@ -88,6 +88,7 @@ XPIDLSRCS = \
|
|||
nsIByteRangeRequest.idl \
|
||||
nsIMultiPartChannel.idl \
|
||||
nsIExternalProtocolHandler.idl \
|
||||
nsIAuthModule.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/* vim:set ts=4 sw=4 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla 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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is IBM Corporation.
|
||||
* Portions created by IBM Corporation are Copyright (C) 2003
|
||||
* IBM Corporation. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* 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
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* 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"
|
||||
|
||||
[uuid(991eff7c-a8ba-441a-b71b-753bd8e6d6be)]
|
||||
interface nsIAuthModule : nsISupports
|
||||
{
|
||||
/**
|
||||
* Called to initialize an auth module. The other methods cannot be called
|
||||
* unless this method succeeds.
|
||||
*
|
||||
* @param aDomain
|
||||
* the authentication domain, which may be null if not applicable.
|
||||
* @param aUsername
|
||||
* the user's login name
|
||||
* @param aPassword
|
||||
* the user's password
|
||||
*/
|
||||
void init(in wstring aDomain,
|
||||
in wstring aUsername,
|
||||
in wstring aPassword);
|
||||
|
||||
/**
|
||||
* Called to get the next token in a sequence of authentication steps.
|
||||
*
|
||||
* @param aInToken
|
||||
* A buffer containing the input token (e.g., a challenge from a
|
||||
* server). This may be null.
|
||||
* @param aInTokenLength
|
||||
* The length of the input token.
|
||||
* @param aOutToken
|
||||
* If getNextToken succeeds, then aOutToken will point to a buffer
|
||||
* to be sent in response to the server challenge. The length of
|
||||
* this buffer is given by aOutTokenLength. The buffer at aOutToken
|
||||
* must be recycled with a call to nsMemory::Free.
|
||||
* @param aOutTokenLength
|
||||
* If getNextToken succeeds, then aOutTokenLength contains the
|
||||
* length of the buffer (number of bytes) pointed to by aOutToken.
|
||||
*/
|
||||
void getNextToken([const] in voidPtr aInToken,
|
||||
in unsigned long aInTokenLength,
|
||||
out voidPtr aOutToken,
|
||||
out unsigned long aOutTokenLength);
|
||||
};
|
||||
|
||||
%{C++
|
||||
/**
|
||||
* nsIAuthModule implementations are registered under the following contract
|
||||
* ID prefix:
|
||||
*/
|
||||
#define NS_AUTH_MODULE_CONTRACTID_PREFIX \
|
||||
"@mozilla.org/network/auth-module;1?name="
|
||||
%}
|
|
@ -181,10 +181,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsFtpProtocolHandler, Init)
|
|||
#include "nsHttpAuthManager.h"
|
||||
#include "nsHttpBasicAuth.h"
|
||||
#include "nsHttpDigestAuth.h"
|
||||
#ifdef XP_WIN
|
||||
#include "nsHttpNTLMAuth.h"
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsHttpNTLMAuth, Init)
|
||||
#endif
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpNTLMAuth)
|
||||
#undef LOG
|
||||
#undef LOG_ENABLED
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsHttpHandler, Init)
|
||||
|
@ -888,12 +886,10 @@ static const nsModuleComponentInfo gNetModuleInfo[] = {
|
|||
NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "digest",
|
||||
nsHttpDigestAuthConstructor },
|
||||
|
||||
#ifdef XP_WIN
|
||||
{ "HTTP NTLM Auth Encoder",
|
||||
NS_HTTPNTLMAUTH_CID,
|
||||
NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "ntlm",
|
||||
nsHttpNTLMAuthConstructor },
|
||||
#endif
|
||||
|
||||
{ NS_HTTPAUTHMANAGER_CLASSNAME,
|
||||
NS_HTTPAUTHMANAGER_CID,
|
||||
|
|
|
@ -53,18 +53,13 @@ CPPSRCS = \
|
|||
nsHttpAuthManager.cpp \
|
||||
nsHttpBasicAuth.cpp \
|
||||
nsHttpDigestAuth.cpp \
|
||||
nsHttpNTLMAuth.cpp \
|
||||
nsHttpTransaction.cpp \
|
||||
nsHttpHandler.cpp \
|
||||
nsHttpChannel.cpp \
|
||||
nsHttpPipeline.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
CPPSRCS += \
|
||||
nsHttpNTLMAuth.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
LOCAL_INCLUDES=-I$(srcdir)/../../../base/src
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@netscape.com>
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* 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
|
||||
|
@ -35,197 +35,16 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SECURITY_WIN32 1
|
||||
#include <security.h>
|
||||
#include <rpc.h>
|
||||
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpNTLMAuth.h"
|
||||
#include "plbase64.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsString.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
|
||||
static HINSTANCE gLib = NULL;
|
||||
static PSecurityFunctionTable gFT = NULL;
|
||||
static ULONG gMaxTokenLen = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define CASE_(_x) case _x: return # _x;
|
||||
static const char *MapErrorCode(int rc)
|
||||
{
|
||||
switch (rc) {
|
||||
CASE_(SEC_E_OK)
|
||||
CASE_(SEC_I_CONTINUE_NEEDED)
|
||||
CASE_(SEC_I_COMPLETE_NEEDED)
|
||||
CASE_(SEC_I_COMPLETE_AND_CONTINUE)
|
||||
CASE_(SEC_E_INCOMPLETE_MESSAGE)
|
||||
CASE_(SEC_I_INCOMPLETE_CREDENTIALS)
|
||||
CASE_(SEC_E_INVALID_HANDLE)
|
||||
CASE_(SEC_E_TARGET_UNKNOWN)
|
||||
CASE_(SEC_E_LOGON_DENIED)
|
||||
CASE_(SEC_E_INTERNAL_ERROR)
|
||||
CASE_(SEC_E_NO_CREDENTIALS)
|
||||
CASE_(SEC_E_NO_AUTHENTICATING_AUTHORITY)
|
||||
CASE_(SEC_E_INSUFFICIENT_MEMORY)
|
||||
CASE_(SEC_E_INVALID_TOKEN)
|
||||
}
|
||||
return "<unknown>";
|
||||
}
|
||||
#else
|
||||
#define MapErrorCode(_rc) ""
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "nsICryptoFIPSInfo.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIAuthModule.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
// test for FIPS mode. if set, then NTLM cannot be supported. if PSM is not
|
||||
// present, assume FIPS mode to be consistent with DIGEST auth. i.e., if user
|
||||
// did not install PSM, then we should assume that the user doesn't want any
|
||||
// crypto activity.
|
||||
static PRBool
|
||||
IsNTLMDisabled()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsICryptoFIPSInfo> fipsInfo =
|
||||
do_GetService(NS_CRYPTO_FIPSINFO_SERVICE_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) return PR_TRUE;
|
||||
|
||||
PRBool result;
|
||||
rv = fipsInfo->GetIsFIPSModeActive(&result);
|
||||
if (NS_FAILED(rv)) return PR_TRUE;
|
||||
|
||||
return result;
|
||||
}
|
||||
#include "plbase64.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static PRBool
|
||||
IsWin9x()
|
||||
{
|
||||
static PRInt32 result = -1;
|
||||
if (result == -1) {
|
||||
OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
|
||||
if (GetVersionEx(&info)) {
|
||||
result = (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
|
||||
info.dwMajorVersion == 4);
|
||||
}
|
||||
else {
|
||||
NS_WARNING("GetVersionEx failed");
|
||||
result = PR_FALSE;
|
||||
}
|
||||
}
|
||||
return (PRBool) result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// IE6 will automatically send out the user's default identity when challenged.
|
||||
// this is rather risky given NTLM's use of the MD4 hash and the fact that any
|
||||
// webserver can issue a NTLM challenge. this macro defines whether or not
|
||||
// mozilla will automatically send out the user's default identity.
|
||||
#define TRY_DEFAULT_LOGON_AUTOMATICALLY PR_FALSE
|
||||
|
||||
class nsNTLMSessionState : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsNTLMSessionState()
|
||||
: mDefaultLogonFailed(!TRY_DEFAULT_LOGON_AUTOMATICALLY)
|
||||
{}
|
||||
virtual ~nsNTLMSessionState() {}
|
||||
|
||||
PRBool mDefaultLogonFailed;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(nsNTLMSessionState)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsNTLMContinuationState : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
virtual ~nsNTLMContinuationState()
|
||||
{
|
||||
(gFT->DeleteSecurityContext)(&mCtx);
|
||||
#ifdef __MINGW32__
|
||||
(gFT->FreeCredentialsHandle)(&mCred);
|
||||
#else
|
||||
(gFT->FreeCredentialHandle)(&mCred);
|
||||
#endif
|
||||
}
|
||||
|
||||
CredHandle mCred;
|
||||
CtxtHandle mCtx;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(nsNTLMContinuationState)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsHttpNTLMAuth::nsHttpNTLMAuth()
|
||||
{
|
||||
}
|
||||
|
||||
nsHttpNTLMAuth::~nsHttpNTLMAuth()
|
||||
{
|
||||
if (gLib) {
|
||||
FreeLibrary(gLib);
|
||||
gLib = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpNTLMAuth::Init()
|
||||
{
|
||||
if (IsNTLMDisabled())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PSecurityFunctionTable (*initFun)(void);
|
||||
|
||||
// Win9x provides SECUR32.DLL, but WinNT4.0 (and likely older versions)
|
||||
// only provide SECURITY.DLL. Newer versions of Windows provide both.
|
||||
gLib = LoadLibrary("secur32.dll");
|
||||
if (!gLib) {
|
||||
gLib = LoadLibrary("security.dll");
|
||||
if (!gLib) {
|
||||
NS_ERROR("failed to load secur32.dll");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
initFun = (PSecurityFunctionTable (*)(void)) GetProcAddress(gLib, "InitSecurityInterfaceA");
|
||||
if (!initFun) {
|
||||
NS_ERROR("failed to locate DLL entry point");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
gFT = initFun();
|
||||
if (!gFT) {
|
||||
NS_ERROR("no function table");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
PSecPkgInfo pkgInfo;
|
||||
int rc = (gFT->QuerySecurityPackageInfo)("NTLM", &pkgInfo);
|
||||
if (rc != SEC_E_OK) {
|
||||
NS_ERROR("NTLM security package not found");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
gMaxTokenLen = pkgInfo->cbMaxToken;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsHttpNTLMAuth, nsIHttpAuthenticator)
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -238,24 +57,25 @@ nsHttpNTLMAuth::ChallengeReceived(nsIHttpChannel *channel,
|
|||
{
|
||||
LOG(("nsHttpNTLMAuth::ChallengeReceived\n"));
|
||||
|
||||
// NOTE: we don't define any session state
|
||||
|
||||
*identityInvalid = PR_FALSE;
|
||||
// only request new identity if challenge is exactly "NTLM" and if we
|
||||
// have determined that the default logon is not accepted.
|
||||
// only request new identity if challenge is exactly "NTLM"
|
||||
if (PL_strcasecmp(challenge, "NTLM") == 0) {
|
||||
nsNTLMSessionState *session = (nsNTLMSessionState *) *sessionState;
|
||||
if (session) {
|
||||
// existance of continuation state implies default logon was
|
||||
// attempted and must have failed.
|
||||
if (*continuationState)
|
||||
session->mDefaultLogonFailed = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
session = new nsNTLMSessionState();
|
||||
if (!session)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*sessionState = session);
|
||||
}
|
||||
*identityInvalid = session->mDefaultLogonFailed;
|
||||
nsCOMPtr<nsIAuthModule> module =
|
||||
do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "ntlm");
|
||||
// if this fails, then it means that we cannot do NTLM auth.
|
||||
if (!module)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// non-null continuation state implies that we failed to authenticate.
|
||||
// blow away the old authentication state, and use the new one.
|
||||
NS_IF_RELEASE(*continuationState);
|
||||
|
||||
NS_ADDREF(*continuationState = module);
|
||||
|
||||
// prompt user for domain, username, and password...
|
||||
*identityInvalid = PR_TRUE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -274,103 +94,25 @@ nsHttpNTLMAuth::GenerateCredentials(nsIHttpChannel *httpChannel,
|
|||
{
|
||||
LOG(("nsHttpNTLMAuth::GenerateCredentials\n"));
|
||||
|
||||
// NOTE: the FIPS setting can change dynamically, so we need to check it
|
||||
// here as well. this isn't a very costly check, and moreover we aren't
|
||||
// going to execute this code that frequently since NTLM performs the
|
||||
// handshake once per connection.
|
||||
if (IsNTLMDisabled())
|
||||
return NS_ERROR_FAILURE;
|
||||
*creds = nsnull;
|
||||
|
||||
NS_ENSURE_TRUE(gFT, NS_ERROR_NOT_INITIALIZED);
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIAuthModule> module = do_QueryInterface(*continuationState, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*creds = NULL;
|
||||
|
||||
nsNTLMSessionState *session = (nsNTLMSessionState *) *sessionState;
|
||||
NS_ASSERTION(session, "ChallengeReceived not called");
|
||||
|
||||
nsNTLMContinuationState *state = (nsNTLMContinuationState *) *continuationState;
|
||||
CtxtHandle *ctxIn;
|
||||
SecBufferDesc obd, ibd;
|
||||
SecBuffer ob, ib;
|
||||
PRBool ibSet;
|
||||
int rc;
|
||||
void *inBuf, *outBuf;
|
||||
PRUint32 inBufLen, outBufLen;
|
||||
|
||||
// initial challenge
|
||||
if (PL_strcasecmp(challenge, "NTLM") == 0) {
|
||||
SEC_WINNT_AUTH_IDENTITY_W identW;
|
||||
SEC_WINNT_AUTH_IDENTITY_A identA;
|
||||
nsCString domainBuf, userBuf, passBuf;
|
||||
void *pIdent = NULL;
|
||||
TimeStamp useBefore;
|
||||
PRUnichar *buf = nsnull;
|
||||
// initialize auth module
|
||||
rv = module->Init(domain, user, pass);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (user && pass && domain) {
|
||||
//
|
||||
// The version of SECUR32.DLL that ships with many versions of Win9x will
|
||||
// crash and burn if given a unicode user identity. See bug 212336.
|
||||
//
|
||||
if (IsWin9x()) {
|
||||
NS_CopyUnicodeToNative(nsDependentString(user), userBuf);
|
||||
NS_CopyUnicodeToNative(nsDependentString(domain), domainBuf);
|
||||
NS_CopyUnicodeToNative(nsDependentString(pass), passBuf);
|
||||
identA.User = (unsigned char *) userBuf.get();
|
||||
identA.UserLength = userBuf.Length();
|
||||
identA.Domain = (unsigned char *) domainBuf.get();
|
||||
identA.DomainLength = domainBuf.Length();
|
||||
identA.Password = (unsigned char *) passBuf.get();
|
||||
identA.PasswordLength = passBuf.Length();
|
||||
identA.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
|
||||
pIdent = &identA;
|
||||
}
|
||||
else {
|
||||
identW.User = (unsigned short *) user;
|
||||
identW.UserLength = nsCRT::strlen(user);
|
||||
identW.Domain = (unsigned short *) domain;
|
||||
identW.DomainLength = nsCRT::strlen(domain);
|
||||
identW.Password = (unsigned short *) pass;
|
||||
identW.PasswordLength = nsCRT::strlen(pass);
|
||||
identW.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
||||
pIdent = &identW;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_darinf
|
||||
LOG((" using supplied logon [domain=%s user=%s pass=%s]\n",
|
||||
NS_LossyConvertUCS2toASCII(domain).get(),
|
||||
NS_LossyConvertUCS2toASCII(user).get(),
|
||||
NS_LossyConvertUCS2toASCII(pass).get()));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
LOG((" using default windows logon\n"));
|
||||
|
||||
// clear out any old state (in case user identity was wrong)
|
||||
if (state) {
|
||||
NS_RELEASE(state);
|
||||
*continuationState = nsnull;
|
||||
if (session)
|
||||
session->mDefaultLogonFailed = PR_TRUE;
|
||||
}
|
||||
state = new nsNTLMContinuationState(); // no addref yet
|
||||
|
||||
rc = (gFT->AcquireCredentialsHandle)(NULL, // pszPrincipal
|
||||
"NTLM", // pszPackage
|
||||
SECPKG_CRED_OUTBOUND, // fCredentialUse
|
||||
NULL, // pvLogonID
|
||||
pIdent, // pAuthData
|
||||
NULL, // pGetKeyFn
|
||||
NULL, // pvGetKeyArgument
|
||||
&state->mCred, // phCredential
|
||||
&useBefore); // ptsExpiry
|
||||
LOG((" AcquireCredentialsHandle returned [rc=%d]\n", rc));
|
||||
|
||||
CRTFREEIF(buf);
|
||||
|
||||
ctxIn = NULL;
|
||||
ibSet = PR_FALSE;
|
||||
inBuf = nsnull;
|
||||
}
|
||||
else {
|
||||
NS_ENSURE_TRUE(state, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// decode challenge; skip past "NTLM " to the start of the base64
|
||||
// encoded data.
|
||||
int len = strlen(challenge);
|
||||
|
@ -380,80 +122,37 @@ nsHttpNTLMAuth::GenerateCredentials(nsIHttpChannel *httpChannel,
|
|||
len -= 5;
|
||||
|
||||
// decode into the input secbuffer
|
||||
ib.BufferType = SECBUFFER_TOKEN;
|
||||
ib.cbBuffer = (len * 3)/4; // sufficient size (see plbase64.h)
|
||||
ib.pvBuffer = malloc(ib.cbBuffer);
|
||||
if (!ib.pvBuffer)
|
||||
inBufLen = (len * 3)/4; // sufficient size (see plbase64.h)
|
||||
inBuf = nsMemory::Alloc(inBufLen);
|
||||
if (!inBuf)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (PL_Base64Decode(challenge, len, (char *) ib.pvBuffer) == NULL) {
|
||||
free(ib.pvBuffer);
|
||||
if (PL_Base64Decode(challenge, len, (char *) inBuf) == nsnull) {
|
||||
nsMemory::Free(inBuf);
|
||||
return NS_ERROR_UNEXPECTED; // improper base64 encoding
|
||||
}
|
||||
ctxIn = &state->mCtx;
|
||||
ibSet = PR_TRUE;
|
||||
}
|
||||
|
||||
DWORD ctxReq = ISC_REQ_REPLAY_DETECT |
|
||||
ISC_REQ_SEQUENCE_DETECT |
|
||||
ISC_REQ_CONFIDENTIALITY |
|
||||
ISC_REQ_DELEGATE;
|
||||
DWORD ctxAttr;
|
||||
|
||||
if (ibSet) {
|
||||
ibd.ulVersion = SECBUFFER_VERSION;
|
||||
ibd.cBuffers = 1;
|
||||
ibd.pBuffers = &ib;
|
||||
}
|
||||
|
||||
obd.ulVersion = SECBUFFER_VERSION;
|
||||
obd.cBuffers = 1;
|
||||
obd.pBuffers = &ob; // just one buffer
|
||||
ob.BufferType = SECBUFFER_TOKEN; // preping a token here
|
||||
ob.cbBuffer = gMaxTokenLen;
|
||||
ob.pvBuffer = calloc(ob.cbBuffer, 1);
|
||||
|
||||
rc = (gFT->InitializeSecurityContext)(&state->mCred, // phCredential
|
||||
ctxIn, // phContext
|
||||
NULL, // pszTargetName
|
||||
ctxReq, // fContextReq
|
||||
0, // Reserved1
|
||||
SECURITY_NATIVE_DREP, // TargetDataRep
|
||||
ibSet ? &ibd : NULL, // pInput
|
||||
0, // Reserved2
|
||||
&state->mCtx, // phNewContext
|
||||
&obd, // pOutput
|
||||
&ctxAttr, // pfContextAttr
|
||||
NULL); // ptsExpiry
|
||||
LOG((" InitializeSecurityContext returned [rc=%d:%s]\n", rc, MapErrorCode(rc)));
|
||||
|
||||
if (rc == SEC_I_CONTINUE_NEEDED || rc == SEC_E_OK) {
|
||||
rv = module->GetNextToken(inBuf, inBufLen, &outBuf, &outBufLen);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// base64 encode data in output buffer and prepend "NTLM "
|
||||
int credsLen = 5 + ((ob.cbBuffer + 2)/3)*4;
|
||||
*creds = (char *) malloc(credsLen + 1);
|
||||
if (*creds) {
|
||||
int credsLen = 5 + ((outBufLen + 2)/3)*4;
|
||||
*creds = (char *) nsMemory::Alloc(credsLen + 1);
|
||||
if (!*creds)
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
else {
|
||||
memcpy(*creds, "NTLM ", 5);
|
||||
PL_Base64Encode((char *) ob.pvBuffer, ob.cbBuffer, *creds + 5);
|
||||
PL_Base64Encode((char *) outBuf, outBufLen, *creds + 5);
|
||||
(*creds)[credsLen] = '\0'; // null terminate
|
||||
}
|
||||
// OK, we are done with |outBuf|
|
||||
nsMemory::Free(outBuf);
|
||||
}
|
||||
|
||||
if (ibSet)
|
||||
free(ib.pvBuffer);
|
||||
free(ob.pvBuffer);
|
||||
if (inBuf)
|
||||
nsMemory::Free(inBuf);
|
||||
|
||||
if (!*creds) {
|
||||
// destroy newly allocated state
|
||||
if (state && !*continuationState)
|
||||
delete state;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// save newly allocated state
|
||||
if (state && !*continuationState)
|
||||
NS_ADDREF(*continuationState = state);
|
||||
|
||||
return NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -46,10 +46,8 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHTTPAUTHENTICATOR
|
||||
|
||||
nsHttpNTLMAuth();
|
||||
virtual ~nsHttpNTLMAuth();
|
||||
|
||||
nsresult Init();
|
||||
nsHttpNTLMAuth() {}
|
||||
virtual ~nsHttpNTLMAuth() {}
|
||||
};
|
||||
|
||||
#endif // !nsHttpNTLMAuth_h__
|
||||
|
|
|
@ -55,7 +55,7 @@ CPPSRCS = \
|
|||
TestIOThreads.cpp \
|
||||
TestOpen.cpp \
|
||||
TestCookie.cpp \
|
||||
TestServ.cpp \
|
||||
ReadNTLM.cpp \
|
||||
$(NULL)
|
||||
|
||||
SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))
|
||||
|
|
|
@ -0,0 +1,358 @@
|
|||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla 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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is IBM Corporation.
|
||||
* Portions created by IBM Corporation are Copyright (C) 2003
|
||||
* IBM Corporation. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* 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
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "plbase64.h"
|
||||
#include "nsString.h"
|
||||
#include "nsString2.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "prmem.h"
|
||||
|
||||
/*
|
||||
* ReadNTLM : reads NTLM messages.
|
||||
*
|
||||
* based on http://davenport.sourceforge.net/ntlm.html
|
||||
*/
|
||||
|
||||
#define kNegotiateUnicode 0x00000001
|
||||
#define kNegotiateOEM 0x00000002
|
||||
#define kRequestTarget 0x00000004
|
||||
#define kUnknown1 0x00000008
|
||||
#define kNegotiateSign 0x00000010
|
||||
#define kNegotiateSeal 0x00000020
|
||||
#define kNegotiateDatagramStyle 0x00000040
|
||||
#define kNegotiateLanManagerKey 0x00000080
|
||||
#define kNegotiateNetware 0x00000100
|
||||
#define kNegotiateNTLMKey 0x00000200
|
||||
#define kUnknown2 0x00000400
|
||||
#define kUnknown3 0x00000800
|
||||
#define kNegotiateDomainSupplied 0x00001000
|
||||
#define kNegotiateWorkstationSupplied 0x00002000
|
||||
#define kNegotiateLocalCall 0x00004000
|
||||
#define kNegotiateAlwaysSign 0x00008000
|
||||
#define kTargetTypeDomain 0x00010000
|
||||
#define kTargetTypeServer 0x00020000
|
||||
#define kTargetTypeShare 0x00040000
|
||||
#define kNegotiateNTLM2Key 0x00080000
|
||||
#define kRequestInitResponse 0x00100000
|
||||
#define kRequestAcceptResponse 0x00200000
|
||||
#define kRequestNonNTSessionKey 0x00400000
|
||||
#define kNegotiateTargetInfo 0x00800000
|
||||
#define kUnknown4 0x01000000
|
||||
#define kUnknown5 0x02000000
|
||||
#define kUnknown6 0x04000000
|
||||
#define kUnknown7 0x08000000
|
||||
#define kUnknown8 0x10000000
|
||||
#define kNegotiate128 0x20000000
|
||||
#define kNegotiateKeyExchange 0x40000000
|
||||
#define kNegotiate56 0x80000000
|
||||
|
||||
static const char NTLM_SIGNATURE[] = "NTLMSSP";
|
||||
static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 };
|
||||
static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 };
|
||||
static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 };
|
||||
|
||||
#define NTLM_MARKER_LEN 4
|
||||
#define NTLM_TYPE1_HEADER_LEN 32
|
||||
#define NTLM_TYPE2_HEADER_LEN 32
|
||||
#define NTLM_TYPE3_HEADER_LEN 64
|
||||
|
||||
#define LM_HASH_LEN 16
|
||||
#define LM_RESP_LEN 24
|
||||
|
||||
#define NTLM_HASH_LEN 16
|
||||
#define NTLM_RESP_LEN 24
|
||||
|
||||
static void PrintFlags(PRUint32 flags)
|
||||
{
|
||||
#define TEST(_flag) \
|
||||
if (flags & k ## _flag) \
|
||||
printf(" 0x%08x (" # _flag ")\n", k ## _flag)
|
||||
|
||||
TEST(NegotiateUnicode);
|
||||
TEST(NegotiateOEM);
|
||||
TEST(RequestTarget);
|
||||
TEST(Unknown1);
|
||||
TEST(NegotiateSign);
|
||||
TEST(NegotiateSeal);
|
||||
TEST(NegotiateDatagramStyle);
|
||||
TEST(NegotiateLanManagerKey);
|
||||
TEST(NegotiateNetware);
|
||||
TEST(NegotiateNTLMKey);
|
||||
TEST(Unknown2);
|
||||
TEST(Unknown3);
|
||||
TEST(NegotiateDomainSupplied);
|
||||
TEST(NegotiateWorkstationSupplied);
|
||||
TEST(NegotiateLocalCall);
|
||||
TEST(NegotiateAlwaysSign);
|
||||
TEST(TargetTypeDomain);
|
||||
TEST(TargetTypeServer);
|
||||
TEST(TargetTypeShare);
|
||||
TEST(NegotiateNTLM2Key);
|
||||
TEST(RequestInitResponse);
|
||||
TEST(RequestAcceptResponse);
|
||||
TEST(RequestNonNTSessionKey);
|
||||
TEST(NegotiateTargetInfo);
|
||||
TEST(Unknown4);
|
||||
TEST(Unknown5);
|
||||
TEST(Unknown6);
|
||||
TEST(Unknown7);
|
||||
TEST(Unknown8);
|
||||
TEST(Negotiate128);
|
||||
TEST(NegotiateKeyExchange);
|
||||
TEST(Negotiate56);
|
||||
|
||||
#undef TEST
|
||||
}
|
||||
|
||||
static void
|
||||
PrintBuf(const char *tag, const PRUint8 *buf, PRUint32 bufLen)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("%s =\n", tag);
|
||||
while (bufLen > 0)
|
||||
{
|
||||
int count = bufLen;
|
||||
if (count > 8)
|
||||
count = 8;
|
||||
|
||||
printf(" ");
|
||||
for (i=0; i<count; ++i)
|
||||
{
|
||||
printf("0x%02x ", int(buf[i]));
|
||||
}
|
||||
for (; i<8; ++i)
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printf(" ");
|
||||
for (i=0; i<count; ++i)
|
||||
{
|
||||
if (isprint(buf[i]))
|
||||
printf("%c", buf[i]);
|
||||
else
|
||||
printf(".");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
bufLen -= count;
|
||||
buf += count;
|
||||
}
|
||||
}
|
||||
|
||||
static PRUint16
|
||||
ReadUint16(const PRUint8 *&buf)
|
||||
{
|
||||
PRUint16 x;
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
x = ((PRUint16) buf[1]) | ((PRUint16) buf[0] << 8);
|
||||
#else
|
||||
x = ((PRUint16) buf[0]) | ((PRUint16) buf[1] << 8);
|
||||
#endif
|
||||
buf += sizeof(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
static PRUint32
|
||||
ReadUint32(const PRUint8 *&buf)
|
||||
{
|
||||
PRUint32 x;
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
x = ( (PRUint32) buf[3]) |
|
||||
(((PRUint32) buf[2]) << 8) |
|
||||
(((PRUint32) buf[1]) << 16) |
|
||||
(((PRUint32) buf[0]) << 24);
|
||||
#else
|
||||
x = ( (PRUint32) buf[0]) |
|
||||
(((PRUint32) buf[1]) << 8) |
|
||||
(((PRUint32) buf[2]) << 16) |
|
||||
(((PRUint32) buf[3]) << 24);
|
||||
#endif
|
||||
buf += sizeof(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
PRUint16 length;
|
||||
PRUint16 capacity;
|
||||
PRUint32 offset;
|
||||
} SecBuf;
|
||||
|
||||
static void
|
||||
ReadSecBuf(SecBuf *s, const PRUint8 *&buf)
|
||||
{
|
||||
s->length = ReadUint16(buf);
|
||||
s->capacity = ReadUint16(buf);
|
||||
s->offset = ReadUint32(buf);
|
||||
}
|
||||
|
||||
static void
|
||||
ReadType1MsgBody(const PRUint8 *inBuf, PRUint32 start)
|
||||
{
|
||||
const PRUint8 *cursor = inBuf + start;
|
||||
PRUint32 flags;
|
||||
|
||||
PrintBuf("flags", cursor, 4);
|
||||
// read flags
|
||||
flags = ReadUint32(cursor);
|
||||
PrintFlags(flags);
|
||||
|
||||
// type 1 message may not include trailing security buffers
|
||||
if ((flags & kNegotiateDomainSupplied) |
|
||||
(flags & kNegotiateWorkstationSupplied))
|
||||
{
|
||||
SecBuf secbuf;
|
||||
ReadSecBuf(&secbuf, cursor);
|
||||
PrintBuf("supplied domain", inBuf + secbuf.offset, secbuf.length);
|
||||
|
||||
ReadSecBuf(&secbuf, cursor);
|
||||
PrintBuf("supplied workstation", inBuf + secbuf.offset, secbuf.length);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ReadType2MsgBody(const PRUint8 *inBuf, PRUint32 start)
|
||||
{
|
||||
PRUint16 targetLen, offset;
|
||||
PRUint32 flags;
|
||||
const PRUint8 *target;
|
||||
const PRUint8 *cursor = inBuf + start;
|
||||
|
||||
// read target name security buffer
|
||||
targetLen = ReadUint16(cursor);
|
||||
ReadUint16(cursor); // discard next 16-bit value
|
||||
offset = ReadUint32(cursor); // get offset from inBuf
|
||||
target = inBuf + offset;
|
||||
|
||||
PrintBuf("target", target, targetLen);
|
||||
|
||||
PrintBuf("flags", cursor, 4);
|
||||
// read flags
|
||||
flags = ReadUint32(cursor);
|
||||
PrintFlags(flags);
|
||||
|
||||
// read challenge
|
||||
PrintBuf("challenge", cursor, 8);
|
||||
cursor += 8;
|
||||
|
||||
PrintBuf("context", cursor, 8);
|
||||
cursor += 8;
|
||||
|
||||
SecBuf secbuf;
|
||||
ReadSecBuf(&secbuf, cursor);
|
||||
PrintBuf("target information", inBuf + secbuf.offset, secbuf.length);
|
||||
}
|
||||
|
||||
static void
|
||||
ReadType3MsgBody(const PRUint8 *inBuf, PRUint32 start)
|
||||
{
|
||||
const PRUint8 *cursor = inBuf + start;
|
||||
|
||||
SecBuf secbuf;
|
||||
|
||||
ReadSecBuf(&secbuf, cursor); // LM response
|
||||
PrintBuf("LM response", inBuf + secbuf.offset, secbuf.length);
|
||||
|
||||
ReadSecBuf(&secbuf, cursor); // NTLM response
|
||||
PrintBuf("NTLM response", inBuf + secbuf.offset, secbuf.length);
|
||||
|
||||
ReadSecBuf(&secbuf, cursor); // domain name
|
||||
PrintBuf("domain name", inBuf + secbuf.offset, secbuf.length);
|
||||
|
||||
ReadSecBuf(&secbuf, cursor); // user name
|
||||
PrintBuf("user name", inBuf + secbuf.offset, secbuf.length);
|
||||
|
||||
ReadSecBuf(&secbuf, cursor); // workstation name
|
||||
PrintBuf("workstation name", inBuf + secbuf.offset, secbuf.length);
|
||||
|
||||
ReadSecBuf(&secbuf, cursor); // session key
|
||||
PrintBuf("session key", inBuf + secbuf.offset, secbuf.length);
|
||||
|
||||
PRUint32 flags = ReadUint32(cursor);
|
||||
PrintBuf("flags", (const PRUint8 *) &flags, sizeof(flags));
|
||||
PrintFlags(flags);
|
||||
}
|
||||
|
||||
static void
|
||||
ReadMsg(const char *base64buf, PRUint32 bufLen)
|
||||
{
|
||||
PRUint8 *inBuf = (PRUint8 *) PL_Base64Decode(base64buf, bufLen, NULL);
|
||||
if (!inBuf)
|
||||
{
|
||||
printf("PL_Base64Decode failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const PRUint8 *cursor = inBuf;
|
||||
|
||||
PrintBuf("signature", cursor, 8);
|
||||
|
||||
// verify NTLMSSP signature
|
||||
if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
|
||||
{
|
||||
printf("### invalid or corrupt NTLM signature\n");
|
||||
}
|
||||
cursor += sizeof(NTLM_SIGNATURE);
|
||||
|
||||
PrintBuf("message type", cursor, 4);
|
||||
|
||||
if (memcmp(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
|
||||
ReadType1MsgBody(inBuf, 12);
|
||||
else if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
|
||||
ReadType2MsgBody(inBuf, 12);
|
||||
else if (memcmp(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
|
||||
ReadType3MsgBody(inBuf, 12);
|
||||
else
|
||||
printf("### invalid or unknown message type\n");
|
||||
|
||||
PR_Free(inBuf);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
printf("usage: ntlmread <msg>\n");
|
||||
return -1;
|
||||
}
|
||||
ReadMsg(argv[1], (PRUint32) strlen(argv[1]));
|
||||
return 0;
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -47,6 +48,9 @@
|
|||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifdef XP_UNIX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "nspr.h"
|
||||
#include "nscore.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -67,6 +71,9 @@
|
|||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIDNSService.h"
|
||||
#include "nsIAuthPrompt.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsXPIDLString.h"
|
||||
|
@ -92,6 +99,39 @@ static PRBool gAskUserForInput = PR_FALSE;
|
|||
static PRBool gResume = PR_FALSE;
|
||||
static PRUint32 gStartAt = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set proxy preferences for testing
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static nsresult
|
||||
SetHttpProxy(const char *proxy)
|
||||
{
|
||||
const char *colon = strchr(proxy, ':');
|
||||
if (!colon)
|
||||
{
|
||||
NS_WARNING("invalid proxy token; use host:port");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
int port = atoi(colon + 1);
|
||||
if (port == 0)
|
||||
{
|
||||
NS_WARNING("invalid proxy port; must be an integer");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
nsCAutoString proxyHost;
|
||||
proxyHost = Substring(proxy, colon);
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (prefs)
|
||||
{
|
||||
prefs->SetCharPref("network.proxy.http", proxyHost.get());
|
||||
prefs->SetIntPref("network.proxy.http_port", port);
|
||||
prefs->SetIntPref("network.proxy.type", 1); // manual proxy config
|
||||
}
|
||||
LOG(("connecting via proxy=%s:%d\n", proxyHost.get(), port));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HeaderVisitor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -182,6 +222,97 @@ TestHttpEventSink::OnRedirect(nsIHttpChannel *channel, nsIChannel *newChannel)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// TestAuthPrompt
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class TestAuthPrompt : public nsIAuthPrompt
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIAUTHPROMPT
|
||||
|
||||
TestAuthPrompt();
|
||||
virtual ~TestAuthPrompt();
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(TestAuthPrompt, nsIAuthPrompt)
|
||||
|
||||
TestAuthPrompt::TestAuthPrompt()
|
||||
{
|
||||
}
|
||||
|
||||
TestAuthPrompt::~TestAuthPrompt()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TestAuthPrompt::Prompt(const PRUnichar *dialogTitle,
|
||||
const PRUnichar *text,
|
||||
const PRUnichar *passwordRealm,
|
||||
PRUint32 savePassword,
|
||||
const PRUnichar *defaultText,
|
||||
PRUnichar **result,
|
||||
PRBool *_retval)
|
||||
{
|
||||
*_retval = PR_FALSE;
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TestAuthPrompt::PromptUsernameAndPassword(const PRUnichar *dialogTitle,
|
||||
const PRUnichar *dialogText,
|
||||
const PRUnichar *passwordRealm,
|
||||
PRUint32 savePassword,
|
||||
PRUnichar **user,
|
||||
PRUnichar **pwd,
|
||||
PRBool *_retval)
|
||||
{
|
||||
NS_ConvertUTF16toUTF8 text(passwordRealm);
|
||||
printf("* --------------------------------------------------------------------------- *\n");
|
||||
printf("* Authentication Required [%s]\n", text.get());
|
||||
printf("* --------------------------------------------------------------------------- *\n");
|
||||
|
||||
char buf[256];
|
||||
int n;
|
||||
|
||||
printf("Enter username: ");
|
||||
fgets(buf, sizeof(buf), stdin);
|
||||
n = strlen(buf);
|
||||
buf[n-1] = '\0'; // trim trailing newline
|
||||
*user = ToNewUnicode(nsDependentCString(buf));
|
||||
|
||||
const char *p;
|
||||
#ifdef XP_UNIX
|
||||
p = getpass("Enter password: ");
|
||||
#else
|
||||
printf("Enter password: ");
|
||||
fgets(buf, sizeof(buf), stdin);
|
||||
n = strlen(buf);
|
||||
buf[n-1] = '\0'; // trim trailing newline
|
||||
p = buf;
|
||||
#endif
|
||||
*pwd = ToNewUnicode(nsDependentCString(p));
|
||||
|
||||
// zap buf
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
*_retval = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TestAuthPrompt::PromptPassword(const PRUnichar *dialogTitle,
|
||||
const PRUnichar *text,
|
||||
const PRUnichar *passwordRealm,
|
||||
PRUint32 savePassword,
|
||||
PRUnichar **pwd,
|
||||
PRBool *_retval)
|
||||
{
|
||||
*_retval = PR_FALSE;
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// InputTestConsumer
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -413,19 +544,30 @@ public:
|
|||
NotificationCallbacks() {
|
||||
}
|
||||
|
||||
NS_IMETHOD GetInterface(const nsIID& eventSinkIID, void* *result) {
|
||||
NS_IMETHOD GetInterface(const nsIID& iid, void* *result) {
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
if (eventSinkIID.Equals(NS_GET_IID(nsIHttpEventSink))) {
|
||||
if (iid.Equals(NS_GET_IID(nsIHttpEventSink))) {
|
||||
TestHttpEventSink *sink;
|
||||
|
||||
sink = new TestHttpEventSink();
|
||||
if (sink == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(sink);
|
||||
rv = sink->QueryInterface(eventSinkIID, result);
|
||||
rv = sink->QueryInterface(iid, result);
|
||||
NS_RELEASE(sink);
|
||||
}
|
||||
|
||||
if (iid.Equals(NS_GET_IID(nsIAuthPrompt))) {
|
||||
TestAuthPrompt *prompt;
|
||||
|
||||
prompt = new TestAuthPrompt();
|
||||
if (prompt == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(prompt);
|
||||
rv = prompt->QueryInterface(iid, result);
|
||||
NS_RELEASE(prompt);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
@ -595,7 +737,7 @@ main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
gTestLog = PR_NewLogModule("Test");
|
||||
gTestLog = PR_NewLogModule("Test");
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -640,6 +782,11 @@ main(int argc, char* argv[])
|
|||
continue;
|
||||
}
|
||||
|
||||
if (PL_strcasecmp(argv[i], "-proxy") == 0) {
|
||||
SetHttpProxy(argv[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG(("\t%s\n", argv[i]));
|
||||
rv = StartLoadingURL(argv[i]);
|
||||
}
|
||||
|
|
|
@ -79,12 +79,15 @@ CPPSRCS = \
|
|||
nsUsageArrayHelper.cpp \
|
||||
nsCRLManager.cpp \
|
||||
nsNSSShutDown.cpp \
|
||||
nsNTLMAuthModule.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_XUL
|
||||
CPPSRCS += nsCertTree.cpp
|
||||
endif
|
||||
|
||||
CSRCS += md4.c
|
||||
|
||||
REQUIRES = nspr \
|
||||
xpcom \
|
||||
string \
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
/* vim:set ts=2 sw=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla 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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is IBM Corporation.
|
||||
* Portions created by IBM Corporation are Copyright (C) 2003
|
||||
* IBM Corporation. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* 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
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* 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 ***** */
|
||||
|
||||
/*
|
||||
* "clean room" MD4 implementation (see RFC 1320)
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "md4.h"
|
||||
|
||||
typedef PRUint32 Uint32;
|
||||
typedef PRUint8 Uint8;
|
||||
|
||||
/* the "conditional" function */
|
||||
#define F(x,y,z) (((x) & (y)) | (~(x) & (z)))
|
||||
|
||||
/* the "majority" function */
|
||||
#define G(x,y,z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
|
||||
|
||||
/* the "parity" function */
|
||||
#define H(x,y,z) ((x) ^ (y) ^ (z))
|
||||
|
||||
/* rotate n-bits to the left */
|
||||
#define ROTL(x,n) (((x) << (n)) | ((x) >> (0x20 - n)))
|
||||
|
||||
/* round 1: [abcd k s]: a = (a + F(b,c,d) + X[k]) <<< s */
|
||||
#define RD1(a,b,c,d,k,s) a += F(b,c,d) + X[k]; a = ROTL(a,s)
|
||||
|
||||
/* round 2: [abcd k s]: a = (a + G(b,c,d) + X[k] + MAGIC) <<< s */
|
||||
#define RD2(a,b,c,d,k,s) a += G(b,c,d) + X[k] + 0x5A827999; a = ROTL(a,s)
|
||||
|
||||
/* round 3: [abcd k s]: a = (a + H(b,c,d) + X[k] + MAGIC) <<< s */
|
||||
#define RD3(a,b,c,d,k,s) a += H(b,c,d) + X[k] + 0x6ED9EBA1; a = ROTL(a,s)
|
||||
|
||||
/* converts from word array to byte array, len is number of bytes */
|
||||
static void w2b(Uint8 *out, const Uint32 *in, Uint32 len)
|
||||
{
|
||||
Uint8 *bp; const Uint32 *wp, *wpend;
|
||||
|
||||
bp = out;
|
||||
wp = in;
|
||||
wpend = wp + (len >> 2);
|
||||
|
||||
for (; wp != wpend; ++wp, bp += 4)
|
||||
{
|
||||
bp[0] = (Uint8) ((*wp ) & 0xFF);
|
||||
bp[1] = (Uint8) ((*wp >> 8) & 0xFF);
|
||||
bp[2] = (Uint8) ((*wp >> 16) & 0xFF);
|
||||
bp[3] = (Uint8) ((*wp >> 24) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* converts from byte array to word array, len is number of bytes */
|
||||
static void b2w(Uint32 *out, const Uint8 *in, Uint32 len)
|
||||
{
|
||||
Uint32 *wp; const Uint8 *bp, *bpend;
|
||||
|
||||
wp = out;
|
||||
bp = in;
|
||||
bpend = in + len;
|
||||
|
||||
for (; bp != bpend; bp += 4, ++wp)
|
||||
{
|
||||
*wp = (Uint32) (bp[0] ) |
|
||||
(Uint32) (bp[1] << 8) |
|
||||
(Uint32) (bp[2] << 16) |
|
||||
(Uint32) (bp[3] << 24);
|
||||
}
|
||||
}
|
||||
|
||||
/* update state: data is 64 bytes in length */
|
||||
static void md4step(Uint32 state[4], const Uint8 *data)
|
||||
{
|
||||
Uint32 A, B, C, D, X[16];
|
||||
|
||||
b2w(X, data, 64);
|
||||
|
||||
A = state[0];
|
||||
B = state[1];
|
||||
C = state[2];
|
||||
D = state[3];
|
||||
|
||||
RD1(A,B,C,D, 0,3); RD1(D,A,B,C, 1,7); RD1(C,D,A,B, 2,11); RD1(B,C,D,A, 3,19);
|
||||
RD1(A,B,C,D, 4,3); RD1(D,A,B,C, 5,7); RD1(C,D,A,B, 6,11); RD1(B,C,D,A, 7,19);
|
||||
RD1(A,B,C,D, 8,3); RD1(D,A,B,C, 9,7); RD1(C,D,A,B,10,11); RD1(B,C,D,A,11,19);
|
||||
RD1(A,B,C,D,12,3); RD1(D,A,B,C,13,7); RD1(C,D,A,B,14,11); RD1(B,C,D,A,15,19);
|
||||
|
||||
RD2(A,B,C,D, 0,3); RD2(D,A,B,C, 4,5); RD2(C,D,A,B, 8, 9); RD2(B,C,D,A,12,13);
|
||||
RD2(A,B,C,D, 1,3); RD2(D,A,B,C, 5,5); RD2(C,D,A,B, 9, 9); RD2(B,C,D,A,13,13);
|
||||
RD2(A,B,C,D, 2,3); RD2(D,A,B,C, 6,5); RD2(C,D,A,B,10, 9); RD2(B,C,D,A,14,13);
|
||||
RD2(A,B,C,D, 3,3); RD2(D,A,B,C, 7,5); RD2(C,D,A,B,11, 9); RD2(B,C,D,A,15,13);
|
||||
|
||||
RD3(A,B,C,D, 0,3); RD3(D,A,B,C, 8,9); RD3(C,D,A,B, 4,11); RD3(B,C,D,A,12,15);
|
||||
RD3(A,B,C,D, 2,3); RD3(D,A,B,C,10,9); RD3(C,D,A,B, 6,11); RD3(B,C,D,A,14,15);
|
||||
RD3(A,B,C,D, 1,3); RD3(D,A,B,C, 9,9); RD3(C,D,A,B, 5,11); RD3(B,C,D,A,13,15);
|
||||
RD3(A,B,C,D, 3,3); RD3(D,A,B,C,11,9); RD3(C,D,A,B, 7,11); RD3(B,C,D,A,15,15);
|
||||
|
||||
state[0] += A;
|
||||
state[1] += B;
|
||||
state[2] += C;
|
||||
state[3] += D;
|
||||
}
|
||||
|
||||
void md4sum(const Uint8 *input, Uint32 inputLen, Uint8 *result)
|
||||
{
|
||||
Uint8 final[128];
|
||||
Uint32 i, n, m, state[4];
|
||||
|
||||
/* magic initial states */
|
||||
state[0] = 0x67452301;
|
||||
state[1] = 0xEFCDAB89;
|
||||
state[2] = 0x98BADCFE;
|
||||
state[3] = 0x10325476;
|
||||
|
||||
/* compute number of complete 64-byte segments contained in input */
|
||||
m = inputLen >> 6;
|
||||
|
||||
/* digest first m segments */
|
||||
for (i=0; i<m; ++i)
|
||||
md4step(state, (input + (i << 6)));
|
||||
|
||||
/* build final buffer */
|
||||
n = inputLen % 64;
|
||||
memcpy(final, input + (m << 6), n);
|
||||
final[n] = 0x80;
|
||||
memset(final + n + 1, 0, 120 - (n + 1));
|
||||
|
||||
inputLen = inputLen << 3;
|
||||
w2b(final + (n >= 56 ? 120 : 56), &inputLen, 4);
|
||||
|
||||
md4step(state, final);
|
||||
if (n >= 56)
|
||||
md4step(state, final + 64);
|
||||
|
||||
/* copy state to result */
|
||||
w2b(result, state, 16);
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* vim:set ts=2 sw=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla 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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is IBM Corporation.
|
||||
* Portions created by IBM Corporation are Copyright (C) 2003
|
||||
* IBM Corporation. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* 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
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef md4_h__
|
||||
#define md4_h__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "prtypes.h"
|
||||
|
||||
/**
|
||||
* md4sum - computes the MD4 sum over the input buffer per RFC 1320
|
||||
*
|
||||
* @param input
|
||||
* buffer containing input data
|
||||
* @param inputLen
|
||||
* length of input buffer (number of bytes)
|
||||
* @param result
|
||||
* 16-byte buffer that will contain the MD4 sum upon return
|
||||
*
|
||||
* NOTE: MD4 is superceded by MD5. do not use MD4 unless required by the
|
||||
* protocol you are implementing (e.g., NTLM requires MD4).
|
||||
*
|
||||
* NOTE: this interface is designed for relatively small buffers. A streaming
|
||||
* interface would make more sense if that were a requirement. Currently, this
|
||||
* is good enough for the applications we care about.
|
||||
*/
|
||||
void md4sum(const PRUint8 *input, PRUint32 inputLen, PRUint8 *result);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* md4_h__ */
|
|
@ -52,6 +52,7 @@
|
|||
#include "nsICategoryManager.h"
|
||||
#include "nsCRLManager.h"
|
||||
#include "nsCipherInfo.h"
|
||||
#include "nsNTLMAuthModule.h"
|
||||
|
||||
// We must ensure that the nsNSSComponent has been loaded before
|
||||
// creating any other components.
|
||||
|
@ -166,6 +167,7 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsHash)
|
|||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsCertPicker)
|
||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsCRLManager)
|
||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsCipherInfoService)
|
||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(PR_FALSE, nsNTLMAuthModule, InitTest)
|
||||
|
||||
static NS_METHOD RegisterPSMContentListeners(
|
||||
nsIComponentManager *aCompMgr,
|
||||
|
@ -379,6 +381,13 @@ static const nsModuleComponentInfo components[] =
|
|||
NS_PKCS11MODULEDB_CID,
|
||||
NS_CRYPTO_FIPSINFO_SERVICE_CONTRACTID,
|
||||
nsPKCS11ModuleDBConstructor
|
||||
},
|
||||
|
||||
{
|
||||
NS_NTLMAUTHMODULE_CLASSNAME,
|
||||
NS_NTLMAUTHMODULE_CID,
|
||||
NS_NTLMAUTHMODULE_CONTRACTID,
|
||||
nsNTLMAuthModuleConstructor
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,852 @@
|
|||
/* vim:set ts=2 sw=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla 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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is IBM Corporation.
|
||||
* Portions created by IBM Corporation are Copyright (C) 2003
|
||||
* IBM Corporation. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* 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
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* 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 <stdlib.h>
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "nsNTLMAuthModule.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "prsystem.h"
|
||||
#include "nss.h"
|
||||
#include "pk11func.h"
|
||||
#include "md4.h"
|
||||
|
||||
static void des_makekey(const PRUint8 *raw, PRUint8 *key);
|
||||
static void des_encrypt(const PRUint8 *key, const PRUint8 *src, PRUint8 *hash);
|
||||
static void md5sum(const PRUint8 *input, PRUint32 inputLen, PRUint8 *result);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// this file contains a cross-platform NTLM authentication implementation. it
|
||||
// is based on documentation from: http://davenport.sourceforge.net/ntlm.html
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define NTLM_NegotiateUnicode 0x00000001
|
||||
#define NTLM_NegotiateOEM 0x00000002
|
||||
#define NTLM_RequestTarget 0x00000004
|
||||
#define NTLM_Unknown1 0x00000008
|
||||
#define NTLM_NegotiateSign 0x00000010
|
||||
#define NTLM_NegotiateSeal 0x00000020
|
||||
#define NTLM_NegotiateDatagramStyle 0x00000040
|
||||
#define NTLM_NegotiateLanManagerKey 0x00000080
|
||||
#define NTLM_NegotiateNetware 0x00000100
|
||||
#define NTLM_NegotiateNTLMKey 0x00000200
|
||||
#define NTLM_Unknown2 0x00000400
|
||||
#define NTLM_Unknown3 0x00000800
|
||||
#define NTLM_NegotiateDomainSupplied 0x00001000
|
||||
#define NTLM_NegotiateWorkstationSupplied 0x00002000
|
||||
#define NTLM_NegotiateLocalCall 0x00004000
|
||||
#define NTLM_NegotiateAlwaysSign 0x00008000
|
||||
#define NTLM_TargetTypeDomain 0x00010000
|
||||
#define NTLM_TargetTypeServer 0x00020000
|
||||
#define NTLM_TargetTypeShare 0x00040000
|
||||
#define NTLM_NegotiateNTLM2Key 0x00080000
|
||||
#define NTLM_RequestInitResponse 0x00100000
|
||||
#define NTLM_RequestAcceptResponse 0x00200000
|
||||
#define NTLM_RequestNonNTSessionKey 0x00400000
|
||||
#define NTLM_NegotiateTargetInfo 0x00800000
|
||||
#define NTLM_Unknown4 0x01000000
|
||||
#define NTLM_Unknown5 0x02000000
|
||||
#define NTLM_Unknown6 0x04000000
|
||||
#define NTLM_Unknown7 0x08000000
|
||||
#define NTLM_Unknown8 0x10000000
|
||||
#define NTLM_Negotiate128 0x20000000
|
||||
#define NTLM_NegotiateKeyExchange 0x40000000
|
||||
#define NTLM_Negotiate56 0x80000000
|
||||
|
||||
// we send these flags with our type 1 message
|
||||
#define NTLM_TYPE1_FLAGS \
|
||||
(NTLM_NegotiateUnicode | \
|
||||
NTLM_NegotiateOEM | \
|
||||
NTLM_RequestTarget | \
|
||||
NTLM_NegotiateNTLMKey | \
|
||||
NTLM_NegotiateNTLM2Key)
|
||||
|
||||
static const char NTLM_SIGNATURE[] = "NTLMSSP";
|
||||
static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 };
|
||||
static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 };
|
||||
static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 };
|
||||
|
||||
#define NTLM_TYPE1_HEADER_LEN 32
|
||||
#define NTLM_TYPE2_HEADER_LEN 32
|
||||
#define NTLM_TYPE3_HEADER_LEN 64
|
||||
|
||||
#define LM_HASH_LEN 16
|
||||
#define LM_RESP_LEN 24
|
||||
|
||||
#define NTLM_HASH_LEN 16
|
||||
#define NTLM_RESP_LEN 24
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static void PrintFlags(PRUint32 flags)
|
||||
{
|
||||
#define TEST(_flag) \
|
||||
if (flags & NTLM_ ## _flag) \
|
||||
printf(" 0x%08x (" # _flag ")\n", NTLM_ ## _flag)
|
||||
|
||||
TEST(NegotiateUnicode);
|
||||
TEST(NegotiateOEM);
|
||||
TEST(RequestTarget);
|
||||
TEST(Unknown1);
|
||||
TEST(NegotiateSign);
|
||||
TEST(NegotiateSeal);
|
||||
TEST(NegotiateDatagramStyle);
|
||||
TEST(NegotiateLanManagerKey);
|
||||
TEST(NegotiateNetware);
|
||||
TEST(NegotiateNTLMKey);
|
||||
TEST(Unknown2);
|
||||
TEST(Unknown3);
|
||||
TEST(NegotiateDomainSupplied);
|
||||
TEST(NegotiateWorkstationSupplied);
|
||||
TEST(NegotiateLocalCall);
|
||||
TEST(NegotiateAlwaysSign);
|
||||
TEST(TargetTypeDomain);
|
||||
TEST(TargetTypeServer);
|
||||
TEST(TargetTypeShare);
|
||||
TEST(NegotiateNTLM2Key);
|
||||
TEST(RequestInitResponse);
|
||||
TEST(RequestAcceptResponse);
|
||||
TEST(RequestNonNTSessionKey);
|
||||
TEST(NegotiateTargetInfo);
|
||||
TEST(Unknown4);
|
||||
TEST(Unknown5);
|
||||
TEST(Unknown6);
|
||||
TEST(Unknown7);
|
||||
TEST(Unknown8);
|
||||
TEST(Negotiate128);
|
||||
TEST(NegotiateKeyExchange);
|
||||
TEST(Negotiate56);
|
||||
|
||||
#undef TEST
|
||||
}
|
||||
|
||||
static void
|
||||
PrintBuf(const char *tag, const PRUint8 *buf, PRUint32 bufLen)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("%s =\n", tag);
|
||||
while (bufLen > 0)
|
||||
{
|
||||
int count = bufLen;
|
||||
if (count > 8)
|
||||
count = 8;
|
||||
|
||||
printf(" ");
|
||||
for (i=0; i<count; ++i)
|
||||
{
|
||||
printf("0x%02x ", int(buf[i]));
|
||||
}
|
||||
for (; i<8; ++i)
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printf(" ");
|
||||
for (i=0; i<count; ++i)
|
||||
{
|
||||
if (isprint(buf[i]))
|
||||
printf("%c", buf[i]);
|
||||
else
|
||||
printf(".");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
bufLen -= count;
|
||||
buf += count;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// byte order swapping
|
||||
#define SWAP16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
|
||||
#define SWAP32(x) ((SWAP16((x) & 0xffff) << 16) | (SWAP16((x) >> 16)))
|
||||
|
||||
static void *
|
||||
WriteBytes(void *buf, const void *data, PRUint32 dataLen)
|
||||
{
|
||||
memcpy(buf, data, dataLen);
|
||||
return (PRUint8 *) buf + dataLen;
|
||||
}
|
||||
|
||||
static void *
|
||||
WriteDWORD(void *buf, PRUint32 dword)
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
// NTLM uses little endian on the wire
|
||||
dword = SWAP32(dword);
|
||||
#endif
|
||||
return WriteBytes(buf, &dword, sizeof(dword));
|
||||
}
|
||||
|
||||
static void *
|
||||
WriteSecBuf(void *buf, PRUint16 length, PRUint32 offset)
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
length = SWAP16(length);
|
||||
offset = SWAP32(offset);
|
||||
#endif
|
||||
buf = WriteBytes(buf, &length, sizeof(length));
|
||||
buf = WriteBytes(buf, &length, sizeof(length));
|
||||
buf = WriteBytes(buf, &offset, sizeof(offset));
|
||||
return buf;
|
||||
}
|
||||
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
/**
|
||||
* WriteUnicodeLE copies a unicode string from one buffer to another. The
|
||||
* resulting unicode string is in little-endian format. The input string is
|
||||
* assumed to be in the native endianness of the local machine. It is safe
|
||||
* to pass the same buffer as both input and output, which is a handy way to
|
||||
* convert the unicode buffer to little-endian on big-endian platforms.
|
||||
*/
|
||||
static void *
|
||||
WriteUnicodeLE(void *buf, const PRUnichar *str, PRUint32 strLen)
|
||||
{
|
||||
// convert input string from BE to LE
|
||||
PRUint8 *cursor = (PRUint8 *) buf,
|
||||
*input = (PRUint8 *) str;
|
||||
for (PRUint32 i=0; i<strLen; ++i, input+=2, cursor+=2)
|
||||
{
|
||||
// allow for the case where |buf == str|
|
||||
PRUint8 temp = input[0];
|
||||
cursor[0] = input[1];
|
||||
cursor[1] = temp;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
static PRUint16
|
||||
ReadUint16(const PRUint8 *&buf)
|
||||
{
|
||||
PRUint16 x = ((PRUint16) buf[0]) | ((PRUint16) buf[1] << 8);
|
||||
buf += sizeof(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
static PRUint32
|
||||
ReadUint32(const PRUint8 *&buf)
|
||||
{
|
||||
PRUint32 x = ( (PRUint32) buf[0]) |
|
||||
(((PRUint32) buf[1]) << 8) |
|
||||
(((PRUint32) buf[2]) << 16) |
|
||||
(((PRUint32) buf[3]) << 24);
|
||||
buf += sizeof(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
ZapBuf(void *buf, size_t bufLen)
|
||||
{
|
||||
memset(buf, 0, bufLen);
|
||||
}
|
||||
|
||||
static void
|
||||
ZapString(nsCString &s)
|
||||
{
|
||||
ZapBuf(NS_CONST_CAST(char *, s.get()), s.Length());
|
||||
}
|
||||
|
||||
static void
|
||||
ZapString(nsString &s)
|
||||
{
|
||||
ZapBuf(NS_CONST_CAST(PRUnichar *, s.get()), s.Length() * 2);
|
||||
}
|
||||
|
||||
static const unsigned char LM_MAGIC[] = "KGS!@#$%";
|
||||
|
||||
/**
|
||||
* LM_Hash computes the LM hash of the given password.
|
||||
*
|
||||
* @param password
|
||||
* null-terminated unicode password.
|
||||
* @param hash
|
||||
* 16-byte result buffer
|
||||
*/
|
||||
static void
|
||||
LM_Hash(const nsString &password, unsigned char *hash)
|
||||
{
|
||||
// convert password to OEM character set. we'll just use the native
|
||||
// filesystem charset.
|
||||
nsCAutoString passbuf;
|
||||
NS_CopyUnicodeToNative(password, passbuf);
|
||||
ToUpperCase(passbuf);
|
||||
PRUint32 n = passbuf.Length();
|
||||
passbuf.SetLength(14);
|
||||
for (PRUint32 i=n; i<14; ++i)
|
||||
passbuf.SetCharAt('\0', i);
|
||||
|
||||
unsigned char k1[8], k2[8];
|
||||
des_makekey((const unsigned char *) passbuf.get() , k1);
|
||||
des_makekey((const unsigned char *) passbuf.get() + 7, k2);
|
||||
ZapString(passbuf);
|
||||
|
||||
// use password keys to hash LM magic string twice.
|
||||
des_encrypt(k1, LM_MAGIC, hash);
|
||||
des_encrypt(k2, LM_MAGIC, hash + 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* NTLM_Hash computes the NTLM hash of the given password.
|
||||
*
|
||||
* @param password
|
||||
* null-terminated unicode password.
|
||||
* @param hash
|
||||
* 16-byte result buffer
|
||||
*/
|
||||
static void
|
||||
NTLM_Hash(const nsString &password, unsigned char *hash)
|
||||
{
|
||||
PRUint32 len = password.Length();
|
||||
PRUint8 *passbuf;
|
||||
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
passbuf = (PRUint8 *) malloc(len * 2);
|
||||
WriteUnicodeLE(passbuf, password.get(), len);
|
||||
#else
|
||||
passbuf = (PRUint8 *) password.get();
|
||||
#endif
|
||||
|
||||
md4sum(passbuf, len * 2, hash);
|
||||
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
ZapBuf(passbuf, len * 2);
|
||||
free(passbuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* LM_Response generates the LM response given a 16-byte password hash and the
|
||||
* challenge from the Type-2 message.
|
||||
*
|
||||
* @param hash
|
||||
* 16-byte password hash
|
||||
* @param challenge
|
||||
* 8-byte challenge from Type-2 message
|
||||
* @param response
|
||||
* 24-byte buffer to contain the LM response upon return
|
||||
*/
|
||||
static void
|
||||
LM_Response(const PRUint8 *hash, const PRUint8 *challenge, PRUint8 *response)
|
||||
{
|
||||
PRUint8 keybytes[21], k1[8], k2[8], k3[8];
|
||||
|
||||
memcpy(keybytes, hash, 16);
|
||||
ZapBuf(keybytes + 16, 5);
|
||||
|
||||
des_makekey(keybytes , k1);
|
||||
des_makekey(keybytes + 7, k2);
|
||||
des_makekey(keybytes + 14, k3);
|
||||
|
||||
des_encrypt(k1, challenge, response);
|
||||
des_encrypt(k2, challenge, response + 8);
|
||||
des_encrypt(k3, challenge, response + 16);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static nsresult
|
||||
GenerateType1Msg(void **outBuf, PRUint32 *outLen)
|
||||
{
|
||||
//
|
||||
// verify that bufLen is sufficient
|
||||
//
|
||||
*outLen = NTLM_TYPE1_HEADER_LEN;
|
||||
*outBuf = nsMemory::Alloc(*outLen);
|
||||
if (!*outBuf)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
//
|
||||
// write out type 1 msg
|
||||
//
|
||||
void *cursor = *outBuf;
|
||||
|
||||
// 0 : signature
|
||||
cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
|
||||
|
||||
// 8 : marker
|
||||
cursor = WriteBytes(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_TYPE1_MARKER));
|
||||
|
||||
// 12 : flags
|
||||
cursor = WriteDWORD(cursor, NTLM_TYPE1_FLAGS);
|
||||
|
||||
//
|
||||
// NOTE: it is common for the domain and workstation fields to be empty.
|
||||
// this is true of Win2k clients, and my guess is that there is
|
||||
// little utility to sending these strings before the charset has
|
||||
// been negotiated. we follow suite -- anyways, it doesn't hurt
|
||||
// to save some bytes on the wire ;-)
|
||||
//
|
||||
|
||||
// 16 : supplied domain security buffer (empty)
|
||||
cursor = WriteSecBuf(cursor, 0, NTLM_TYPE1_HEADER_LEN);
|
||||
|
||||
// 24 : supplied workstation security buffer (empty)
|
||||
cursor = WriteSecBuf(cursor, 0, NTLM_TYPE1_HEADER_LEN);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct Type2Msg
|
||||
{
|
||||
PRUint32 flags; // NTLM_Xxx bitwise combination
|
||||
PRUint8 challenge[8]; // 8 byte challenge
|
||||
const void *target; // target string (type depends on flags)
|
||||
PRUint32 targetLen; // target length in bytes
|
||||
};
|
||||
|
||||
static nsresult
|
||||
ParseType2Msg(const void *inBuf, PRUint32 inLen, Type2Msg *msg)
|
||||
{
|
||||
// make sure inBuf is long enough to contain a meaningful type2 msg.
|
||||
//
|
||||
// 0 NTLMSSP Signature
|
||||
// 8 NTLM Message Type
|
||||
// 12 Target Name
|
||||
// 20 Flags
|
||||
// 24 Challenge
|
||||
// 32 end of header, start of optional data blocks
|
||||
//
|
||||
if (inLen < NTLM_TYPE2_HEADER_LEN)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
const PRUint8 *cursor = (const PRUint8 *) inBuf;
|
||||
|
||||
// verify NTLMSSP signature
|
||||
if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
cursor += sizeof(NTLM_SIGNATURE);
|
||||
|
||||
// verify Type-2 marker
|
||||
if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_TYPE2_MARKER)) != 0)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
cursor += sizeof(NTLM_TYPE2_MARKER);
|
||||
|
||||
// read target name security buffer
|
||||
msg->targetLen = ReadUint16(cursor);
|
||||
ReadUint16(cursor); // discard next 16-bit value
|
||||
PRUint32 offset = ReadUint32(cursor); // get offset from inBuf
|
||||
msg->target = ((const PRUint8 *) inBuf) + offset;
|
||||
|
||||
// read flags
|
||||
msg->flags = ReadUint32(cursor);
|
||||
|
||||
// read challenge
|
||||
memcpy(msg->challenge, cursor, sizeof(msg->challenge));
|
||||
cursor += sizeof(msg->challenge);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("NTLM type 2 message:\n");
|
||||
PrintBuf("target", (const PRUint8 *) msg->target, msg->targetLen);
|
||||
PrintBuf("flags", (const PRUint8 *) &msg->flags, 4);
|
||||
PrintFlags(msg->flags);
|
||||
PrintBuf("challenge", msg->challenge, sizeof(msg->challenge));
|
||||
#endif
|
||||
|
||||
// we currently do not implement LMv2/NTLMv2 or NTLM2 responses,
|
||||
// so we can ignore target information. we may want to enable
|
||||
// support for these alternate mechanisms in the future.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
GenerateType3Msg(const nsString &domain,
|
||||
const nsString &username,
|
||||
const nsString &password,
|
||||
const void *inBuf,
|
||||
PRUint32 inLen,
|
||||
void **outBuf,
|
||||
PRUint32 *outLen)
|
||||
{
|
||||
// inBuf contains Type-2 msg (the challenge) from server
|
||||
|
||||
nsresult rv;
|
||||
Type2Msg msg;
|
||||
|
||||
rv = ParseType2Msg(inBuf, inLen, &msg);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
PRBool unicode = (msg.flags & NTLM_NegotiateUnicode);
|
||||
|
||||
// temporary buffers for unicode strings
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
nsAutoString ucsDomainBuf, ucsUserBuf;
|
||||
#endif
|
||||
nsAutoString ucsHostBuf;
|
||||
// temporary buffers for oem strings
|
||||
nsCAutoString oemDomainBuf, oemUserBuf, oemHostBuf;
|
||||
// pointers and lengths for the string buffers; encoding is unicode if
|
||||
// the "negotiate unicode" flag was set in the Type-2 message.
|
||||
const void *domainPtr, *userPtr, *hostPtr;
|
||||
PRUint32 domainLen, userLen, hostLen;
|
||||
|
||||
//
|
||||
// get domain name
|
||||
//
|
||||
if (unicode)
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
ucsDomainBuf = domain;
|
||||
domainPtr = ucsDomainBuf.get();
|
||||
domainLen = ucsDomainBuf.Length() * 2;
|
||||
WriteUnicodeLE((void *) domainPtr, domainPtr, domainLen);
|
||||
#else
|
||||
domainPtr = domain.get();
|
||||
domainLen = domain.Length() * 2;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_CopyUnicodeToNative(domain, oemDomainBuf);
|
||||
domainPtr = oemDomainBuf.get();
|
||||
domainLen = oemDomainBuf.Length();
|
||||
}
|
||||
|
||||
//
|
||||
// get user name
|
||||
//
|
||||
if (unicode)
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
ucsUserBuf = username;
|
||||
userPtr = ucsUserBuf.get();
|
||||
userLen = ucsUserBuf.Length() * 2;
|
||||
WriteUnicodeLE((void *) userPtr, userPtr, userLen);
|
||||
#else
|
||||
userPtr = username.get();
|
||||
userLen = username.Length() * 2;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_CopyUnicodeToNative(username, oemUserBuf);
|
||||
userPtr = oemUserBuf.get();
|
||||
userLen = oemUserBuf.Length();
|
||||
}
|
||||
|
||||
//
|
||||
// get workstation name (use local machine's hostname)
|
||||
//
|
||||
char hostBuf[SYS_INFO_BUFFER_LENGTH];
|
||||
if (PR_GetSystemInfo(PR_SI_HOSTNAME, hostBuf, sizeof(hostBuf)) == PR_FAILURE)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
hostLen = strlen(hostBuf);
|
||||
if (unicode)
|
||||
{
|
||||
// hostname is ASCII, so we can do a simple zero-pad expansion:
|
||||
CopyASCIItoUCS2(nsDependentCString(hostBuf, hostLen), ucsHostBuf);
|
||||
hostPtr = ucsHostBuf.get();
|
||||
hostLen = ucsHostBuf.Length() * 2;
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
WriteUnicodeLE((void *) hostPtr, hostPtr, hostLen);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
hostPtr = hostBuf;
|
||||
|
||||
//
|
||||
// now that we have generated all of the strings, we can allocate outBuf.
|
||||
//
|
||||
*outLen = NTLM_TYPE3_HEADER_LEN + hostLen + domainLen + userLen +
|
||||
LM_RESP_LEN + NTLM_RESP_LEN;
|
||||
*outBuf = nsMemory::Alloc(*outLen);
|
||||
if (!*outBuf)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
//
|
||||
// next, we compute the LM and NTLM responses.
|
||||
//
|
||||
PRUint8 lmResp[LM_RESP_LEN], ntlmResp[NTLM_RESP_LEN], ntlmHash[NTLM_HASH_LEN];
|
||||
if (msg.flags & NTLM_NegotiateNTLM2Key)
|
||||
{
|
||||
// compute NTLM2 session response
|
||||
PRUint8 sessionHash[16], temp[16];
|
||||
|
||||
PK11_GenerateRandom(lmResp, 8);
|
||||
memset(lmResp + 8, 0, LM_RESP_LEN - 8);
|
||||
|
||||
memcpy(temp, msg.challenge, 8);
|
||||
memcpy(temp + 8, lmResp, 8);
|
||||
md5sum(temp, 16, sessionHash);
|
||||
|
||||
NTLM_Hash(password, ntlmHash);
|
||||
LM_Response(ntlmHash, sessionHash, ntlmResp);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRUint8 lmHash[LM_HASH_LEN];
|
||||
|
||||
LM_Hash(password, lmHash);
|
||||
LM_Response(lmHash, msg.challenge, lmResp);
|
||||
|
||||
NTLM_Hash(password, ntlmHash);
|
||||
LM_Response(ntlmHash, msg.challenge, ntlmResp);
|
||||
}
|
||||
|
||||
//
|
||||
// finally, we assemble the Type-3 msg :-)
|
||||
//
|
||||
void *cursor = *outBuf;
|
||||
PRUint32 offset;
|
||||
|
||||
// 0 : signature
|
||||
cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
|
||||
|
||||
// 8 : marker
|
||||
cursor = WriteBytes(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_TYPE3_MARKER));
|
||||
|
||||
// 12 : LM response sec buf
|
||||
offset = NTLM_TYPE3_HEADER_LEN + domainLen + userLen + hostLen;
|
||||
cursor = WriteSecBuf(cursor, LM_RESP_LEN, offset);
|
||||
memcpy((PRUint8 *) *outBuf + offset, lmResp, LM_RESP_LEN);
|
||||
|
||||
// 20 : NTLM response sec buf
|
||||
offset += LM_RESP_LEN;
|
||||
cursor = WriteSecBuf(cursor, NTLM_RESP_LEN, offset);
|
||||
memcpy((PRUint8 *) *outBuf + offset, ntlmResp, NTLM_RESP_LEN);
|
||||
|
||||
// 28 : domain name sec buf
|
||||
offset = NTLM_TYPE3_HEADER_LEN;
|
||||
cursor = WriteSecBuf(cursor, domainLen, offset);
|
||||
memcpy((PRUint8 *) *outBuf + offset, domainPtr, domainLen);
|
||||
|
||||
// 36 : user name sec buf
|
||||
offset += domainLen;
|
||||
cursor = WriteSecBuf(cursor, userLen, offset);
|
||||
memcpy((PRUint8 *) *outBuf + offset, userPtr, userLen);
|
||||
|
||||
// 44 : workstation (host) name sec buf
|
||||
offset += userLen;
|
||||
cursor = WriteSecBuf(cursor, hostLen, offset);
|
||||
memcpy((PRUint8 *) *outBuf + offset, hostPtr, hostLen);
|
||||
|
||||
// 52 : session key sec buf (not used)
|
||||
offset += (hostLen + LM_RESP_LEN + NTLM_RESP_LEN);
|
||||
cursor = WriteSecBuf(cursor, 0, offset);
|
||||
|
||||
// 60 : negotiated flags
|
||||
cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsNTLMAuthModule, nsIAuthModule)
|
||||
|
||||
nsNTLMAuthModule::~nsNTLMAuthModule()
|
||||
{
|
||||
ZapString(mPassword);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNTLMAuthModule::InitTest()
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
//
|
||||
// disable NTLM authentication when FIPS mode is enabled.
|
||||
//
|
||||
return PK11_IsFIPS() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNTLMAuthModule::Init(const PRUnichar *domain,
|
||||
const PRUnichar *username,
|
||||
const PRUnichar *password)
|
||||
{
|
||||
mDomain = domain;
|
||||
mUsername = username;
|
||||
mPassword = password;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNTLMAuthModule::GetNextToken(const void *inToken,
|
||||
PRUint32 inTokenLen,
|
||||
void **outToken,
|
||||
PRUint32 *outTokenLen)
|
||||
{
|
||||
nsresult rv;
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
//
|
||||
// disable NTLM authentication when FIPS mode is enabled.
|
||||
//
|
||||
if (PK11_IsFIPS())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// if inToken is non-null, then assume it contains a type 2 message...
|
||||
if (inToken)
|
||||
rv = GenerateType3Msg(mDomain, mUsername, mPassword, inToken,
|
||||
inTokenLen, outToken, outTokenLen);
|
||||
else
|
||||
rv = GenerateType1Msg(outToken, outTokenLen);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// DES support code
|
||||
|
||||
// set odd parity bit (in least significant bit position)
|
||||
static PRUint8
|
||||
des_setkeyparity(PRUint8 x)
|
||||
{
|
||||
if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^
|
||||
(x >> 4) ^ (x >> 3) ^ (x >> 2) ^
|
||||
(x >> 1)) & 0x01) == 0)
|
||||
x |= 0x01;
|
||||
else
|
||||
x &= 0xfe;
|
||||
return x;
|
||||
}
|
||||
|
||||
// build 64-bit des key from 56-bit raw key
|
||||
static void
|
||||
des_makekey(const PRUint8 *raw, PRUint8 *key)
|
||||
{
|
||||
key[0] = des_setkeyparity(raw[0]);
|
||||
key[1] = des_setkeyparity((raw[0] << 7) | (raw[1] >> 1));
|
||||
key[2] = des_setkeyparity((raw[1] << 6) | (raw[2] >> 2));
|
||||
key[3] = des_setkeyparity((raw[2] << 5) | (raw[3] >> 3));
|
||||
key[4] = des_setkeyparity((raw[3] << 4) | (raw[4] >> 4));
|
||||
key[5] = des_setkeyparity((raw[4] << 3) | (raw[5] >> 5));
|
||||
key[6] = des_setkeyparity((raw[5] << 2) | (raw[6] >> 6));
|
||||
key[7] = des_setkeyparity((raw[6] << 1));
|
||||
}
|
||||
|
||||
// run des encryption algorithm (using NSS)
|
||||
static void
|
||||
des_encrypt(const PRUint8 *key, const PRUint8 *src, PRUint8 *hash)
|
||||
{
|
||||
CK_MECHANISM_TYPE cipherMech = CKM_DES_ECB;
|
||||
PK11SlotInfo *slot = nsnull;
|
||||
PK11SymKey *symkey = nsnull;
|
||||
PK11Context *ctxt = nsnull;
|
||||
SECItem keyItem, *param;
|
||||
SECStatus rv;
|
||||
unsigned int n;
|
||||
|
||||
slot = PK11_GetBestSlot(cipherMech, nsnull);
|
||||
if (!slot)
|
||||
{
|
||||
NS_ERROR("no slot");
|
||||
goto done;
|
||||
}
|
||||
|
||||
keyItem.data = (PRUint8 *) key;
|
||||
keyItem.len = 8;
|
||||
symkey = PK11_ImportSymKey(slot, cipherMech,
|
||||
PK11_OriginUnwrap, CKA_ENCRYPT,
|
||||
&keyItem, nsnull);
|
||||
if (!symkey)
|
||||
{
|
||||
NS_ERROR("no symkey");
|
||||
goto done;
|
||||
}
|
||||
|
||||
// no initialization vector required
|
||||
param = PK11_ParamFromIV(cipherMech, nsnull);
|
||||
if (!param)
|
||||
{
|
||||
NS_ERROR("no param");
|
||||
goto done;
|
||||
}
|
||||
|
||||
ctxt = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT,
|
||||
symkey, param);
|
||||
if (!ctxt)
|
||||
{
|
||||
NS_ERROR("no context");
|
||||
goto done;
|
||||
}
|
||||
|
||||
rv = PK11_CipherOp(ctxt, hash, (int *) &n, 8, (PRUint8 *) src, 8);
|
||||
if (rv != SECSuccess)
|
||||
{
|
||||
NS_ERROR("des failure");
|
||||
goto done;
|
||||
}
|
||||
|
||||
rv = PK11_DigestFinal(ctxt, hash+8, &n, 0);
|
||||
if (rv != SECSuccess)
|
||||
{
|
||||
NS_ERROR("des failure");
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if (ctxt)
|
||||
PK11_DestroyContext(ctxt, PR_TRUE);
|
||||
if (symkey)
|
||||
PK11_FreeSymKey(symkey);
|
||||
if (param)
|
||||
SECITEM_FreeItem(param, PR_TRUE);
|
||||
if (slot)
|
||||
PK11_FreeSlot(slot);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// MD5 support code
|
||||
|
||||
static void md5sum(const PRUint8 *input, PRUint32 inputLen, PRUint8 *result)
|
||||
{
|
||||
PK11Context *ctxt = PK11_CreateDigestContext(SEC_OID_MD5);
|
||||
if (ctxt)
|
||||
{
|
||||
if (PK11_DigestBegin(ctxt) == SECSuccess)
|
||||
{
|
||||
if (PK11_DigestOp(ctxt, input, inputLen) == SECSuccess)
|
||||
{
|
||||
PRUint32 resultLen = 16;
|
||||
PK11_DigestFinal(ctxt, result, &resultLen, resultLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
PK11_DestroyContext(ctxt, PR_TRUE);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/* vim:set ts=2 sw=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla 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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is IBM Corporation.
|
||||
* Portions created by IBM Corporation are Copyright (C) 2003
|
||||
* IBM Corporation. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* 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
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef nsNTLMAuthModule_h__
|
||||
#define nsNTLMAuthModule_h__
|
||||
|
||||
#include "nsIAuthModule.h"
|
||||
#include "nsString2.h"
|
||||
|
||||
class nsNTLMAuthModule : public nsIAuthModule
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIAUTHMODULE
|
||||
|
||||
nsNTLMAuthModule() {}
|
||||
virtual ~nsNTLMAuthModule();
|
||||
|
||||
nsresult InitTest();
|
||||
|
||||
private:
|
||||
nsString mDomain;
|
||||
nsString mUsername;
|
||||
nsString mPassword;
|
||||
};
|
||||
|
||||
#define NS_NTLMAUTHMODULE_CLASSNAME \
|
||||
"nsNTLMAuthModule"
|
||||
#define NS_NTLMAUTHMODULE_CONTRACTID \
|
||||
NS_AUTH_MODULE_CONTRACTID_PREFIX "ntlm"
|
||||
#define NS_NTLMAUTHMODULE_CID \
|
||||
{ /* a4e5888f-4fe4-4632-8e7e-745196ea7c70 */ \
|
||||
0xa4e5888f, \
|
||||
0x4fe4, \
|
||||
0x4632, \
|
||||
{0x8e, 0x7e, 0x74, 0x51, 0x96, 0xea, 0x7c, 0x70} \
|
||||
}
|
||||
|
||||
#endif // nsNTLMAuthModule_h__
|
Загрузка…
Ссылка в новой задаче