libwinpr-sspi: improve NTLM message debugging

This commit is contained in:
Marc-André Moreau 2012-07-01 14:33:36 -04:00
parent aff78da527
commit 63a3fe70cb
7 changed files with 297 additions and 230 deletions

View File

@ -65,6 +65,7 @@ void ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
GetComputerNameExA(ComputerNameDnsHostname, NULL, &nSize); GetComputerNameExA(ComputerNameDnsHostname, NULL, &nSize);
TargetName = malloc(nSize); TargetName = malloc(nSize);
GetComputerNameExA(ComputerNameDnsHostname, TargetName, &nSize); GetComputerNameExA(ComputerNameDnsHostname, TargetName, &nSize);
CharUpperA(TargetName);
} }
context->TargetName.cbBuffer = strlen(TargetName) * 2; context->TargetName.cbBuffer = strlen(TargetName) * 2;

View File

@ -81,6 +81,13 @@ enum _NTLM_STATE
}; };
typedef enum _NTLM_STATE NTLM_STATE; typedef enum _NTLM_STATE NTLM_STATE;
struct _NTLM_AV_PAIR
{
UINT16 AvId;
UINT16 AvLen;
};
typedef struct _NTLM_AV_PAIR NTLM_AV_PAIR;
struct _AV_PAIR struct _AV_PAIR
{ {
UINT16 length; UINT16 length;
@ -136,6 +143,32 @@ struct _NTLM_VERSION_INFO
}; };
typedef struct _NTLM_VERSION_INFO NTLM_VERSION_INFO; typedef struct _NTLM_VERSION_INFO NTLM_VERSION_INFO;
struct _NTLM_RESPONSE
{
BYTE Response[24];
};
typedef struct _NTLM_RESPONSE NTLM_RESPONSE;
struct _NTLMv2_CLIENT_CHALLENGE
{
UINT8 RespType;
UINT8 HiRespType;
UINT16 Reserved1;
UINT32 Reserved2;
BYTE Timestamp[8];
BYTE ClientChallenge[8];
UINT32 Reserved3;
NTLM_AV_PAIR* AvPairs;
};
typedef struct _NTLMv2_CLIENT_CHALLENGE NTLMv2_CLIENT_CHALLENGE;
struct _NTLMv2_RESPONSE
{
BYTE Response[16];
NTLMv2_CLIENT_CHALLENGE Challenge;
};
typedef struct _NTLMv2_RESPONSE NTLMv2_RESPONSE;
struct _NTLM_MESSAGE_FIELDS struct _NTLM_MESSAGE_FIELDS
{ {
UINT16 Len; UINT16 Len;
@ -169,6 +202,7 @@ struct _NTLM_CHALLENGE_MESSAGE
UINT32 MessageType; UINT32 MessageType;
UINT32 NegotiateFlags; UINT32 NegotiateFlags;
BYTE ServerChallenge[8]; BYTE ServerChallenge[8];
BYTE Reserved[8];
NTLM_VERSION_INFO Version; NTLM_VERSION_INFO Version;
NTLM_MESSAGE_FIELDS TargetName; NTLM_MESSAGE_FIELDS TargetName;
NTLM_MESSAGE_FIELDS TargetInfo; NTLM_MESSAGE_FIELDS TargetInfo;

View File

@ -43,6 +43,78 @@ const char* const AV_PAIRS_STRINGS[] =
"MsvChannelBindings" "MsvChannelBindings"
}; };
void ntlm_av_pair_list_init(NTLM_AV_PAIR* pAvPairList)
{
NTLM_AV_PAIR* pAvPair = pAvPairList;
pAvPair->AvId = MsvAvEOL;
pAvPair->AvLen = 0;
}
ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength)
{
/* size of headers + value lengths + terminating MsvAvEOL AV_PAIR */
return (AvPairsCount + 1) * sizeof(NTLM_AV_PAIR) + AvPairsValueLength;
}
PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair)
{
return &((PBYTE) pAvPair)[sizeof(NTLM_AV_PAIR)];
}
int ntlm_av_pair_get_next_offset(NTLM_AV_PAIR* pAvPair)
{
return pAvPair->AvLen + sizeof(NTLM_AV_PAIR);
}
NTLM_AV_PAIR* ntlm_av_pair_get_next_pointer(NTLM_AV_PAIR* pAvPair)
{
return (NTLM_AV_PAIR*) ((PBYTE) pAvPair + ntlm_av_pair_get_next_offset(pAvPair));
}
NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, AV_ID AvId, LONG AvPairListSize)
{
NTLM_AV_PAIR* pAvPair = pAvPairList;
if (!pAvPair)
return NULL;
while (1)
{
if (pAvPair->AvId == AvId)
return pAvPair;
if (pAvPair->AvId == MsvAvEOL)
return NULL;
AvPairListSize -= ntlm_av_pair_get_next_offset(pAvPair);
if (AvPairListSize <= 0)
return NULL;
pAvPair = ntlm_av_pair_get_next_pointer(pAvPair);
}
return NULL;
}
NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, AV_ID AvId, PUNICODE_STRING pValue, LONG AvPairListSize)
{
NTLM_AV_PAIR* pAvPair;
pAvPair = ntlm_av_pair_get(pAvPairList, MsvAvEOL, AvPairListSize);
if (!pAvPair)
return NULL;
pAvPair->AvId = AvId;
pAvPair->AvLen = pValue->Length;
CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), pValue->Buffer, pValue->Length);
return pAvPair;
}
/** /**
* Input array of AV_PAIRs.\n * Input array of AV_PAIRs.\n
* AV_PAIR @msdn{cc236646} * AV_PAIR @msdn{cc236646}
@ -322,74 +394,65 @@ void ntlm_populate_av_pairs(NTLM_CONTEXT* context)
ntlm_output_av_pairs(context, &context->TargetInfo); ntlm_output_av_pairs(context, &context->TargetInfo);
} }
/** void ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
* Populate array of AV_PAIRs (server).\n {
* AV_PAIR @msdn{cc236646} char* name;
* @param NTLM context DWORD nSize = 0;
*/
void ntlm_populate_server_av_pairs(NTLM_CONTEXT* context) GetComputerNameExA(type, NULL, &nSize);
name = malloc(nSize);
GetComputerNameExA(type, name, &nSize);
if (type == ComputerNameNetBIOS)
CharUpperA(name);
pName->Length = strlen(name) * 2;
pName->Buffer = (PWSTR) malloc(pName->Length);
MultiByteToWideChar(CP_ACP, 0, name, strlen(name),
(LPWSTR) pName->Buffer, pName->Length / 2);
pName->MaximumLength = pName->Length;
free(name);
}
void ntlm_construct_server_target_info(NTLM_CONTEXT* context)
{ {
int length; int length;
DWORD nSize; ULONG AvPairsCount;
AV_PAIRS* av_pairs; ULONG AvPairsLength;
char* NbDomainName; LONG AvPairListSize;
char* NbComputerName; NTLM_AV_PAIR* pAvPairList;
char* DnsDomainName; UNICODE_STRING NbDomainName;
char* DnsComputerName; UNICODE_STRING NbComputerName;
UNICODE_STRING DnsDomainName;
UNICODE_STRING DnsComputerName;
UNICODE_STRING Timestamp;
av_pairs = context->av_pairs; ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS);
ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS);
ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain);
ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname);
nSize = 0; Timestamp.Buffer = (PWSTR) context->Timestamp;
GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize); Timestamp.Length = sizeof(context->Timestamp);
NbDomainName = malloc(nSize);
GetComputerNameExA(ComputerNameNetBIOS, NbDomainName, &nSize);
CharUpperA(NbDomainName);
nSize = 0; AvPairsCount = 5;
GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize); AvPairsLength = NbDomainName.Length + NbComputerName.Length +
NbComputerName = malloc(nSize); DnsDomainName.Length + DnsComputerName.Length + 8;
GetComputerNameExA(ComputerNameNetBIOS, NbComputerName, &nSize);
CharUpperA(NbComputerName);
nSize = 0; length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength);
GetComputerNameExA(ComputerNameDnsDomain, NULL, &nSize);
DnsDomainName = malloc(nSize);
GetComputerNameExA(ComputerNameDnsDomain, DnsDomainName, &nSize);
nSize = 0;
GetComputerNameExA(ComputerNameDnsHostname, NULL, &nSize);
DnsComputerName = malloc(nSize);
GetComputerNameExA(ComputerNameDnsHostname, DnsComputerName, &nSize);
av_pairs->NbDomainName.length = strlen(NbDomainName) * 2;
av_pairs->NbDomainName.value = (BYTE*) malloc(av_pairs->NbDomainName.length);
MultiByteToWideChar(CP_ACP, 0, NbDomainName, strlen(NbDomainName),
(LPWSTR) av_pairs->NbDomainName.value, av_pairs->NbDomainName.length / 2);
av_pairs->NbComputerName.length = strlen(NbDomainName) * 2;
av_pairs->NbComputerName.value = (BYTE*) malloc(av_pairs->NbComputerName.length);
MultiByteToWideChar(CP_ACP, 0, NbComputerName, strlen(NbComputerName),
(LPWSTR) av_pairs->NbComputerName.value, av_pairs->NbComputerName.length / 2);
av_pairs->DnsDomainName.length = strlen(DnsDomainName) * 2;
av_pairs->DnsDomainName.value = (BYTE*) malloc(av_pairs->DnsDomainName.length);
MultiByteToWideChar(CP_ACP, 0, DnsDomainName, strlen(DnsDomainName),
(LPWSTR) av_pairs->DnsDomainName.value, av_pairs->DnsDomainName.length / 2);
av_pairs->DnsComputerName.length = strlen(DnsComputerName) * 2;
av_pairs->DnsComputerName.value = (BYTE*) malloc(av_pairs->DnsComputerName.length);
MultiByteToWideChar(CP_ACP, 0, DnsComputerName, strlen(DnsComputerName),
(LPWSTR) av_pairs->DnsComputerName.value, av_pairs->DnsComputerName.length / 2);
length = ntlm_compute_av_pairs_length(context) + 4;
sspi_SecBufferAlloc(&context->TargetInfo, length); sspi_SecBufferAlloc(&context->TargetInfo, length);
ntlm_output_av_pairs(context, &context->TargetInfo);
free(NbDomainName); pAvPairList = (NTLM_AV_PAIR*) context->TargetInfo.pvBuffer;
free(NbComputerName); AvPairListSize = (ULONG) context->TargetInfo.cbBuffer;
free(DnsDomainName);
free(DnsComputerName); ntlm_av_pair_list_init(pAvPairList);
ntlm_av_pair_add(pAvPairList, MsvAvNbDomainName, &NbDomainName, AvPairListSize);
ntlm_av_pair_add(pAvPairList, MsvAvNbComputerName, &NbComputerName, AvPairListSize);
ntlm_av_pair_add(pAvPairList, MsvAvDnsDomainName, &DnsDomainName, AvPairListSize);
ntlm_av_pair_add(pAvPairList, MsvAvDnsComputerName, &DnsComputerName, AvPairListSize);
ntlm_av_pair_add(pAvPairList, MsvAvTimestamp, &Timestamp, AvPairListSize);
} }
/** /**

View File

@ -24,6 +24,16 @@
#include <winpr/stream.h> #include <winpr/stream.h>
void ntlm_av_pair_list_init(NTLM_AV_PAIR* pAvPairList);
ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength);
PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair);
int ntlm_av_pair_get_next_offset(NTLM_AV_PAIR* pAvPair);
NTLM_AV_PAIR* ntlm_av_pair_get_next_pointer(NTLM_AV_PAIR* pAvPair);
NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, AV_ID AvId, LONG AvPairListSize);
NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, AV_ID AvId, PUNICODE_STRING pValue, LONG AvPairListSize);
void ntlm_construct_server_target_info(NTLM_CONTEXT* context);
void ntlm_input_av_pairs(NTLM_CONTEXT* context, PStream s); void ntlm_input_av_pairs(NTLM_CONTEXT* context, PStream s);
void ntlm_output_av_pairs(NTLM_CONTEXT* context, PSecBuffer buffer); void ntlm_output_av_pairs(NTLM_CONTEXT* context, PSecBuffer buffer);
void ntlm_populate_av_pairs(NTLM_CONTEXT* context); void ntlm_populate_av_pairs(NTLM_CONTEXT* context);

View File

@ -56,6 +56,21 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
versionInfo->NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; versionInfo->NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
} }
/**
* Read VERSION structure.\n
* VERSION @msdn{cc236654}
* @param s
*/
void ntlm_read_version_info(PStream s, NTLM_VERSION_INFO* versionInfo)
{
StreamRead_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */
StreamRead_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */
StreamRead_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */
StreamRead(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */
StreamRead_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */
}
/** /**
* Write VERSION structure.\n * Write VERSION structure.\n
* VERSION @msdn{cc236654} * VERSION @msdn{cc236654}
@ -64,17 +79,28 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
void ntlm_write_version_info(PStream s, NTLM_VERSION_INFO* versionInfo) void ntlm_write_version_info(PStream s, NTLM_VERSION_INFO* versionInfo)
{ {
OSVERSIONINFOA osVersionInfo; StreamWrite_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */
StreamWrite_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */
StreamWrite_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */
StreamWrite(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */
StreamWrite_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */
}
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); /**
* Print VERSION structure.\n
* VERSION @msdn{cc236654}
* @param s
*/
GetVersionExA(&osVersionInfo); void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo)
{
StreamWrite_UINT8(s, osVersionInfo.dwMajorVersion); /* ProductMajorVersion (1 byte) */ printf("VERSION =\n{\n");
StreamWrite_UINT8(s, osVersionInfo.dwMinorVersion); /* ProductMinorVersion (1 byte) */ printf("\tProductMajorVersion: %d\n", versionInfo->ProductMajorVersion);
StreamWrite_UINT16(s, osVersionInfo.dwBuildNumber); /* ProductBuild (2 bytes) */ printf("\tProductMinorVersion: %d\n", versionInfo->ProductMinorVersion);
StreamZero(s, 3); /* Reserved (3 bytes) */ printf("\tProductBuild: %d\n", versionInfo->ProductBuild);
StreamWrite_UINT8(s, NTLMSSP_REVISION_W2K3); /* NTLMRevisionCurrent (1 byte) */ printf("\tReserved: 0x%02X%02X%02X\n", versionInfo->Reserved[0],
versionInfo->Reserved[1], versionInfo->Reserved[2]);
printf("\tNTLMRevisionCurrent: 0x%02X\n", versionInfo->NTLMRevisionCurrent);
} }
/** /**

View File

@ -25,7 +25,9 @@
#include "ntlm_av_pairs.h" #include "ntlm_av_pairs.h"
void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo); void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo);
void ntlm_read_version_info(PStream s, NTLM_VERSION_INFO* versionInfo);
void ntlm_write_version_info(PStream s, NTLM_VERSION_INFO* versionInfo); void ntlm_write_version_info(PStream s, NTLM_VERSION_INFO* versionInfo);
void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo);
void ntlm_output_restriction_encoding(NTLM_CONTEXT* context); void ntlm_output_restriction_encoding(NTLM_CONTEXT* context);
void ntlm_output_target_name(NTLM_CONTEXT* context); void ntlm_output_target_name(NTLM_CONTEXT* context);

View File

@ -187,6 +187,15 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf
StreamRead_UINT32(s, message.NegotiateFlags); /* NegotiateFlags (4 bytes) */ StreamRead_UINT32(s, message.NegotiateFlags); /* NegotiateFlags (4 bytes) */
if (!((message.NegotiateFlags & NTLMSSP_REQUEST_TARGET) &&
(message.NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM) &&
(message.NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) &&
(message.NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE)))
{
PStreamFreeDetach(s);
return SEC_E_INVALID_TOKEN;
}
context->NegotiateFlags = message.NegotiateFlags; context->NegotiateFlags = message.NegotiateFlags;
/* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
@ -202,7 +211,7 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf
if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
{ {
/* Only present if NTLMSSP_NEGOTIATE_VERSION is set */ /* Only present if NTLMSSP_NEGOTIATE_VERSION is set */
StreamSeek(s, 8); /* Version (8 bytes) */ ntlm_read_version_info(s, &(message.Version)); /* Version (8 bytes) */
} }
length = StreamSize(s); length = StreamSize(s);
@ -322,7 +331,7 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu
SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer) SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
{ {
BYTE* p; PBYTE p;
PStream s; PStream s;
int length; int length;
PBYTE StartOffset; PBYTE StartOffset;
@ -334,6 +343,8 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf
ZeroMemory(&message, sizeof(message)); ZeroMemory(&message, sizeof(message));
s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer); s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer);
StartOffset = StreamGetPointer(s);
ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) &message); ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) &message);
if (!ntlm_validate_message_header(s, (NTLM_MESSAGE_HEADER*) &message, MESSAGE_TYPE_CHALLENGE)) if (!ntlm_validate_message_header(s, (NTLM_MESSAGE_HEADER*) &message, MESSAGE_TYPE_CHALLENGE))
@ -342,60 +353,38 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf
return SEC_E_INVALID_TOKEN; return SEC_E_INVALID_TOKEN;
} }
StartOffset = StreamGetPointer(s) - 12;
/* TargetNameFields (8 bytes) */ /* TargetNameFields (8 bytes) */
ntlm_read_message_fields(s, &(message.TargetName)); ntlm_read_message_fields(s, &(message.TargetName));
StreamRead_UINT32(s, context->NegotiateFlags); /* NegotiateFlags (4 bytes) */ StreamRead_UINT32(s, context->NegotiateFlags); /* NegotiateFlags (4 bytes) */
#ifdef WITH_DEBUG_NTLM StreamRead(s, message.ServerChallenge, 8); /* ServerChallenge (8 bytes) */
ntlm_print_negotiate_flags(context->NegotiateFlags); CopyMemory(context->ServerChallenge, message.ServerChallenge, 8);
#endif
StreamRead(s, context->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ StreamRead(s, message.Reserved, 8); /* Reserved (8 bytes), should be ignored */
StreamSeek(s, 8); /* Reserved (8 bytes), should be ignored */
/* TargetInfoFields (8 bytes) */ /* TargetInfoFields (8 bytes) */
ntlm_read_message_fields(s, &(message.TargetInfo)); ntlm_read_message_fields(s, &(message.TargetInfo));
/* only present if NTLMSSP_NEGOTIATE_VERSION is set */
if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
{ ntlm_read_version_info(s, &(message.Version)); /* Version (8 bytes) */
StreamSeek(s, 8); /* Version (8 bytes), can be ignored */
}
/* Payload (variable) */ /* Payload (variable) */
PayloadOffset = StreamGetPointer(s); PayloadOffset = StreamGetPointer(s);
if (message.TargetName.Len > 0) if (message.TargetName.Len > 0)
{ ntlm_read_message_fields_buffer(s, &(message.TargetName));
p = StartOffset + message.TargetName.BufferOffset;
sspi_SecBufferAlloc(&context->TargetName, message.TargetName.Len);
CopyMemory(context->TargetName.pvBuffer, p, message.TargetName.Len);
#ifdef WITH_DEBUG_NTLM
printf("TargetName (length = %d, offset = %d)\n", message.TargetName.Len, message.TargetName.BufferOffset);
winpr_HexDump(context->TargetName.pvBuffer, context->TargetName.cbBuffer);
printf("\n");
#endif
}
if (message.TargetInfo.Len > 0) if (message.TargetInfo.Len > 0)
{ {
p = StartOffset + message.TargetInfo.BufferOffset; ntlm_read_message_fields_buffer(s, &(message.TargetInfo));
sspi_SecBufferAlloc(&context->TargetInfo, message.TargetInfo.Len);
CopyMemory(context->TargetInfo.pvBuffer, p, message.TargetInfo.Len);
#ifdef WITH_DEBUG_NTLM context->TargetInfo.pvBuffer = message.TargetInfo.Buffer;
printf("TargetInfo (length = %d, offset = %d)\n", message.TargetInfo.Len, message.TargetInfo.BufferOffset); context->TargetInfo.cbBuffer = message.TargetInfo.Len;
winpr_HexDump(context->TargetInfo.pvBuffer, context->TargetInfo.cbBuffer);
printf("\n");
#endif
if (context->ntlm_v2) if (context->ntlm_v2)
{ {
p = StartOffset + message.TargetInfo.BufferOffset;
StreamSetPointer(s, p); StreamSetPointer(s, p);
ntlm_input_av_pairs(context, s); ntlm_input_av_pairs(context, s);
} }
@ -410,6 +399,14 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf
printf("CHALLENGE_MESSAGE (length = %d)\n", length); printf("CHALLENGE_MESSAGE (length = %d)\n", length);
winpr_HexDump(context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); winpr_HexDump(context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer);
printf("\n"); printf("\n");
ntlm_print_negotiate_flags(context->NegotiateFlags);
if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
ntlm_print_version_info(&(message.Version));
ntlm_print_message_fields(&(message.TargetName), "TargetName");
ntlm_print_message_fields(&(message.TargetInfo), "TargetInfo");
#endif #endif
/* AV_PAIRs */ /* AV_PAIRs */
@ -508,6 +505,12 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
UINT32 PayloadOffset; UINT32 PayloadOffset;
NTLM_CHALLENGE_MESSAGE message; NTLM_CHALLENGE_MESSAGE message;
ZeroMemory(&message, sizeof(message));
s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer);
/* Version */
ntlm_get_version_info(&(message.Version));
/* Server Challenge */ /* Server Challenge */
ntlm_generate_server_challenge(context); ntlm_generate_server_challenge(context);
@ -515,10 +518,10 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
ntlm_generate_timestamp(context); ntlm_generate_timestamp(context);
/* TargetInfo */ /* TargetInfo */
ntlm_populate_server_av_pairs(context); ntlm_construct_server_target_info(context);
ZeroMemory(&message, sizeof(message)); /* ServerChallenge */
s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer); CopyMemory(message.ServerChallenge, context->ServerChallenge, 8);
ntlm_populate_message_header((NTLM_MESSAGE_HEADER*) &message, MESSAGE_TYPE_CHALLENGE); ntlm_populate_message_header((NTLM_MESSAGE_HEADER*) &message, MESSAGE_TYPE_CHALLENGE);
@ -530,11 +533,6 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
message.TargetName.Len = (UINT16) context->TargetName.cbBuffer; message.TargetName.Len = (UINT16) context->TargetName.cbBuffer;
message.TargetName.Buffer = context->TargetName.pvBuffer; message.TargetName.Buffer = context->TargetName.pvBuffer;
} }
else
{
message.TargetName.Len = 0;
message.TargetName.Buffer = NULL;
}
context->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO; context->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
@ -543,11 +541,6 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
message.TargetInfo.Len = (UINT16) context->TargetInfo.cbBuffer; message.TargetInfo.Len = (UINT16) context->TargetInfo.cbBuffer;
message.TargetInfo.Buffer = context->TargetInfo.pvBuffer; message.TargetInfo.Buffer = context->TargetInfo.pvBuffer;
} }
else
{
message.TargetInfo.Len = 0;
message.TargetInfo.Buffer = NULL;
}
PayloadOffset = 48; PayloadOffset = 48;
@ -562,41 +555,22 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
StreamWrite_UINT32(s, context->NegotiateFlags); /* NegotiateFlags (4 bytes) */ StreamWrite_UINT32(s, context->NegotiateFlags); /* NegotiateFlags (4 bytes) */
StreamWrite(s, context->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ StreamWrite(s, message.ServerChallenge, 8); /* ServerChallenge (8 bytes) */
StreamZero(s, 8); /* Reserved (8 bytes), should be ignored */ StreamWrite(s, message.Reserved, 8); /* Reserved (8 bytes), should be ignored */
/* TargetInfoFields (8 bytes) */ /* TargetInfoFields (8 bytes) */
ntlm_write_message_fields(s, &(message.TargetInfo)); ntlm_write_message_fields(s, &(message.TargetInfo));
/* only present if NTLMSSP_NEGOTIATE_VERSION is set */
if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
{ ntlm_write_version_info(s, &(message.Version)); /* Version (8 bytes) */
ntlm_get_version_info(&(message.Version));
ntlm_write_version_info(s, &(message.Version)); /* Version (8 bytes), can be ignored */
}
/* Payload (variable) */ /* Payload (variable) */
if (message.TargetName.Len > 0) if (context->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
{ ntlm_write_message_fields_buffer(s, &(message.TargetName));
StreamWrite(s, message.TargetName.Buffer, message.TargetName.Len);
#ifdef WITH_DEBUG_NTLM
printf("TargetName (length = %d, offset = %d)\n", message.TargetName.Len, message.TargetName.BufferOffset);
winpr_HexDump(message.TargetName.Buffer, message.TargetName.Len);
printf("\n");
#endif
}
if (message.TargetInfo.Len > 0) if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
{ ntlm_write_message_fields_buffer(s, &(message.TargetInfo));
StreamWrite(s, message.TargetInfo.Buffer, message.TargetInfo.Len);
#ifdef WITH_DEBUG_NTLM
printf("TargetInfo (length = %d, offset = %d)\n", message.TargetInfo.Len, message.TargetInfo.BufferOffset);
winpr_HexDump(message.TargetInfo.Buffer, message.TargetInfo.Len);
printf("\n");
#endif
}
length = StreamSize(s); length = StreamSize(s);
buffer->cbBuffer = length; buffer->cbBuffer = length;
@ -608,6 +582,12 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
printf("CHALLENGE_MESSAGE (length = %d)\n", length); printf("CHALLENGE_MESSAGE (length = %d)\n", length);
winpr_HexDump(context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); winpr_HexDump(context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer);
printf("\n"); printf("\n");
if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
ntlm_print_version_info(&(message.Version));
ntlm_print_message_fields(&(message.TargetName), "TargetName");
ntlm_print_message_fields(&(message.TargetInfo), "TargetInfo");
#endif #endif
context->state = NTLM_STATE_AUTHENTICATE; context->state = NTLM_STATE_AUTHENTICATE;
@ -659,57 +639,25 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
StreamRead_UINT32(s, message.NegotiateFlags); /* NegotiateFlags (4 bytes) */ StreamRead_UINT32(s, message.NegotiateFlags); /* NegotiateFlags (4 bytes) */
if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
{ ntlm_read_version_info(s, &(message.Version)); /* Version (8 bytes) */
/* Only present if NTLMSSP_NEGOTIATE_VERSION is set */
#ifdef WITH_DEBUG_NTLM
printf("Version (length = 8)\n");
winpr_HexDump(s->p, 8);
printf("\n");
#endif
StreamSeek(s, 8); /* Version (8 bytes) */
}
length = StreamSize(s); length = StreamSize(s);
sspi_SecBufferAlloc(&context->AuthenticateMessage, length); sspi_SecBufferAlloc(&context->AuthenticateMessage, length);
CopyMemory(context->AuthenticateMessage.pvBuffer, s->data, length); CopyMemory(context->AuthenticateMessage.pvBuffer, s->data, length);
buffer->cbBuffer = length; buffer->cbBuffer = length;
#ifdef WITH_DEBUG_NTLM
printf("AUTHENTICATE_MESSAGE (length = %d)\n", length);
winpr_HexDump(s->data, length);
printf("\n");
#endif
/* DomainName */ /* DomainName */
ntlm_read_message_fields_buffer(s, &(message.DomainName)); ntlm_read_message_fields_buffer(s, &(message.DomainName));
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.DomainName), "DomainName");
#endif
/* UserName */ /* UserName */
ntlm_read_message_fields_buffer(s, &(message.UserName)); ntlm_read_message_fields_buffer(s, &(message.UserName));
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.UserName), "UserName");
#endif
/* Workstation */ /* Workstation */
ntlm_read_message_fields_buffer(s, &(message.Workstation)); ntlm_read_message_fields_buffer(s, &(message.Workstation));
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.Workstation), "Workstation");
#endif
/* LmChallengeResponse */ /* LmChallengeResponse */
ntlm_read_message_fields_buffer(s, &(message.LmChallengeResponse)); ntlm_read_message_fields_buffer(s, &(message.LmChallengeResponse));
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.LmChallengeResponse), "LmChallengeResponse");
#endif
/* NtChallengeResponse */ /* NtChallengeResponse */
ntlm_read_message_fields_buffer(s, &(message.NtChallengeResponse)); ntlm_read_message_fields_buffer(s, &(message.NtChallengeResponse));
@ -720,15 +668,23 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
CopyMemory(context->ClientChallenge, ClientChallengeBuffer, 8); CopyMemory(context->ClientChallenge, ClientChallengeBuffer, 8);
} }
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.NtChallengeResponse), "NtChallengeResponse");
#endif
/* EncryptedRandomSessionKey */ /* EncryptedRandomSessionKey */
ntlm_read_message_fields_buffer(s, &(message.EncryptedRandomSessionKey)); ntlm_read_message_fields_buffer(s, &(message.EncryptedRandomSessionKey));
CopyMemory(context->EncryptedRandomSessionKey, message.EncryptedRandomSessionKey.Buffer, 16); CopyMemory(context->EncryptedRandomSessionKey, message.EncryptedRandomSessionKey.Buffer, 16);
#ifdef WITH_DEBUG_NTLM #ifdef WITH_DEBUG_NTLM
printf("AUTHENTICATE_MESSAGE (length = %d)\n", length);
winpr_HexDump(s->data, length);
printf("\n");
if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
ntlm_print_version_info(&(message.Version));
ntlm_print_message_fields(&(message.DomainName), "DomainName");
ntlm_print_message_fields(&(message.UserName), "UserName");
ntlm_print_message_fields(&(message.Workstation), "Workstation");
ntlm_print_message_fields(&(message.LmChallengeResponse), "LmChallengeResponse");
ntlm_print_message_fields(&(message.NtChallengeResponse), "NtChallengeResponse");
ntlm_print_message_fields(&(message.EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); ntlm_print_message_fields(&(message.EncryptedRandomSessionKey), "EncryptedRandomSessionKey");
#endif #endif
@ -941,21 +897,9 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
StreamWrite_UINT32(s, message.NegotiateFlags); /* NegotiateFlags (4 bytes) */ StreamWrite_UINT32(s, message.NegotiateFlags); /* NegotiateFlags (4 bytes) */
#ifdef WITH_DEBUG_NTLM
ntlm_print_negotiate_flags(message.NegotiateFlags);
#endif
if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
{
ntlm_write_version_info(s, &(message.Version)); ntlm_write_version_info(s, &(message.Version));
#ifdef WITH_DEBUG_NTLM
printf("Version (length = 8)\n");
winpr_HexDump((s->p - 8), 8);
printf("\n");
#endif
}
if (context->ntlm_v2) if (context->ntlm_v2)
{ {
/* Message Integrity Check */ /* Message Integrity Check */
@ -966,56 +910,21 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
/* DomainName */ /* DomainName */
ntlm_write_message_fields_buffer(s, &(message.DomainName)); ntlm_write_message_fields_buffer(s, &(message.DomainName));
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.DomainName), "DomainName");
#endif
/* UserName */ /* UserName */
ntlm_write_message_fields_buffer(s, &(message.UserName)); ntlm_write_message_fields_buffer(s, &(message.UserName));
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.UserName), "UserName");
#endif
/* Workstation */ /* Workstation */
ntlm_write_message_fields_buffer(s, &(message.Workstation)); ntlm_write_message_fields_buffer(s, &(message.Workstation));
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.Workstation), "Workstation");
#endif
/* LmChallengeResponse */ /* LmChallengeResponse */
ntlm_write_message_fields_buffer(s, &(message.LmChallengeResponse)); ntlm_write_message_fields_buffer(s, &(message.LmChallengeResponse));
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.LmChallengeResponse), "LmChallengeResponse");
#endif
/* NtChallengeResponse */ /* NtChallengeResponse */
ntlm_write_message_fields_buffer(s, &(message.NtChallengeResponse)); ntlm_write_message_fields_buffer(s, &(message.NtChallengeResponse));
#ifdef WITH_DEBUG_NTLM
if (context->ntlm_v2)
{
ntlm_print_av_pairs(context);
printf("targetInfo (length = %d)\n", (int) context->TargetInfo.cbBuffer);
winpr_HexDump(context->TargetInfo.pvBuffer, context->TargetInfo.cbBuffer);
printf("\n");
}
#endif
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.NtChallengeResponse), "NtChallengeResponse");
#endif
/* EncryptedRandomSessionKey */ /* EncryptedRandomSessionKey */
ntlm_write_message_fields_buffer(s, &(message.EncryptedRandomSessionKey)); ntlm_write_message_fields_buffer(s, &(message.EncryptedRandomSessionKey));
#ifdef WITH_DEBUG_NTLM
ntlm_print_message_fields(&(message.EncryptedRandomSessionKey), "EncryptedRandomSessionKey");
#endif
length = StreamSize(s); length = StreamSize(s);
sspi_SecBufferAlloc(&context->AuthenticateMessage, length); sspi_SecBufferAlloc(&context->AuthenticateMessage, length);
CopyMemory(context->AuthenticateMessage.pvBuffer, s->data, length); CopyMemory(context->AuthenticateMessage.pvBuffer, s->data, length);
@ -1029,18 +938,40 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
s->p = MicOffset; s->p = MicOffset;
StreamWrite(s, context->MessageIntegrityCheck, 16); StreamWrite(s, context->MessageIntegrityCheck, 16);
s->p = s->data + length; s->p = s->data + length;
#ifdef WITH_DEBUG_NTLM
printf("MessageIntegrityCheck (length = 16)\n");
winpr_HexDump(MicOffset, 16);
printf("\n");
#endif
} }
#ifdef WITH_DEBUG_NTLM #ifdef WITH_DEBUG_NTLM
printf("AUTHENTICATE_MESSAGE (length = %d)\n", length); printf("AUTHENTICATE_MESSAGE (length = %d)\n", length);
winpr_HexDump(s->data, length); winpr_HexDump(s->data, length);
printf("\n"); printf("\n");
ntlm_print_negotiate_flags(message.NegotiateFlags);
if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
ntlm_print_version_info(&(message.Version));
ntlm_print_message_fields(&(message.DomainName), "DomainName");
ntlm_print_message_fields(&(message.UserName), "UserName");
ntlm_print_message_fields(&(message.Workstation), "Workstation");
ntlm_print_message_fields(&(message.LmChallengeResponse), "LmChallengeResponse");
ntlm_print_message_fields(&(message.NtChallengeResponse), "NtChallengeResponse");
ntlm_print_message_fields(&(message.EncryptedRandomSessionKey), "EncryptedRandomSessionKey");
if (context->ntlm_v2)
{
ntlm_print_av_pairs(context);
printf("targetInfo (length = %d)\n", (int) context->TargetInfo.cbBuffer);
winpr_HexDump(context->TargetInfo.pvBuffer, context->TargetInfo.cbBuffer);
printf("\n");
}
if (context->ntlm_v2)
{
printf("MessageIntegrityCheck (length = 16)\n");
winpr_HexDump(MicOffset, 16);
printf("\n");
}
#endif #endif
context->state = NTLM_STATE_FINAL; context->state = NTLM_STATE_FINAL;