FreeRDP/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c
2012-08-14 17:20:53 -04:00

370 lines
9.4 KiB
C

/**
* WinPR: Windows Portable Runtime
* NTLM Security Package (AV_PAIRs)
*
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ntlm.h"
#include "../sspi.h"
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/sysinfo.h>
#include "ntlm_compute.h"
#include "ntlm_av_pairs.h"
const char* const AV_PAIR_STRINGS[] =
{
"MsvAvEOL",
"MsvAvNbComputerName",
"MsvAvNbDomainName",
"MsvAvDnsComputerName",
"MsvAvDnsDomainName",
"MsvAvDnsTreeName",
"MsvAvFlags",
"MsvAvTimestamp",
"MsvAvRestrictions",
"MsvAvTargetName",
"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_length(NTLM_AV_PAIR* pAvPairList)
{
ULONG length;
NTLM_AV_PAIR* pAvPair = pAvPairList;
if (!pAvPair)
return 0;
while (pAvPair->AvId != MsvAvEOL)
{
pAvPair = ntlm_av_pair_get_next_pointer(pAvPair);
}
length = (pAvPair - pAvPairList) + sizeof(NTLM_AV_PAIR);
return length;
}
void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList)
{
NTLM_AV_PAIR* pAvPair = pAvPairList;
if (!pAvPair)
return;
printf("AV_PAIRs =\n{\n");
while (pAvPair->AvId != MsvAvEOL)
{
printf("\t%s AvId: %d AvLen: %d\n",
AV_PAIR_STRINGS[pAvPair->AvId],
pAvPair->AvId, pAvPair->AvLen);
winpr_HexDump(ntlm_av_pair_get_value_pointer(pAvPair), pAvPair->AvLen);
pAvPair = ntlm_av_pair_get_next_pointer(pAvPair);
}
printf("}\n");
}
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, NTLM_AV_ID AvId)
{
NTLM_AV_PAIR* pAvPair = pAvPairList;
if (!pAvPair)
return NULL;
while (1)
{
if (pAvPair->AvId == AvId)
return pAvPair;
if (pAvPair->AvId == MsvAvEOL)
return NULL;
pAvPair = ntlm_av_pair_get_next_pointer(pAvPair);
}
return NULL;
}
NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId, PBYTE Value, UINT16 AvLen)
{
NTLM_AV_PAIR* pAvPair;
pAvPair = ntlm_av_pair_get(pAvPairList, MsvAvEOL);
if (!pAvPair)
return NULL;
pAvPair->AvId = AvId;
pAvPair->AvLen = AvLen;
CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen);
return pAvPair;
}
NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, NTLM_AV_PAIR* pAvPair)
{
NTLM_AV_PAIR* pAvPairCopy;
pAvPairCopy = ntlm_av_pair_get(pAvPairList, MsvAvEOL);
if (!pAvPairCopy)
return NULL;
pAvPairCopy->AvId = pAvPair->AvId;
pAvPairCopy->AvLen = pAvPair->AvLen;
CopyMemory(ntlm_av_pair_get_value_pointer(pAvPairCopy),
ntlm_av_pair_get_value_pointer(pAvPair), pAvPair->AvLen);
return pAvPairCopy;
}
void ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
{
char* name;
DWORD nSize = 0;
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_challenge_target_info(NTLM_CONTEXT* context)
{
int length;
ULONG AvPairsCount;
ULONG AvPairsLength;
LONG AvPairListSize;
NTLM_AV_PAIR* pAvPairList;
UNICODE_STRING NbDomainName;
UNICODE_STRING NbComputerName;
UNICODE_STRING DnsDomainName;
UNICODE_STRING DnsComputerName;
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);
AvPairsCount = 5;
AvPairsLength = NbDomainName.Length + NbComputerName.Length +
DnsDomainName.Length + DnsComputerName.Length + 8;
length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength);
sspi_SecBufferAlloc(&context->ChallengeTargetInfo, length);
pAvPairList = (NTLM_AV_PAIR*) context->ChallengeTargetInfo.pvBuffer;
AvPairListSize = (ULONG) context->ChallengeTargetInfo.cbBuffer;
ntlm_av_pair_list_init(pAvPairList);
ntlm_av_pair_add(pAvPairList, MsvAvNbDomainName, (PBYTE) NbDomainName.Buffer, NbDomainName.Length);
ntlm_av_pair_add(pAvPairList, MsvAvNbComputerName, (PBYTE) NbComputerName.Buffer, NbComputerName.Length);
ntlm_av_pair_add(pAvPairList, MsvAvDnsDomainName, (PBYTE) DnsDomainName.Buffer, DnsDomainName.Length);
ntlm_av_pair_add(pAvPairList, MsvAvDnsComputerName, (PBYTE) DnsComputerName.Buffer, DnsComputerName.Length);
ntlm_av_pair_add(pAvPairList, MsvAvTimestamp, context->Timestamp, sizeof(context->Timestamp));
}
void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
{
ULONG size;
ULONG AvPairsCount;
ULONG AvPairsValueLength;
NTLM_AV_PAIR* AvTimestamp;
NTLM_AV_PAIR* AvNbDomainName;
NTLM_AV_PAIR* AvNbComputerName;
NTLM_AV_PAIR* AvDnsDomainName;
NTLM_AV_PAIR* AvDnsComputerName;
NTLM_AV_PAIR* AvDnsTreeName;
NTLM_AV_PAIR* ChallengeTargetInfo;
NTLM_AV_PAIR* AuthenticateTargetInfo;
AvPairsCount = AvPairsValueLength = 0;
ChallengeTargetInfo = (NTLM_AV_PAIR*) context->ChallengeTargetInfo.pvBuffer;
AvNbDomainName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvNbDomainName);
AvNbComputerName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvNbComputerName);
AvDnsDomainName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvDnsDomainName);
AvDnsComputerName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvDnsComputerName);
AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvDnsTreeName);
AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvTimestamp);
if (AvNbDomainName != NULL)
{
AvPairsCount++; /* MsvAvNbDomainName */
AvPairsValueLength += AvNbDomainName->AvLen;
}
if (AvNbComputerName != NULL)
{
AvPairsCount++; /* MsvAvNbComputerName */
AvPairsValueLength += AvNbComputerName->AvLen;
}
if (AvDnsDomainName != NULL)
{
AvPairsCount++; /* MsvAvDnsDomainName */
AvPairsValueLength += AvDnsDomainName->AvLen;
}
if (AvDnsComputerName != NULL)
{
AvPairsCount++; /* MsvAvDnsComputerName */
AvPairsValueLength += AvDnsComputerName->AvLen;
}
if (AvDnsTreeName != NULL)
{
AvPairsCount++; /* MsvAvDnsTreeName */
AvPairsValueLength += AvDnsTreeName->AvLen;
}
AvPairsCount++; /* MsvAvTimestamp */
AvPairsValueLength += 8;
if (context->UseMIC)
{
AvPairsCount++; /* MsvAvFlags */
AvPairsValueLength += 4;
}
//AvPairsCount++; /* MsvAvRestrictions */
//AvPairsValueLength += 48;
if (!context->SuppressExtendedProtection)
{
AvPairsCount++; /* MsvChannelBindings */
AvPairsValueLength += 16;
if (context->ServicePrincipalName.Length > 0)
{
AvPairsCount++; /* MsvAvTargetName */
AvPairsValueLength += context->ServicePrincipalName.Length;
}
}
size = ntlm_av_pair_list_size(AvPairsCount, AvPairsValueLength);
if (context->NTLMv2)
size += 8; /* unknown 8-byte padding */
sspi_SecBufferAlloc(&context->AuthenticateTargetInfo, size);
AuthenticateTargetInfo = (NTLM_AV_PAIR*) context->AuthenticateTargetInfo.pvBuffer;
ntlm_av_pair_list_init(AuthenticateTargetInfo);
if (AvNbDomainName != NULL)
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvNbDomainName);
if (AvNbComputerName != NULL)
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvNbComputerName);
if (AvDnsDomainName != NULL)
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsDomainName);
if (AvDnsComputerName != NULL)
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsComputerName);
if (AvDnsTreeName != NULL)
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsTreeName);
if (AvTimestamp != NULL)
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvTimestamp);
if (context->UseMIC)
{
UINT32 flags = MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK;
ntlm_av_pair_add(AuthenticateTargetInfo, MsvAvFlags, (PBYTE) &flags, 4);
}
if (!context->SuppressExtendedProtection)
{
BYTE ChannelBindingToken[16];
ZeroMemory(ChannelBindingToken, 16);
ntlm_av_pair_add(AuthenticateTargetInfo, MsvChannelBindings,
ChannelBindingToken, sizeof(ChannelBindingToken));
if (context->ServicePrincipalName.Length > 0)
{
ntlm_av_pair_add(AuthenticateTargetInfo, MsvAvTargetName,
(PBYTE) context->ServicePrincipalName.Buffer,
context->ServicePrincipalName.Length);
}
}
if (context->NTLMv2)
{
NTLM_AV_PAIR* AvEOL;
AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvEOL);
ZeroMemory((void*) AvEOL, 4);
}
}