libfreerdp-sspi: improve server-side NTLM message parsing
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Sun, 18 Mar 2012 22:14:20 +0000 (18:14 -0400)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Sun, 18 Mar 2012 22:14:20 +0000 (18:14 -0400)
libfreerdp-sspi/NTLM/ntlm.c
libfreerdp-sspi/NTLM/ntlm.h
libfreerdp-sspi/NTLM/ntlm_compute.c
libfreerdp-sspi/NTLM/ntlm_compute.h
libfreerdp-sspi/NTLM/ntlm_message.c

index 04fc607..a5d83b1 100644 (file)
@@ -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);
        }
index b26b8be..5ac170a 100644 (file)
@@ -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 */
index 2604829..d0f471e 100644 (file)
@@ -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;
 
@@ -422,6 +422,40 @@ void ntlm_populate_av_pairs(NTLM_CONTEXT* context)
 }
 
 /**
+ * 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}
  * @param NTLM context
index 1d0138f..6bc14f4 100644 (file)
@@ -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);
 
index 820df04..c81e34d 100644 (file)
@@ -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;
+       }
+
+       context->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
 
-       TargetInfoLen = context->TargetInfo.cbBuffer;
-       TargetInfoBuffer = context->TargetInfo.pvBuffer;
+       if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
+       {
+               TargetInfoLen = context->TargetInfo.cbBuffer;
+               TargetInfoBuffer = context->TargetInfo.pvBuffer;
+       }
+       else
+       {
+               TargetInfoLen = 0;
+               TargetInfoBuffer = NULL;
+       }
 
-       TargetNameBufferOffset = 56;
+       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);