Blame winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c

Packit Service fa4841
/**
Packit Service fa4841
 * WinPR: Windows Portable Runtime
Packit Service fa4841
 * NTLM Security Package (AV_PAIRs)
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <assert.h>
Packit Service fa4841
Packit Service fa4841
#include "ntlm.h"
Packit Service fa4841
#include "../sspi.h"
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/print.h>
Packit Service fa4841
#include <winpr/sysinfo.h>
Packit Service fa4841
#include <winpr/tchar.h>
Packit Service fa4841
#include <winpr/crypto.h>
Packit Service fa4841
Packit Service fa4841
#include "ntlm_compute.h"
Packit Service fa4841
Packit Service fa4841
#include "ntlm_av_pairs.h"
Packit Service fa4841
Packit Service fa4841
#include "../../log.h"
Packit Service fa4841
#define TAG WINPR_TAG("sspi.NTLM")
Packit Service fa4841
Packit Service fa4841
static BOOL ntlm_av_pair_get_next_offset(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pOffset);
Packit Service fa4841
Packit Service fa4841
static BOOL ntlm_av_pair_check_data(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair, size_t size)
Packit Service fa4841
{
Packit Service fa4841
	size_t offset;
Packit Service fa4841
	if (!pAvPair || cbAvPair < sizeof(NTLM_AV_PAIR) + size)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	if (!ntlm_av_pair_get_next_offset(pAvPair, cbAvPair, &offset))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	return cbAvPair >= offset;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static const char* get_av_pair_string(UINT16 pair)
Packit Service fa4841
{
Packit Service fa4841
	switch (pair)
Packit Service fa4841
	{
Packit Service fa4841
		case MsvAvEOL:
Packit Service fa4841
			return "MsvAvEOL";
Packit Service fa4841
		case MsvAvNbComputerName:
Packit Service fa4841
			return "MsvAvNbComputerName";
Packit Service fa4841
		case MsvAvNbDomainName:
Packit Service fa4841
			return "MsvAvNbDomainName";
Packit Service fa4841
		case MsvAvDnsComputerName:
Packit Service fa4841
			return "MsvAvDnsComputerName";
Packit Service fa4841
		case MsvAvDnsDomainName:
Packit Service fa4841
			return "MsvAvDnsDomainName";
Packit Service fa4841
		case MsvAvDnsTreeName:
Packit Service fa4841
			return "MsvAvDnsTreeName";
Packit Service fa4841
		case MsvAvFlags:
Packit Service fa4841
			return "MsvAvFlags";
Packit Service fa4841
		case MsvAvTimestamp:
Packit Service fa4841
			return "MsvAvTimestamp";
Packit Service fa4841
		case MsvAvSingleHost:
Packit Service fa4841
			return "MsvAvSingleHost";
Packit Service fa4841
		case MsvAvTargetName:
Packit Service fa4841
			return "MsvAvTargetName";
Packit Service fa4841
		case MsvChannelBindings:
Packit Service fa4841
			return "MsvChannelBindings";
Packit Service fa4841
		default:
Packit Service fa4841
			return "UNKNOWN";
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair);
Packit Service fa4841
static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPairList, size_t* pcbAvPairList);
Packit Service fa4841
Packit Service fa4841
static INLINE void ntlm_av_pair_set_id(NTLM_AV_PAIR* pAvPair, UINT16 id)
Packit Service fa4841
{
Packit Service fa4841
	Data_Write_UINT16(&pAvPair->AvId, id);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static INLINE void ntlm_av_pair_set_len(NTLM_AV_PAIR* pAvPair, UINT16 len)
Packit Service fa4841
{
Packit Service fa4841
	Data_Write_UINT16(&pAvPair->AvLen, len);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL ntlm_av_pair_list_init(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
Packit Service fa4841
{
Packit Service fa4841
	NTLM_AV_PAIR* pAvPair = pAvPairList;
Packit Service fa4841
Packit Service fa4841
	if (!pAvPair || (cbAvPairList < sizeof(NTLM_AV_PAIR)))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	ntlm_av_pair_set_id(pAvPair, MsvAvEOL);
Packit Service fa4841
	ntlm_av_pair_set_len(pAvPair, 0);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static INLINE BOOL ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair, size_t size, UINT16* pair)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 AvId;
Packit Service fa4841
	if (!pAvPair || !pair)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (size < sizeof(NTLM_AV_PAIR))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Data_Read_UINT16(&pAvPair->AvId, AvId);
Packit Service fa4841
Packit Service fa4841
	*pair = AvId;
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
Packit Service fa4841
{
Packit Service fa4841
	size_t cbAvPair;
Packit Service fa4841
	NTLM_AV_PAIR* pAvPair;
Packit Service fa4841
Packit Service fa4841
	pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
Packit Service fa4841
	if (!pAvPair)
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	return ((PBYTE)pAvPair - (PBYTE)pAvPairList) + sizeof(NTLM_AV_PAIR);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pAvLen)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 AvLen;
Packit Service fa4841
	if (!pAvPair)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (size < sizeof(NTLM_AV_PAIR))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Data_Read_UINT16(&pAvPair->AvLen, AvLen);
Packit Service fa4841
Packit Service fa4841
	*pAvLen = AvLen;
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 pair;
Packit Service fa4841
	size_t cbAvPair = cbAvPairList;
Packit Service fa4841
	NTLM_AV_PAIR* pAvPair = pAvPairList;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_check(pAvPair, cbAvPair))
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	WLog_INFO(TAG, "AV_PAIRs =");
Packit Service fa4841
Packit Service fa4841
	while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL))
Packit Service fa4841
	{
Packit Service fa4841
		size_t cbLen = 0;
Packit Service fa4841
		ntlm_av_pair_get_len(pAvPair, cbAvPair, &cbLen);
Packit Service fa4841
Packit Service fa4841
		WLog_INFO(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair);
Packit Service fa4841
		winpr_HexDump(TAG, WLOG_INFO, ntlm_av_pair_get_value_pointer(pAvPair), cbLen);
Packit Service fa4841
Packit Service fa4841
		pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength)
Packit Service fa4841
{
Packit Service fa4841
	/* size of headers + value lengths + terminating MsvAvEOL AV_PAIR */
