From 633e0f90bf7cc933d84d3470081661cc870c5d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 29 Jun 2012 16:09:14 -0400 Subject: [PATCH] libwinpr-sspi: simplify NTLM header and fields read/write --- include/winpr/wtypes.h | 8 ++ winpr/sspi/NTLM/ntlm.h | 31 +++--- winpr/sspi/NTLM/ntlm_message.c | 188 ++++++++++++++++----------------- 3 files changed, 118 insertions(+), 109 deletions(-) diff --git a/include/winpr/wtypes.h b/include/winpr/wtypes.h index 94d5ac4a2..1311132e2 100644 --- a/include/winpr/wtypes.h +++ b/include/winpr/wtypes.h @@ -54,6 +54,14 @@ typedef float FLOAT; typedef unsigned char UCHAR, *PUCHAR; typedef short SHORT; +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + typedef void* HANDLE, *LPHANDLE; typedef DWORD HCALL; typedef int INT, *LPINT; diff --git a/winpr/sspi/NTLM/ntlm.h b/winpr/sspi/NTLM/ntlm.h index 904d8d853..3a6e06e04 100644 --- a/winpr/sspi/NTLM/ntlm.h +++ b/winpr/sspi/NTLM/ntlm.h @@ -136,14 +136,21 @@ struct _NTLM_VERSION_INFO }; typedef struct _NTLM_VERSION_INFO NTLM_VERSION_INFO; -struct _NTLM_MESSAGE_FIELD +struct _NTLM_MESSAGE_FIELDS { UINT16 Len; UINT16 MaxLen; PBYTE Buffer; UINT32 BufferOffset; }; -typedef struct _NTLM_MESSAGE_FIELD NTLM_MESSAGE_FIELD; +typedef struct _NTLM_MESSAGE_FIELDS NTLM_MESSAGE_FIELDS; + +struct _NTLM_MESSAGE_HEADER +{ + BYTE Signature[8]; + UINT32 MessageType; +}; +typedef struct _NTLM_MESSAGE_HEADER NTLM_MESSAGE_HEADER; struct _NTLM_NEGOTIATE_MESSAGE { @@ -151,8 +158,8 @@ struct _NTLM_NEGOTIATE_MESSAGE UINT32 MessageType; UINT32 NegotiateFlags; NTLM_VERSION_INFO Version; - NTLM_MESSAGE_FIELD DomainName; - NTLM_MESSAGE_FIELD Workstation; + NTLM_MESSAGE_FIELDS DomainName; + NTLM_MESSAGE_FIELDS Workstation; }; typedef struct _NTLM_NEGOTIATE_MESSAGE NTLM_NEGOTIATE_MESSAGE; @@ -163,8 +170,8 @@ struct _NTLM_CHALLENGE_MESSAGE UINT32 NegotiateFlags; BYTE ServerChallenge[8]; NTLM_VERSION_INFO Version; - NTLM_MESSAGE_FIELD TargetName; - NTLM_MESSAGE_FIELD TargetInfo; + NTLM_MESSAGE_FIELDS TargetName; + NTLM_MESSAGE_FIELDS TargetInfo; }; typedef struct _NTLM_CHALLENGE_MESSAGE NTLM_CHALLENGE_MESSAGE; @@ -174,12 +181,12 @@ struct _NTLM_AUTHENTICATE_MESSAGE UINT32 MessageType; UINT32 NegotiateFlags; NTLM_VERSION_INFO Version; - NTLM_MESSAGE_FIELD DomainName; - NTLM_MESSAGE_FIELD UserName; - NTLM_MESSAGE_FIELD Workstation; - NTLM_MESSAGE_FIELD LmChallengeResponse; - NTLM_MESSAGE_FIELD NtChallengeResponse; - NTLM_MESSAGE_FIELD EncryptedRandomSessionKey; + NTLM_MESSAGE_FIELDS DomainName; + NTLM_MESSAGE_FIELDS UserName; + NTLM_MESSAGE_FIELDS Workstation; + NTLM_MESSAGE_FIELDS LmChallengeResponse; + NTLM_MESSAGE_FIELDS NtChallengeResponse; + NTLM_MESSAGE_FIELDS EncryptedRandomSessionKey; BYTE MessageIntegrityCheck[16]; }; typedef struct _NTLM_AUTHENTICATE_MESSAGE NTLM_AUTHENTICATE_MESSAGE; diff --git a/winpr/sspi/NTLM/ntlm_message.c b/winpr/sspi/NTLM/ntlm_message.c index 214f22678..cb8cedcf0 100644 --- a/winpr/sspi/NTLM/ntlm_message.c +++ b/winpr/sspi/NTLM/ntlm_message.c @@ -29,7 +29,7 @@ #include "ntlm_message.h" -static const char NTLM_SIGNATURE[] = "NTLMSSP"; +static const char NTLM_SIGNATURE[8] = "NTLMSSP\0"; static const char* const NTLM_NEGOTIATE_STRINGS[] = { @@ -86,6 +86,58 @@ void ntlm_print_negotiate_flags(UINT32 flags) printf("}\n"); } +void ntlm_read_message_header(PStream s, NTLM_MESSAGE_HEADER* header) +{ + StreamRead(s, header->Signature, sizeof(NTLM_SIGNATURE)); + StreamRead_UINT32(s, header->MessageType); +} + +void ntlm_write_message_header(PStream s, NTLM_MESSAGE_HEADER* header) +{ + StreamWrite(s, header->Signature, sizeof(NTLM_SIGNATURE)); + StreamWrite_UINT32(s, header->MessageType); +} + +void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType) +{ + CopyMemory(header->Signature, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); + header->MessageType = MessageType; +} + +BOOL ntlm_validate_message_header(PStream s, NTLM_MESSAGE_HEADER* header, UINT32 MessageType) +{ + if (memcmp(header->Signature, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0) + { + printf("Unexpected NTLM signature: %s, expected:%s\n", header->Signature, NTLM_SIGNATURE); + return FALSE; + } + + if (header->MessageType != MessageType) + { + printf("Unexpected NTLM message type: %d, expected: %d\n", header->MessageType, MessageType); + return FALSE; + } + + return TRUE; +} + +void ntlm_read_message_fields(PStream s, NTLM_MESSAGE_FIELDS* fields) +{ + StreamRead_UINT16(s, fields->Len); /* Len (2 bytes) */ + StreamRead_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ + StreamRead_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ +} + +void ntlm_write_message_fields(PStream s, NTLM_MESSAGE_FIELDS* fields) +{ + if (fields->MaxLen < 1) + fields->MaxLen = fields->Len; + + StreamWrite_UINT16(s, fields->Len); /* Len (2 bytes) */ + StreamWrite_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ + StreamWrite_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ +} + SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { PStream s; @@ -95,17 +147,9 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf ZeroMemory(&message, sizeof(message)); s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer); - StreamRead(s, message.Signature, 8); - StreamRead_UINT32(s, message.MessageType); + ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) &message); - if (memcmp(message.Signature, NTLM_SIGNATURE, 8) != 0) - { - printf("Unexpected NTLM signature: %s, expected:%s\n", message.Signature, NTLM_SIGNATURE); - PStreamFreeDetach(s); - return SEC_E_INVALID_TOKEN; - } - - if (message.MessageType != MESSAGE_TYPE_NEGOTIATE) + if (!ntlm_validate_message_header(s, (NTLM_MESSAGE_HEADER*) &message, MESSAGE_TYPE_NEGOTIATE)) { PStreamFreeDetach(s); return SEC_E_INVALID_TOKEN; @@ -118,16 +162,12 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ /* DomainNameFields (8 bytes) */ - StreamRead_UINT16(s, message.DomainName.Len); /* DomainNameLen */ - StreamRead_UINT16(s, message.DomainName.MaxLen); /* DomainNameMaxLen */ - StreamRead_UINT32(s, message.DomainName.BufferOffset); /* DomainNameBufferOffset */ + ntlm_read_message_fields(s, &(message.DomainName)); /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ /* WorkstationFields (8 bytes) */ - StreamRead_UINT16(s, message.Workstation.Len); /* WorkstationLen */ - StreamRead_UINT16(s, message.Workstation.MaxLen); /* WorkstationMaxLen */ - StreamRead_UINT32(s, message.Workstation.BufferOffset); /* WorkstationBufferOffset */ + ntlm_read_message_fields(s, &(message.Workstation)); if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) { @@ -164,8 +204,10 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu ZeroMemory(&message, sizeof(message)); s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer); - StreamWrite(s, NTLM_SIGNATURE, 8); /* Signature (8 bytes) */ - StreamWrite_UINT32(s, MESSAGE_TYPE_NEGOTIATE); /* MessageType */ + ntlm_populate_message_header((NTLM_MESSAGE_HEADER*) &message, MESSAGE_TYPE_NEGOTIATE); + + /* Message Header (12 bytes) */ + ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*) &message); if (context->ntlm_v2) { @@ -207,16 +249,12 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ /* DomainNameFields (8 bytes) */ - StreamWrite_UINT16(s, 0); /* DomainNameLen */ - StreamWrite_UINT16(s, 0); /* DomainNameMaxLen */ - StreamWrite_UINT32(s, 0); /* DomainNameBufferOffset */ + ntlm_write_message_fields(s, &(message.DomainName)); /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ /* WorkstationFields (8 bytes) */ - StreamWrite_UINT16(s, 0); /* WorkstationLen */ - StreamWrite_UINT16(s, 0); /* WorkstationMaxLen */ - StreamWrite_UINT32(s, 0); /* WorkstationBufferOffset */ + ntlm_write_message_fields(s, &(message.Workstation)); if (message.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) { @@ -266,17 +304,9 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf ZeroMemory(&message, sizeof(message)); s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer); - StreamRead(s, message.Signature, 8); - StreamRead_UINT32(s, message.MessageType); + ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) &message); - if (memcmp(message.Signature, NTLM_SIGNATURE, 8) != 0) - { - printf("Unexpected NTLM signature: %s, expected:%s\n", message.Signature, NTLM_SIGNATURE); - PStreamFreeDetach(s); - return SEC_E_INVALID_TOKEN; - } - - if (message.MessageType != MESSAGE_TYPE_CHALLENGE) + if (!ntlm_validate_message_header(s, (NTLM_MESSAGE_HEADER*) &message, MESSAGE_TYPE_CHALLENGE)) { PStreamFreeDetach(s); return SEC_E_INVALID_TOKEN; @@ -285,9 +315,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf StartOffset = StreamGetPointer(s) - 12; /* TargetNameFields (8 bytes) */ - StreamRead_UINT16(s, message.TargetName.Len); /* TargetNameLen (2 bytes) */ - StreamRead_UINT16(s, message.TargetName.MaxLen); /* TargetNameMaxLen (2 bytes) */ - StreamRead_UINT32(s, message.TargetName.BufferOffset); /* TargetNameBufferOffset (4 bytes) */ + ntlm_read_message_fields(s, &(message.TargetName)); StreamRead_UINT32(s, context->NegotiateFlags); /* NegotiateFlags (4 bytes) */ @@ -299,9 +327,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf StreamSeek(s, 8); /* Reserved (8 bytes), should be ignored */ /* TargetInfoFields (8 bytes) */ - StreamRead_UINT16(s, message.TargetInfo.Len); /* TargetInfoLen (2 bytes) */ - StreamRead_UINT16(s, message.TargetInfo.MaxLen); /* TargetInfoMaxLen (2 bytes) */ - StreamRead_UINT32(s, message.TargetInfo.BufferOffset); /* TargetInfoBufferOffset (4 bytes) */ + ntlm_read_message_fields(s, &(message.TargetInfo)); /* only present if NTLMSSP_NEGOTIATE_VERSION is set */ @@ -466,8 +492,10 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu ZeroMemory(&message, sizeof(message)); s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer); - StreamWrite(s, NTLM_SIGNATURE, 8); /* Signature (8 bytes) */ - StreamWrite_UINT32(s, MESSAGE_TYPE_CHALLENGE); /* MessageType */ + ntlm_populate_message_header((NTLM_MESSAGE_HEADER*) &message, MESSAGE_TYPE_CHALLENGE); + + /* Message Header (12 bytes) */ + ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*) &message); if (context->NegotiateFlags & NTLMSSP_REQUEST_TARGET) { @@ -502,9 +530,7 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu message.TargetInfo.BufferOffset = message.TargetName.BufferOffset + message.TargetName.Len; /* TargetNameFields (8 bytes) */ - StreamWrite_UINT16(s, message.TargetName.Len); /* TargetNameLen (2 bytes) */ - StreamWrite_UINT16(s, message.TargetName.Len); /* TargetNameMaxLen (2 bytes) */ - StreamWrite_UINT32(s, message.TargetName.BufferOffset); /* TargetNameBufferOffset (4 bytes) */ + ntlm_write_message_fields(s, &(message.TargetName)); StreamWrite_UINT32(s, context->NegotiateFlags); /* NegotiateFlags (4 bytes) */ @@ -512,9 +538,7 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu StreamZero(s, 8); /* Reserved (8 bytes), should be ignored */ /* TargetInfoFields (8 bytes) */ - StreamWrite_UINT16(s, message.TargetInfo.Len); /* TargetInfoLen (2 bytes) */ - StreamWrite_UINT16(s, message.TargetInfo.Len); /* TargetInfoMaxLen (2 bytes) */ - StreamWrite_UINT32(s, message.TargetInfo.BufferOffset); /* TargetInfoBufferOffset (4 bytes) */ + ntlm_write_message_fields(s, &(message.TargetInfo)); /* only present if NTLMSSP_NEGOTIATE_VERSION is set */ @@ -574,55 +598,35 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer ZeroMemory(&message, sizeof(message)); s = PStreamAllocAttach(buffer->pvBuffer, buffer->cbBuffer); - StreamRead(s, message.Signature, 8); - StreamRead_UINT32(s, message.MessageType); + ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*) &message); - if (memcmp(message.Signature, NTLM_SIGNATURE, 8) != 0) - { - printf("Unexpected NTLM signature: %s, expected:%s\n", message.Signature, NTLM_SIGNATURE); - PStreamFreeDetach(s); - return SEC_E_INVALID_TOKEN; - } - - if (message.MessageType != MESSAGE_TYPE_AUTHENTICATE) + if (!ntlm_validate_message_header(s, (NTLM_MESSAGE_HEADER*) &message, MESSAGE_TYPE_AUTHENTICATE)) { PStreamFreeDetach(s); return SEC_E_INVALID_TOKEN; } /* LmChallengeResponseFields (8 bytes) */ - StreamRead_UINT16(s, message.LmChallengeResponse.Len); /* LmChallengeResponseLen */ - StreamRead_UINT16(s, message.LmChallengeResponse.MaxLen); /* LmChallengeResponseMaxLen */ - StreamRead_UINT32(s, message.LmChallengeResponse.BufferOffset); /* LmChallengeResponseBufferOffset */ + ntlm_read_message_fields(s, &(message.LmChallengeResponse)); /* NtChallengeResponseFields (8 bytes) */ - StreamRead_UINT16(s, message.NtChallengeResponse.Len); /* NtChallengeResponseLen */ - StreamRead_UINT16(s, message.NtChallengeResponse.MaxLen); /* NtChallengeResponseMaxLen */ - StreamRead_UINT32(s, message.NtChallengeResponse.BufferOffset); /* NtChallengeResponseBufferOffset */ + ntlm_read_message_fields(s, &(message.NtChallengeResponse)); /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ /* DomainNameFields (8 bytes) */ - StreamRead_UINT16(s, message.DomainName.Len); /* DomainNameLen */ - StreamRead_UINT16(s, message.DomainName.MaxLen); /* DomainNameMaxLen */ - StreamRead_UINT32(s, message.DomainName.BufferOffset); /* DomainNameBufferOffset */ + ntlm_read_message_fields(s, &(message.DomainName)); /* UserNameFields (8 bytes) */ - StreamRead_UINT16(s, message.UserName.Len); /* UserNameLen */ - StreamRead_UINT16(s, message.UserName.MaxLen); /* UserNameMaxLen */ - StreamRead_UINT32(s, message.UserName.BufferOffset); /* UserNameBufferOffset */ + ntlm_read_message_fields(s, &(message.UserName)); /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ /* WorkstationFields (8 bytes) */ - StreamRead_UINT16(s, message.Workstation.Len); /* WorkstationLen */ - StreamRead_UINT16(s, message.Workstation.MaxLen); /* WorkstationMaxLen */ - StreamRead_UINT32(s, message.Workstation.BufferOffset); /* WorkstationBufferOffset */ + ntlm_read_message_fields(s, &(message.Workstation)); /* EncryptedRandomSessionKeyFields (8 bytes) */ - StreamRead_UINT16(s, message.EncryptedRandomSessionKey.Len); /* EncryptedRandomSessionKeyLen */ - StreamRead_UINT16(s, message.EncryptedRandomSessionKey.MaxLen); /* EncryptedRandomSessionKeyMaxLen */ - StreamRead_UINT32(s, message.EncryptedRandomSessionKey.BufferOffset); /* EncryptedRandomSessionKeyBufferOffset */ + ntlm_read_message_fields(s, &(message.EncryptedRandomSessionKey)); StreamRead_UINT32(s, message.NegotiateFlags); /* NegotiateFlags (4 bytes) */ @@ -900,42 +904,32 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer message.NtChallengeResponse.BufferOffset = message.LmChallengeResponse.BufferOffset + message.LmChallengeResponse.Len; message.EncryptedRandomSessionKey.BufferOffset = message.NtChallengeResponse.BufferOffset + message.NtChallengeResponse.Len; - StreamWrite(s, NTLM_SIGNATURE, 8); /* Signature (8 bytes) */ - StreamWrite_UINT32(s, MESSAGE_TYPE_AUTHENTICATE); /* MessageType */ + ntlm_populate_message_header((NTLM_MESSAGE_HEADER*) &message, MESSAGE_TYPE_AUTHENTICATE); + + /* Message Header (12 bytes) */ + ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*) &message); /* LmChallengeResponseFields (8 bytes) */ - StreamWrite_UINT16(s, message.LmChallengeResponse.Len); /* LmChallengeResponseLen */ - StreamWrite_UINT16(s, message.LmChallengeResponse.Len); /* LmChallengeResponseMaxLen */ - StreamWrite_UINT32(s, message.LmChallengeResponse.BufferOffset); /* LmChallengeResponseBufferOffset */ + ntlm_write_message_fields(s, &(message.LmChallengeResponse)); /* NtChallengeResponseFields (8 bytes) */ - StreamWrite_UINT16(s, message.NtChallengeResponse.Len); /* NtChallengeResponseLen */ - StreamWrite_UINT16(s, message.NtChallengeResponse.Len); /* NtChallengeResponseMaxLen */ - StreamWrite_UINT32(s, message.NtChallengeResponse.BufferOffset); /* NtChallengeResponseBufferOffset */ + ntlm_write_message_fields(s, &(message.NtChallengeResponse)); /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ /* DomainNameFields (8 bytes) */ - StreamWrite_UINT16(s, message.DomainName.Len); /* DomainNameLen */ - StreamWrite_UINT16(s, message.DomainName.Len); /* DomainNameMaxLen */ - StreamWrite_UINT32(s, message.DomainName.BufferOffset); /* DomainNameBufferOffset */ + ntlm_write_message_fields(s, &(message.DomainName)); /* UserNameFields (8 bytes) */ - StreamWrite_UINT16(s, message.UserName.Len); /* UserNameLen */ - StreamWrite_UINT16(s, message.UserName.Len); /* UserNameMaxLen */ - StreamWrite_UINT32(s, message.UserName.BufferOffset); /* UserNameBufferOffset */ + ntlm_write_message_fields(s, &(message.UserName)); /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ /* WorkstationFields (8 bytes) */ - StreamWrite_UINT16(s, message.Workstation.Len); /* WorkstationLen */ - StreamWrite_UINT16(s, message.Workstation.Len); /* WorkstationMaxLen */ - StreamWrite_UINT32(s, message.Workstation.BufferOffset); /* WorkstationBufferOffset */ + ntlm_write_message_fields(s, &(message.Workstation)); /* EncryptedRandomSessionKeyFields (8 bytes) */ - StreamWrite_UINT16(s, message.EncryptedRandomSessionKey.Len); /* EncryptedRandomSessionKeyLen */ - StreamWrite_UINT16(s, message.EncryptedRandomSessionKey.Len); /* EncryptedRandomSessionKeyMaxLen */ - StreamWrite_UINT32(s, message.EncryptedRandomSessionKey.BufferOffset); /* EncryptedRandomSessionKeyBufferOffset */ + ntlm_write_message_fields(s, &(message.EncryptedRandomSessionKey)); StreamWrite_UINT32(s, message.NegotiateFlags); /* NegotiateFlags (4 bytes) */