Adds a callback that allows servers to compute NTLM hashes by themselves. The typical
use of this callback is to provide a function that gives precomputed hash values.
Sponsored by: Wheel Systems (http://www.wheelsystems.com)
#include <freerdp/autodetect.h>
#include <winpr/sspi.h>
+#include <winpr/ntlm.h>
+
typedef BOOL (*psPeerContextNew)(freerdp_peer* peer, rdpContext* context);
typedef void (*psPeerContextFree)(freerdp_peer* peer, rdpContext* context);
psPeerGetEventHandles GetEventHandles;
psPeerAdjustMonitorsLayout AdjustMonitorsLayout;
psPeerClientCapabilities ClientCapabilities;
+ psPeerComputeNtlmHash ComputeNtlmHash;
};
#ifdef __cplusplus
#include <freerdp/log.h>
#include <freerdp/crypto/tls.h>
#include <freerdp/build-config.h>
+#include <freerdp/peer.h>
#include <winpr/crt.h>
#include <winpr/sam.h>
if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED))
{
- if (nla->SamFile)
+ freerdp_peer *peer = nla->instance->context->peer;
+
+ if (peer->ComputeNtlmHash)
+ {
+ SECURITY_STATUS status;
+
+ status = nla->table->SetContextAttributes(&nla->context, SECPKG_ATTR_AUTH_NTLM_HASH_CB, peer->ComputeNtlmHash, 0);
+ if (status != SEC_E_OK)
+ {
+ WLog_ERR(TAG, "SetContextAttributesA(hash cb) status %s [0x%08"PRIX32"]", GetSecurityStatusString(status), status);
+ }
+
+ status = nla->table->SetContextAttributes(&nla->context, SECPKG_ATTR_AUTH_NTLM_HASH_CB_DATA, peer, 0);
+ if (status != SEC_E_OK)
+ {
+ WLog_ERR(TAG, "SetContextAttributesA(hash cb data) status %s [0x%08"PRIX32"]", GetSecurityStatusString(status), status);
+ }
+ }
+ else if (nla->SamFile)
{
- nla->table->SetContextAttributes(&nla->context,
- SECPKG_ATTR_AUTH_NTLM_SAM_FILE, nla->SamFile, strlen(nla->SamFile) + 1);
+ nla->table->SetContextAttributes(&nla->context, SECPKG_ATTR_AUTH_NTLM_SAM_FILE, nla->SamFile,
+ strlen(nla->SamFile) + 1);
}
if (nla->table->CompleteAuthToken)
}
nla->havePubKeyAuth = TRUE;
- nla->status = nla->table->QueryContextAttributes(&nla->context, SECPKG_ATTR_SIZES,
+ nla->status = nla->table->QueryContextAttributes(&nla->context, SECPKG_ATTR_SIZES,
&nla->ContextSizes);
if (nla->status != SEC_E_OK)
return NULL;
nla->identity = calloc(1, sizeof(SEC_WINNT_AUTH_IDENTITY));
-
if (!nla->identity)
{
free(nla);
#include <string.h>
#include <winpr/winpr.h>
#include <winpr/wtypes.h>
+#include <winpr/sspi.h>
#ifdef __cplusplus
extern "C" {
#endif
+typedef SECURITY_STATUS (*psPeerComputeNtlmHash)(void *client, const SEC_WINNT_AUTH_IDENTITY *authIdentity,
+ const SecBuffer *ntproofvalue, const BYTE *randkey, const BYTE *mic, const SecBuffer *micvalue,
+ BYTE *ntlmhash);
+
WINPR_API BYTE* NTOWFv1W(LPWSTR Password, UINT32 PasswordLength, BYTE* NtHash);
WINPR_API BYTE* NTOWFv1A(LPSTR Password, UINT32 PasswordLength, BYTE* NtHash);
#define SECPKG_ATTR_AUTH_NTLM_RANDKEY 1105
#define SECPKG_ATTR_AUTH_NTLM_MIC 1106
#define SECPKG_ATTR_AUTH_NTLM_MIC_VALUE 1107
+#define SECPKG_ATTR_AUTH_NTLM_HASH_CB 1108
+#define SECPKG_ATTR_AUTH_NTLM_HASH_CB_DATA 1109
struct _SecPkgContext_AuthIdentity
return SEC_E_OK;
}
+SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT *ntlm, SecBuffer *ntproof)
+{
+ BYTE* blob;
+ SecBuffer* target = &ntlm->ChallengeTargetInfo;
+
+ if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer))
+ return SEC_E_INSUFFICIENT_MEMORY;
+
+ blob = (BYTE *)ntproof->pvBuffer;
+
+ CopyMemory(blob, ntlm->ServerChallenge, 8); /* Server challenge. */
+ blob[8] = 1; /* Response version. */
+ blob[9] = 1; /* Highest response version understood by the client. */
+ /* Reserved 6B. */
+
+ CopyMemory(&blob[16], ntlm->Timestamp, 8); /* Time. */
+ CopyMemory(&blob[24], ntlm->ClientChallenge, 8); /* Client challenge. */
+ /* Reserved 4B. */
+ /* Server name. */
+ CopyMemory(&blob[36], target->pvBuffer, target->cbBuffer);
+
+ return SEC_E_OK;
+
+}
+
+SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT *ntlm, SecBuffer *micvalue)
+{
+ BYTE* blob;
+ ULONG msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer +
+ ntlm->AuthenticateMessage.cbBuffer;
+
+ if (!sspi_SecBufferAlloc(micvalue, msgSize))
+ return SEC_E_INSUFFICIENT_MEMORY;
+
+ blob = (BYTE *) micvalue->pvBuffer;
+ CopyMemory(blob, ntlm->NegotiateMessage.pvBuffer, ntlm->NegotiateMessage.cbBuffer);
+ blob += ntlm->NegotiateMessage.cbBuffer;
+ CopyMemory(blob, ntlm->ChallengeMessage.pvBuffer, ntlm->ChallengeMessage.cbBuffer);
+ blob += ntlm->ChallengeMessage.cbBuffer;
+ CopyMemory(blob, ntlm->AuthenticateMessage.pvBuffer, ntlm->AuthenticateMessage.cbBuffer);
+ blob += ntlm->MessageIntegrityCheckOffset;
+ ZeroMemory(blob, 16);
+
+ return SEC_E_OK;
+}
+
+
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa379337/ */
SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute,
}
else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_NTPROOF_VALUE)
{
- BYTE* blob;
- SecBuffer* ntproof, *target;
- ntproof = (SecBuffer*)pBuffer;
- target = &context->ChallengeTargetInfo;
-
- if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer))
- return (SEC_E_INSUFFICIENT_MEMORY);
-
- blob = (BYTE*)ntproof->pvBuffer;
- /* Server challenge. */
- CopyMemory(blob, context->ServerChallenge, 8);
- /* Response version. */
- blob[8] = 1;
- /* Highest response version understood by the client. */
- blob[9] = 1;
- /* Reserved 6B. */
- /* Time. */
- CopyMemory(&blob[16], context->Timestamp, 8);
- /* Client challenge. */
- CopyMemory(&blob[24], context->ClientChallenge, 8);
- /* Reserved 4B. */
- /* Server name. */
- CopyMemory(&blob[36], target->pvBuffer, target->cbBuffer);
- return (SEC_E_OK);
+ return ntlm_computeProofValue(context, (SecBuffer*)pBuffer);
}
else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_RANDKEY)
{
}
else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MIC_VALUE)
{
- BYTE* blob;
- SecBuffer* micvalue;
- ULONG msgSize = context->NegotiateMessage.cbBuffer + context->ChallengeMessage.cbBuffer +
- context->AuthenticateMessage.cbBuffer;
- micvalue = (SecBuffer*) pBuffer;
-
- if (!sspi_SecBufferAlloc(micvalue, msgSize))
- return (SEC_E_INSUFFICIENT_MEMORY);
-
- blob = (BYTE*) micvalue->pvBuffer;
- CopyMemory(blob, context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer);
- blob += context->NegotiateMessage.cbBuffer;
- CopyMemory(blob, context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer);
- blob += context->ChallengeMessage.cbBuffer;
- CopyMemory(blob, context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer);
- blob += context->MessageIntegrityCheckOffset;
- ZeroMemory(blob, 16);
- return (SEC_E_OK);
+ return ntlm_computeMicValue(context, (SecBuffer*) pBuffer);
}
return SEC_E_UNSUPPORTED_FUNCTION;
CopyMemory(context->ServerChallenge, AuthNtlmServerChallenge->ServerChallenge, 8);
return SEC_E_OK;
}
+ else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH_CB)
+ {
+ context->HashCallback = (psPeerComputeNtlmHash)pBuffer;
+ return SEC_E_OK;
+ }
+ else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH_CB_DATA)
+ {
+ context->HashCallbackArg = pBuffer;
+ return SEC_E_OK;
+ }
return SEC_E_UNSUPPORTED_FUNCTION;
}
#include <winpr/nt.h>
#include <winpr/crypto.h>
+#include <winpr/ntlm.h>
#include "../sspi.h"
BYTE ServerSealingKey[16];
BYTE MessageIntegrityCheck[16];
UINT32 MessageIntegrityCheckOffset;
+ psPeerComputeNtlmHash HashCallback;
+ void *HashCallbackArg;
};
typedef struct _NTLM_CONTEXT NTLM_CONTEXT;
NTLM_CONTEXT* ntlm_ContextNew(void);
void ntlm_ContextFree(NTLM_CONTEXT* context);
+SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT *ntlm, SecBuffer *ntproof);
+SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT *ntlm, SecBuffer *micvalue);
#ifdef WITH_DEBUG_NLA
#define WITH_DEBUG_NTLM
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, (BYTE*) hash);
}
+ else if (context->HashCallback)
+ {
+ int ret;
+ SecBuffer proofValue, micValue;
+
+ if (ntlm_computeProofValue(context, &proofValue) != SEC_E_OK)
+ return -1;
+
+ if (ntlm_computeMicValue(context, &micValue) != SEC_E_OK)
+ {
+ sspi_SecBufferFree(&proofValue);
+ return -1;
+ }
+
+ ret = context->HashCallback(context->HashCallbackArg, &credentials->identity, &proofValue,
+ context->EncryptedRandomSessionKey, context->MessageIntegrityCheck, &micValue,
+ hash);
+
+ sspi_SecBufferFree(&proofValue);
+ sspi_SecBufferFree(&micValue);
+ return ret ? 1 : -1;
+ }
else if (context->UseSamFileDatabase)
{
- ntlm_fetch_ntlm_v2_hash(context, hash);
+ return ntlm_fetch_ntlm_v2_hash(context, hash);
}
return 1;
blob = (BYTE*) ntlm_v2_temp.pvBuffer;
/* Compute the NTLMv2 hash */
-
if (ntlm_compute_ntlm_v2_hash(context, (BYTE*) context->NtlmV2Hash) < 0)
return -1;
if (!SecBuffer)
return;
- memset(SecBuffer->pvBuffer, 0, SecBuffer->cbBuffer);
+ if (SecBuffer->pvBuffer)
+ memset(SecBuffer->pvBuffer, 0, SecBuffer->cbBuffer);
free(SecBuffer->pvBuffer);
SecBuffer->pvBuffer = NULL;
SecBuffer->cbBuffer = 0;