Packit Service fa4841
	return ((AvPairsCount + 1) * 4) + AvPairsValueLength;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair)
Packit Service fa4841
{
Packit Service fa4841
	return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL ntlm_av_pair_get_next_offset(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pOffset)
Packit Service fa4841
{
Packit Service fa4841
	size_t avLen;
Packit Service fa4841
	if (!pOffset)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_get_len(pAvPair, size, &avLen))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	*pOffset = avLen + sizeof(NTLM_AV_PAIR);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
Packit Service fa4841
{
Packit Service fa4841
	return ntlm_av_pair_check_data(pAvPair, cbAvPair, 0);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPair, size_t* pcbAvPair)
Packit Service fa4841
{
Packit Service fa4841
	size_t offset;
Packit Service fa4841
Packit Service fa4841
	if (!pcbAvPair)
Packit Service fa4841
		return NULL;
Packit Service fa4841
	if (!ntlm_av_pair_check(pAvPair, *pcbAvPair))
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_get_next_offset(pAvPair, *pcbAvPair, &offset))
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	*pcbAvPair -= offset;
Packit Service fa4841
	return (NTLM_AV_PAIR*)((PBYTE)pAvPair + offset);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
Packit Service fa4841
                               size_t* pcbAvPairListRemaining)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 id;
Packit Service fa4841
	size_t cbAvPair = cbAvPairList;
Packit Service fa4841
	NTLM_AV_PAIR* pAvPair = pAvPairList;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_check(pAvPair, cbAvPair))
Packit Service fa4841
		pAvPair = NULL;
Packit Service fa4841
Packit Service fa4841
	while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &id))
Packit Service fa4841
	{
Packit Service fa4841
		if (id == AvId)
Packit Service fa4841
			break;
Packit Service fa4841
		if (id == MsvAvEOL)
Packit Service fa4841
		{
Packit Service fa4841
			pAvPair = NULL;
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!pAvPair)
Packit Service fa4841
		cbAvPair = 0;
Packit Service fa4841
	if (pcbAvPairListRemaining)
Packit Service fa4841
		*pcbAvPairListRemaining = cbAvPair;
Packit Service fa4841
Packit Service fa4841
	return pAvPair;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
Packit Service fa4841
                             PBYTE Value, UINT16 AvLen)
