diff --git a/libfreerdp-sspi/NTLM/ntlm.c b/libfreerdp-sspi/NTLM/ntlm.c index 04fc6079c..a5d83b159 100644 --- a/libfreerdp-sspi/NTLM/ntlm.c +++ b/libfreerdp-sspi/NTLM/ntlm.c @@ -86,6 +86,13 @@ void ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation) context->WorkstationLength = (uint32) size; } +void ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName) +{ + size_t size; + context->TargetName.pvBuffer = (uint16*) freerdp_uniconv_out(context->uniconv, TargetName, &size); + context->TargetName.cbBuffer = (uint32) size; +} + NTLM_CONTEXT* ntlm_ContextNew() { NTLM_CONTEXT* context; @@ -199,6 +206,8 @@ SECURITY_STATUS ntlm_AcceptSecurityContext(CredHandle* phCredential, CtxtHandle* credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); + ntlm_SetContextTargetName(context, "FreeRDP"); + sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME); } diff --git a/libfreerdp-sspi/NTLM/ntlm.h b/libfreerdp-sspi/NTLM/ntlm.h index b26b8be71..5ac170af0 100644 --- a/libfreerdp-sspi/NTLM/ntlm.h +++ b/libfreerdp-sspi/NTLM/ntlm.h @@ -115,6 +115,8 @@ typedef struct _NTLM_CONTEXT NTLM_CONTEXT; NTLM_CONTEXT* ntlm_ContextNew(); void ntlm_ContextFree(NTLM_CONTEXT* context); -//#define WITH_DEBUG_NTLM 1 +#ifdef WITH_DEBUG_NLA +#define WITH_DEBUG_NTLM +#endif #endif /* FREERDP_SSPI_NTLM_PRIVATE_H */ diff --git a/libfreerdp-sspi/NTLM/ntlm_compute.c b/libfreerdp-sspi/NTLM/ntlm_compute.c index 260482937..d0f471e13 100644 --- a/libfreerdp-sspi/NTLM/ntlm_compute.c +++ b/libfreerdp-sspi/NTLM/ntlm_compute.c @@ -383,7 +383,7 @@ int ntlm_compute_av_pairs_length(NTLM_CONTEXT* context) length += av_pairs->ChannelBindings.length + 4; if (av_pairs->TargetName.length > 0) - length += av_pairs->TargetName.length + 4; + length += av_pairs->TargetName.length + 4; length += 4; @@ -421,6 +421,40 @@ void ntlm_populate_av_pairs(NTLM_CONTEXT* context) ntlm_output_av_pairs(context, &context->TargetInfo); } +/** + * Populate array of AV_PAIRs (server).\n + * AV_PAIR @msdn{cc236646} + * @param NTLM context + */ + +char* test_NbDomainName = "FREERDP"; +char* test_NbComputerName = "FREERDP"; +char* test_DnsDomainName = "FreeRDP"; +char* test_DnsComputerName = "FreeRDP"; + +void ntlm_populate_server_av_pairs(NTLM_CONTEXT* context) +{ + int length; + size_t size; + AV_PAIRS* av_pairs = context->av_pairs; + + av_pairs->NbDomainName.value = (uint8*) freerdp_uniconv_out(context->uniconv, test_NbDomainName, &size); + av_pairs->NbDomainName.length = (uint16) size; + + av_pairs->NbComputerName.value = (uint8*) freerdp_uniconv_out(context->uniconv, test_NbComputerName, &size); + av_pairs->NbComputerName.length = (uint16) size; + + av_pairs->DnsDomainName.value = (uint8*) freerdp_uniconv_out(context->uniconv, test_DnsDomainName, &size); + av_pairs->DnsDomainName.length = (uint16) size; + + av_pairs->DnsComputerName.value = (uint8*) freerdp_uniconv_out(context->uniconv, test_DnsComputerName, &size); + av_pairs->DnsComputerName.length = (uint16) size; + + length = ntlm_compute_av_pairs_length(context) + 4; + sspi_SecBufferAlloc(&context->TargetInfo, length); + ntlm_output_av_pairs(context, &context->TargetInfo); +} + /** * Print array of AV_PAIRs.\n * AV_PAIR @msdn{cc236646} diff --git a/libfreerdp-sspi/NTLM/ntlm_compute.h b/libfreerdp-sspi/NTLM/ntlm_compute.h index 1d0138f04..6bc14f417 100644 --- a/libfreerdp-sspi/NTLM/ntlm_compute.h +++ b/libfreerdp-sspi/NTLM/ntlm_compute.h @@ -29,6 +29,7 @@ void ntlm_output_channel_bindings(NTLM_CONTEXT* context); void ntlm_input_av_pairs(NTLM_CONTEXT* context, STREAM* s); void ntlm_output_av_pairs(NTLM_CONTEXT* context, SecBuffer* buffer); void ntlm_populate_av_pairs(NTLM_CONTEXT* context); +void ntlm_populate_server_av_pairs(NTLM_CONTEXT* context); void ntlm_print_av_pairs(NTLM_CONTEXT* context); void ntlm_free_av_pairs(NTLM_CONTEXT* context); diff --git a/libfreerdp-sspi/NTLM/ntlm_message.c b/libfreerdp-sspi/NTLM/ntlm_message.c index 820df04d9..c81e34da1 100644 --- a/libfreerdp-sspi/NTLM/ntlm_message.c +++ b/libfreerdp-sspi/NTLM/ntlm_message.c @@ -327,6 +327,8 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* buf uint16 TargetInfoMaxLen; uint32 TargetInfoBufferOffset; + ntlm_generate_client_challenge(context); + s = stream_new(0); stream_attach(s, buffer->pvBuffer, buffer->cbBuffer); @@ -499,6 +501,7 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* bu { STREAM* s; int length; + uint32 PayloadOffset; uint16 TargetNameLen; uint8* TargetNameBuffer; uint32 TargetNameBufferOffset; @@ -506,19 +509,51 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* bu uint8* TargetInfoBuffer; uint32 TargetInfoBufferOffset; + /* Server Challenge */ + ntlm_generate_server_challenge(context); + + /* Timestamp */ + ntlm_generate_timestamp(context); + + /* TargetInfo */ + ntlm_populate_server_av_pairs(context); + s = stream_new(0); stream_attach(s, buffer->pvBuffer, buffer->cbBuffer); stream_write(s, NTLM_SIGNATURE, 8); /* Signature (8 bytes) */ stream_write_uint32(s, MESSAGE_TYPE_CHALLENGE); /* MessageType */ - TargetNameLen = context->TargetName.cbBuffer; - TargetNameBuffer = context->TargetName.pvBuffer; + if (context->NegotiateFlags & NTLMSSP_REQUEST_TARGET) + { + TargetNameLen = context->TargetName.cbBuffer; + TargetNameBuffer = context->TargetName.pvBuffer; + } + else + { + TargetNameLen = 0; + TargetNameBuffer = NULL; + } - TargetInfoLen = context->TargetInfo.cbBuffer; - TargetInfoBuffer = context->TargetInfo.pvBuffer; + context->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO; - TargetNameBufferOffset = 56; + if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO) + { + TargetInfoLen = context->TargetInfo.cbBuffer; + TargetInfoBuffer = context->TargetInfo.pvBuffer; + } + else + { + TargetInfoLen = 0; + TargetInfoBuffer = NULL; + } + + PayloadOffset = 48; + + if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + PayloadOffset += 8; + + TargetNameBufferOffset = PayloadOffset; TargetInfoBufferOffset = TargetNameBufferOffset + TargetNameLen; /* TargetNameFields (8 bytes) */ @@ -577,6 +612,15 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* bu printf("\n"); #endif + /* Initialize RC4 seal state */ + ntlm_init_rc4_seal_states(context); + +#ifdef WITH_DEBUG_NTLM + printf("ServerChallenge\n"); + freerdp_hexdump(context->ServerChallenge, 8); + printf("\n"); +#endif + context->state = NTLM_STATE_AUTHENTICATE; stream_detach(s); @@ -594,21 +638,27 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer* uint32 NegotiateFlags; uint16 DomainNameLen; uint16 DomainNameMaxLen; + uint8* DomainNameBuffer; uint32 DomainNameBufferOffset; uint16 UserNameLen; uint16 UserNameMaxLen; + uint8* UserNameBuffer; uint32 UserNameBufferOffset; uint16 WorkstationLen; uint16 WorkstationMaxLen; + uint8* WorkstationBuffer; uint32 WorkstationBufferOffset; uint16 LmChallengeResponseLen; uint16 LmChallengeResponseMaxLen; + uint8* LmChallengeResponseBuffer; uint32 LmChallengeResponseBufferOffset; uint16 NtChallengeResponseLen; uint16 NtChallengeResponseMaxLen; + uint8* NtChallengeResponseBuffer; uint32 NtChallengeResponseBufferOffset; uint16 EncryptedRandomSessionKeyLen; uint16 EncryptedRandomSessionKeyMaxLen; + uint8* EncryptedRandomSessionKeyBuffer; uint32 EncryptedRandomSessionKeyBufferOffset; s = stream_new(0); @@ -665,6 +715,13 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer* if (NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) { /* Only present if NTLMSSP_NEGOTIATE_VERSION is set */ + +#ifdef WITH_DEBUG_NTLM + printf("Version (length = 8)\n"); + freerdp_hexdump(s->p, 8); + printf("\n"); +#endif + stream_seek(s, 8); /* Version (8 bytes) */ } @@ -679,6 +736,72 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer* printf("\n"); #endif + /* DomainName */ + if (DomainNameLen > 0) + { + DomainNameBuffer = s->data + DomainNameBufferOffset; +#ifdef WITH_DEBUG_NTLM + printf("DomainName (length = %d, offset = %d)\n", DomainNameLen, DomainNameBufferOffset); + freerdp_hexdump(DomainNameBuffer, DomainNameLen); + printf("\n"); +#endif + } + + /* UserName */ + if (UserNameLen > 0) + { + UserNameBuffer = s->data + UserNameBufferOffset; +#ifdef WITH_DEBUG_NTLM + printf("UserName (length = %d, offset = %d)\n", UserNameLen, UserNameBufferOffset); + freerdp_hexdump(UserNameBuffer, UserNameLen); + printf("\n"); +#endif + } + + /* Workstation */ + if (WorkstationLen > 0) + { + WorkstationBuffer = s->data + WorkstationBufferOffset; +#ifdef WITH_DEBUG_NTLM + printf("Workstation (length = %d, offset = %d)\n", WorkstationLen, WorkstationBufferOffset); + freerdp_hexdump(WorkstationBuffer, WorkstationLen); + printf("\n"); +#endif + } + + /* LmChallengeResponse */ + if (LmChallengeResponseLen > 0) + { + LmChallengeResponseBuffer = s->data + LmChallengeResponseBufferOffset; +#ifdef WITH_DEBUG_NTLM + printf("LmChallengeResponse (length = %d, offset = %d)\n", LmChallengeResponseLen, LmChallengeResponseBufferOffset); + freerdp_hexdump(LmChallengeResponseBuffer, LmChallengeResponseLen); + printf("\n"); +#endif + } + + /* NtChallengeResponse */ + if (NtChallengeResponseLen > 0) + { + NtChallengeResponseBuffer = s->data + NtChallengeResponseBufferOffset; +#ifdef WITH_DEBUG_NTLM + printf("NtChallengeResponse (length = %d, offset = %d)\n", NtChallengeResponseLen, NtChallengeResponseBufferOffset); + freerdp_hexdump(NtChallengeResponseBuffer, NtChallengeResponseLen); + printf("\n"); +#endif + } + + /* EncryptedRandomSessionKey */ + if (EncryptedRandomSessionKeyLen > 0) + { + EncryptedRandomSessionKeyBuffer = s->data + EncryptedRandomSessionKeyBufferOffset; +#ifdef WITH_DEBUG_NTLM + printf("EncryptedRandomSessionKey (length = %d, offset = %d)\n", EncryptedRandomSessionKeyLen, EncryptedRandomSessionKeyBufferOffset); + freerdp_hexdump(EncryptedRandomSessionKeyBuffer, EncryptedRandomSessionKeyLen); + printf("\n"); +#endif + } + context->state = NTLM_STATE_FINAL; stream_detach(s);