Packit Service fa4841
{
Packit Service fa4841
	size_t cbAvPair;
Packit Service fa4841
	NTLM_AV_PAIR* pAvPair;
Packit Service fa4841
Packit Service fa4841
	pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
Packit Service fa4841
Packit Service fa4841
	/* size of header + value length + terminating MsvAvEOL AV_PAIR */
Packit Service fa4841
	if (!pAvPair || cbAvPair < 2 * sizeof(NTLM_AV_PAIR) + AvLen)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	ntlm_av_pair_set_id(pAvPair, AvId);
Packit Service fa4841
	ntlm_av_pair_set_len(pAvPair, AvLen);
Packit Service fa4841
	if (AvLen)
Packit Service fa4841
	{
Packit Service fa4841
		assert(Value != NULL);
Packit Service fa4841
		CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
Packit Service fa4841
	return ntlm_av_pair_list_init(pAvPair, cbAvPair);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList,
Packit Service fa4841
                                  NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 pair;
Packit Service fa4841
	size_t avLen;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_check(pAvPair, cbAvPair))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	return ntlm_av_pair_add(pAvPairList, cbAvPairList, pair,
Packit Service fa4841
	                        ntlm_av_pair_get_value_pointer(pAvPair), avLen);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
Packit Service fa4841
{
Packit Service fa4841
	char* name;
Packit Service fa4841
	int status;
Packit Service fa4841
	DWORD nSize = 0;
Packit Service fa4841
	CHAR* computerName;
Packit Service fa4841
Packit Service fa4841
	if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || GetLastError() != ERROR_MORE_DATA)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	computerName = calloc(nSize, sizeof(CHAR));
Packit Service fa4841
Packit Service fa4841
	if (!computerName)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (!GetComputerNameExA(ComputerNameNetBIOS, computerName, &nSize))
Packit Service fa4841
	{
Packit Service fa4841
		free(computerName);
Packit Service fa4841
		return -1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (nSize > MAX_COMPUTERNAME_LENGTH)
Packit Service fa4841
		computerName[MAX_COMPUTERNAME_LENGTH] = '\0';
Packit Service fa4841
Packit Service fa4841
	name = computerName;
Packit Service fa4841
Packit Service fa4841
	if (!name)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (type == ComputerNameNetBIOS)
Packit Service fa4841
		CharUpperA(name);
Packit Service fa4841
Packit Service fa4841
	status = ConvertToUnicode(CP_UTF8, 0, name, -1, &pName->Buffer, 0);
Packit Service fa4841
Packit Service fa4841
	if (status <= 0)
Packit Service fa4841
	{
Packit Service fa4841
		free(name);
Packit Service fa4841
		return status;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	pName->Length = (USHORT)((status - 1) * 2);
Packit Service fa4841
	pName->MaximumLength = pName->Length;
Packit Service fa4841
	free(name);
Packit Service fa4841
	return 1;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void ntlm_free_unicode_string(PUNICODE_STRING string)
Packit Service fa4841
{
Packit Service fa4841
	if (string)
Packit Service fa4841
	{
Packit Service fa4841
		if (string->Length > 0)
Packit Service fa4841
		{
Packit Service fa4841
			free(string->Buffer);
Packit Service fa4841
			string->Buffer = NULL;
Packit Service fa4841
			string->Length = 0;
Packit Service fa4841
			string->MaximumLength = 0;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * From http://www.ietf.org/proceedings/72/slides/sasl-2.pdf:
Packit Service fa4841
 *
Packit Service fa4841
 * tls-server-end-point:
Packit Service fa4841
 *
Packit Service fa4841
 * The hash of the TLS server's end entity certificate as it appears, octet for octet,
Packit Service fa4841
 * in the server's Certificate message (note that the Certificate message contains a
Packit Service fa4841
 * certificate_list, the first element of which is the server's end entity certificate.)
Packit Service fa4841
 * The hash function to be selected is as follows: if the certificate's signature hash
Packit Service fa4841
 * algorithm is either MD5 or SHA-1, then use SHA-256, otherwise use the certificate's
Packit Service fa4841
 * signature hash algorithm.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Channel Bindings sample usage:
Packit Service fa4841
 * https://raw.github.com/mozilla/mozilla-central/master/extensions/auth/nsAuthSSPI.cpp
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
typedef struct gss_channel_bindings_struct {
Packit Service fa4841
    OM_uint32 initiator_addrtype;
Packit Service fa4841
    gss_buffer_desc initiator_address;
Packit Service fa4841
    OM_uint32 acceptor_addrtype;
Packit Service fa4841
    gss_buffer_desc acceptor_address;
Packit Service fa4841
    gss_buffer_desc application_data;
Packit Service fa4841
} *gss_channel_bindings_t;
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
static BOOL ntlm_md5_update_uint32_be(WINPR_DIGEST_CTX* md5, UINT32 num)
Packit Service fa4841
{
Packit Service fa4841
	BYTE be32[4];
Packit Service fa4841
	be32[0] = (num >> 0) & 0xFF;
Packit Service fa4841
	be32[1] = (num >> 8) & 0xFF;
Packit Service fa4841
	be32[2] = (num >> 16) & 0xFF;
Packit Service fa4841
	be32[3] = (num >> 24) & 0xFF;
Packit Service fa4841
	return winpr_Digest_Update(md5, be32, 4);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_DIGEST_CTX* md5;
Packit Service fa4841
	BYTE* ChannelBindingToken;
Packit Service fa4841
	UINT32 ChannelBindingTokenLength;
Packit Service fa4841
	SEC_CHANNEL_BINDINGS* ChannelBindings;
Packit Service fa4841
	ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH);
Packit Service fa4841
	ChannelBindings = context->Bindings.Bindings;
Packit Service fa4841
Packit Service fa4841
	if (!ChannelBindings)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	if (!(md5 = winpr_Digest_New()))
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Init(md5, WINPR_MD_MD5))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	ChannelBindingTokenLength = context->Bindings.BindingsLength - sizeof(SEC_CHANNEL_BINDINGS);
Packit Service fa4841
	ChannelBindingToken = &((BYTE*)ChannelBindings)[ChannelBindings->dwApplicationDataOffset];
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwInitiatorAddrType))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbInitiatorLength))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwAcceptorAddrType))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbAcceptorLength))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbApplicationDataLength))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, (void*)ChannelBindingToken, ChannelBindingTokenLength))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(md5, context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
out:
Packit Service fa4841
	winpr_Digest_Free(md5);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
Packit Service fa4841
{
Packit Service fa4841
	/**
Packit Service fa4841
	 * The Single_Host_Data structure allows a client to send machine-specific information
Packit Service fa4841
	 * within an authentication exchange to services on the same machine. The client can
Packit Service fa4841
	 * produce additional information to be processed in an implementation-specific way when
Packit Service fa4841
	 * the client and server are on the same host. If the server and client platforms are
Packit Service fa4841
	 * different or if they are on different hosts, then the information MUST be ignored.
Packit Service fa4841
	 * Any fields after the MachineID field MUST be ignored on receipt.
Packit Service fa4841
	 */
Packit Service fa4841
	Data_Write_UINT32(&context->SingleHostData.Size, 48);
Packit Service fa4841
	Data_Write_UINT32(&context->SingleHostData.Z4, 0);
Packit Service fa4841
	Data_Write_UINT32(&context->SingleHostData.DataPresent, 1);
Packit Service fa4841
	Data_Write_UINT32(&context->SingleHostData.CustomData, SECURITY_MANDATORY_MEDIUM_RID);
Packit Service fa4841
	FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
Packit Service fa4841
{
Packit Service fa4841
	int rc = -1;
Packit Service fa4841
	int length;
Packit Service fa4841
	ULONG AvPairsCount;
Packit Service fa4841
	ULONG AvPairsLength;
Packit Service fa4841
	NTLM_AV_PAIR* pAvPairList;
Packit Service fa4841
	size_t cbAvPairList;
Packit Service fa4841
	UNICODE_STRING NbDomainName = { 0 };
Packit Service fa4841
	UNICODE_STRING NbComputerName = { 0 };
Packit Service fa4841
	UNICODE_STRING DnsDomainName = { 0 };
Packit Service fa4841
	UNICODE_STRING DnsComputerName = { 0 };
Packit Service fa4841
Packit Service fa4841
	if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	NbComputerName.Buffer = NULL;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS) < 0)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	DnsDomainName.Buffer = NULL;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain) < 0)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	DnsComputerName.Buffer = NULL;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname) < 0)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	AvPairsCount = 5;
Packit Service fa4841
	AvPairsLength = NbDomainName.Length + NbComputerName.Length + DnsDomainName.Length +
Packit Service fa4841
	                DnsComputerName.Length + 8;
Packit Service fa4841
	length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength);
Packit Service fa4841
Packit Service fa4841
	if (!sspi_SecBufferAlloc(&context->ChallengeTargetInfo, length))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	pAvPairList = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
Packit Service fa4841
	cbAvPairList = context->ChallengeTargetInfo.cbBuffer;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_list_init(pAvPairList, cbAvPairList))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbDomainName, (PBYTE)NbDomainName.Buffer,
Packit Service fa4841
	                      NbDomainName.Length))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbComputerName,
Packit Service fa4841
	                      (PBYTE)NbComputerName.Buffer, NbComputerName.Length))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsDomainName,
Packit Service fa4841
	                      (PBYTE)DnsDomainName.Buffer, DnsDomainName.Length))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsComputerName,
Packit Service fa4841
	                      (PBYTE)DnsComputerName.Buffer, DnsComputerName.Length))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvTimestamp, context->Timestamp,
Packit Service fa4841
	                      sizeof(context->Timestamp)))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	rc = 1;
Packit Service fa4841
fail:
Packit Service fa4841
	ntlm_free_unicode_string(&NbDomainName);
Packit Service fa4841
	ntlm_free_unicode_string(&NbComputerName);
Packit Service fa4841
	ntlm_free_unicode_string(&DnsDomainName);
Packit Service fa4841
	ntlm_free_unicode_string(&DnsComputerName);
Packit Service fa4841
	return rc;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
Packit Service fa4841
{
Packit Service fa4841
	ULONG size;
Packit Service fa4841
	ULONG AvPairsCount;
Packit Service fa4841
	ULONG AvPairsValueLength;
Packit Service fa4841
	NTLM_AV_PAIR* AvTimestamp;
Packit Service fa4841
	NTLM_AV_PAIR* AvNbDomainName;
Packit Service fa4841
	NTLM_AV_PAIR* AvNbComputerName;
Packit Service fa4841
	NTLM_AV_PAIR* AvDnsDomainName;
Packit Service fa4841
	NTLM_AV_PAIR* AvDnsComputerName;
Packit Service fa4841
	NTLM_AV_PAIR* AvDnsTreeName;
Packit Service fa4841
	NTLM_AV_PAIR* ChallengeTargetInfo;
Packit Service fa4841
	NTLM_AV_PAIR* AuthenticateTargetInfo;
Packit Service fa4841
	size_t cbAvTimestamp;
Packit Service fa4841
	size_t cbAvNbDomainName;
Packit Service fa4841
	size_t cbAvNbComputerName;
Packit Service fa4841
	size_t cbAvDnsDomainName;
Packit Service fa4841
	size_t cbAvDnsComputerName;
Packit Service fa4841
	size_t cbAvDnsTreeName;
Packit Service fa4841
	size_t cbChallengeTargetInfo;
Packit Service fa4841
	size_t cbAuthenticateTargetInfo;
Packit Service fa4841
	AvPairsCount = 1;
Packit Service fa4841
	AvPairsValueLength = 0;
Packit Service fa4841
	ChallengeTargetInfo = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
Packit Service fa4841
	cbChallengeTargetInfo = context->ChallengeTargetInfo.cbBuffer;
Packit Service fa4841
	AvNbDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvNbDomainName,
Packit Service fa4841
	                                  &cbAvNbDomainName);
Packit Service fa4841
	AvNbComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
Packit Service fa4841
	                                    MsvAvNbComputerName, &cbAvNbComputerName);
Packit Service fa4841
	AvDnsDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
Packit Service fa4841
	                                   MsvAvDnsDomainName, &cbAvDnsDomainName);
Packit Service fa4841
	AvDnsComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
Packit Service fa4841
	                                     MsvAvDnsComputerName, &cbAvDnsComputerName);
Packit Service fa4841
	AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvDnsTreeName,
Packit Service fa4841
	                                 &cbAvDnsTreeName);
Packit Service fa4841
	AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvTimestamp,
Packit Service fa4841
	                               &cbAvTimestamp);
Packit Service fa4841
Packit Service fa4841
	if (AvNbDomainName)
Packit Service fa4841
	{
Packit Service fa4841
		size_t avLen;
Packit Service fa4841
		if (!ntlm_av_pair_get_len(AvNbDomainName, cbAvNbDomainName, &avLen))
Packit Service fa4841
			goto fail;
Packit Service fa4841
		AvPairsCount++; /* MsvAvNbDomainName */
Packit Service fa4841
		AvPairsValueLength += avLen;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (AvNbComputerName)
Packit Service fa4841
	{
Packit Service fa4841
		size_t avLen;
Packit Service fa4841
		if (!ntlm_av_pair_get_len(AvNbComputerName, cbAvNbComputerName, &avLen))
Packit Service fa4841
			goto fail;
Packit Service fa4841
		AvPairsCount++; /* MsvAvNbComputerName */
Packit Service fa4841
		AvPairsValueLength += avLen;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (AvDnsDomainName)
Packit Service fa4841
	{
Packit Service fa4841
		size_t avLen;
Packit Service fa4841
		if (!ntlm_av_pair_get_len(AvDnsDomainName, cbAvDnsDomainName, &avLen))
Packit Service fa4841
			goto fail;
Packit Service fa4841
		AvPairsCount++; /* MsvAvDnsDomainName */
Packit Service fa4841
		AvPairsValueLength += avLen;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (AvDnsComputerName)
Packit Service fa4841
	{
Packit Service fa4841
		size_t avLen;
Packit Service fa4841
		if (!ntlm_av_pair_get_len(AvDnsComputerName, cbAvDnsComputerName, &avLen))
Packit Service fa4841
			goto fail;
Packit Service fa4841
		AvPairsCount++; /* MsvAvDnsComputerName */
Packit Service fa4841
		AvPairsValueLength += avLen;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (AvDnsTreeName)
Packit Service fa4841
	{
Packit Service fa4841
		size_t avLen;
Packit Service fa4841
		if (!ntlm_av_pair_get_len(AvDnsTreeName, cbAvDnsTreeName, &avLen))
Packit Service fa4841
			goto fail;
Packit Service fa4841
		AvPairsCount++; /* MsvAvDnsTreeName */
Packit Service fa4841
		AvPairsValueLength += avLen;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	AvPairsCount++; /* MsvAvTimestamp */
Packit Service fa4841
	AvPairsValueLength += 8;
Packit Service fa4841
Packit Service fa4841
	if (context->UseMIC)
Packit Service fa4841
	{
Packit Service fa4841
		AvPairsCount++; /* MsvAvFlags */
Packit Service fa4841
		AvPairsValueLength += 4;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (context->SendSingleHostData)
Packit Service fa4841
	{
Packit Service fa4841
		AvPairsCount++; /* MsvAvSingleHost */
Packit Service fa4841
		ntlm_compute_single_host_data(context);
Packit Service fa4841
		AvPairsValueLength += context->SingleHostData.Size;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/**
Packit Service fa4841
	 * Extended Protection for Authentication:
Packit Service fa4841
	 * http://blogs.technet.com/b/srd/archive/2009/12/08/extended-protection-for-authentication.aspx
Packit Service fa4841
	 */
Packit Service fa4841
Packit Service fa4841
	if (!context->SuppressExtendedProtection)
Packit Service fa4841
	{
Packit Service fa4841
		/**
Packit Service fa4841
		 * SEC_CHANNEL_BINDINGS structure
Packit Service fa4841
		 * http://msdn.microsoft.com/en-us/library/windows/desktop/dd919963/
Packit Service fa4841
		 */
Packit Service fa4841
		AvPairsCount++; /* MsvChannelBindings */
Packit Service fa4841
		AvPairsValueLength += 16;
Packit Service fa4841
		ntlm_compute_channel_bindings(context);
Packit Service fa4841
Packit Service fa4841
		if (context->ServicePrincipalName.Length > 0)
Packit Service fa4841
		{
Packit Service fa4841
			AvPairsCount++; /* MsvAvTargetName */
Packit Service fa4841
			AvPairsValueLength += context->ServicePrincipalName.Length;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	size = ntlm_av_pair_list_size(AvPairsCount, AvPairsValueLength);
Packit Service fa4841
Packit Service fa4841
	if (context->NTLMv2)
Packit Service fa4841
		size += 8; /* unknown 8-byte padding */
Packit Service fa4841
Packit Service fa4841
	if (!sspi_SecBufferAlloc(&context->AuthenticateTargetInfo, size))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	AuthenticateTargetInfo = (NTLM_AV_PAIR*)context->AuthenticateTargetInfo.pvBuffer;
Packit Service fa4841
	cbAuthenticateTargetInfo = context->AuthenticateTargetInfo.cbBuffer;
Packit Service fa4841
Packit Service fa4841
	if (!ntlm_av_pair_list_init(AuthenticateTargetInfo, cbAuthenticateTargetInfo))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (AvNbDomainName)
Packit Service fa4841
	{
Packit Service fa4841
		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvNbDomainName,
Packit Service fa4841
		                           cbAvNbDomainName))
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (AvNbComputerName)
Packit Service fa4841
	{
Packit Service fa4841
		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
Packit Service fa4841
		                           AvNbComputerName, cbAvNbComputerName))
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (AvDnsDomainName)
Packit Service fa4841
	{
Packit Service fa4841
		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
Packit Service fa4841
		                           AvDnsDomainName, cbAvDnsDomainName))
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (AvDnsComputerName)
Packit Service fa4841
	{
Packit Service fa4841
		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
Packit Service fa4841
		                           AvDnsComputerName, cbAvDnsComputerName))
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (AvDnsTreeName)
Packit Service fa4841
	{
Packit Service fa4841
		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvDnsTreeName,
Packit Service fa4841
		                           cbAvDnsTreeName))
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (AvTimestamp)
Packit Service fa4841
	{
Packit Service fa4841
		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvTimestamp,
Packit Service fa4841
		                           cbAvTimestamp))
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (context->UseMIC)
Packit Service fa4841
	{
Packit Service fa4841
		UINT32 flags;
Packit Service fa4841
		Data_Write_UINT32(&flags, MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK);
Packit Service fa4841
Packit Service fa4841
		if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvFlags,
Packit Service fa4841
		                      (PBYTE)&flags, 4))
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (context->SendSingleHostData)
Packit Service fa4841
	{
Packit Service fa4841
		if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost,
Packit Service fa4841
		                      (PBYTE)&context->SingleHostData, context->SingleHostData.Size))
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!context->SuppressExtendedProtection)
Packit Service fa4841
	{
Packit Service fa4841
		if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvChannelBindings,
Packit Service fa4841
		                      context->ChannelBindingsHash, 16))
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		if (context->ServicePrincipalName.Length > 0)
Packit Service fa4841
		{
Packit Service fa4841
			if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvTargetName,
Packit Service fa4841
			                      (PBYTE)context->ServicePrincipalName.Buffer,
Packit Service fa4841
			                      context->ServicePrincipalName.Length))
Packit Service fa4841
				goto fail;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (context->NTLMv2)
Packit Service fa4841
	{
Packit Service fa4841
		NTLM_AV_PAIR* AvEOL;
Packit Service fa4841
		AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvEOL, NULL);
Packit Service fa4841
Packit Service fa4841
		if (!AvEOL)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR));
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return 1;
Packit Service fa4841
fail:
Packit Service fa4841
	sspi_SecBufferFree(&context->AuthenticateTargetInfo);
Packit Service fa4841
	return -1;
Packit Service fa4841
}