Blame libfreerdp/core/nla.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Network Level Authentication (NLA)
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2015 Thincast Technologies GmbH
Packit 1fb8d4
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit 1fb8d4
 * Copyright 2016 Martin Fleisz <martin.fleisz@thincast.com>
Packit 1fb8d4
 * Copyright 2017 Dorian Ducournau <dorian.ducournau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *		 http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <time.h>
Packit 1fb8d4
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
#include <unistd.h>
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
#include <freerdp/crypto/tls.h>
Packit 1fb8d4
#include <freerdp/build-config.h>
Packit 1fb8d4
#include <freerdp/peer.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/sam.h>
Packit 1fb8d4
#include <winpr/sspi.h>
Packit 1fb8d4
#include <winpr/print.h>
Packit 1fb8d4
#include <winpr/tchar.h>
Packit 1fb8d4
#include <winpr/dsparse.h>
Packit 1fb8d4
#include <winpr/library.h>
Packit 1fb8d4
#include <winpr/registry.h>
Packit 1fb8d4
Packit 1fb8d4
#include "nla.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("core.nla")
Packit 1fb8d4
Packit 1fb8d4
#define SERVER_KEY "Software\\"FREERDP_VENDOR_STRING"\\" \
Packit 1fb8d4
	FREERDP_PRODUCT_STRING"\\Server"
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * TSRequest ::= SEQUENCE {
Packit 1fb8d4
 * 	version    [0] INTEGER,
Packit 1fb8d4
 * 	negoTokens [1] NegoData OPTIONAL,
Packit 1fb8d4
 * 	authInfo   [2] OCTET STRING OPTIONAL,
Packit 1fb8d4
 * 	pubKeyAuth [3] OCTET STRING OPTIONAL,
Packit 1fb8d4
 * 	errorCode  [4] INTEGER OPTIONAL
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * NegoData ::= SEQUENCE OF NegoDataItem
Packit 1fb8d4
 *
Packit 1fb8d4
 * NegoDataItem ::= SEQUENCE {
Packit 1fb8d4
 * 	negoToken [0] OCTET STRING
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * TSCredentials ::= SEQUENCE {
Packit 1fb8d4
 * 	credType    [0] INTEGER,
Packit 1fb8d4
 * 	credentials [1] OCTET STRING
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * TSPasswordCreds ::= SEQUENCE {
Packit 1fb8d4
 * 	domainName  [0] OCTET STRING,
Packit 1fb8d4
 * 	userName    [1] OCTET STRING,
Packit 1fb8d4
 * 	password    [2] OCTET STRING
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * TSSmartCardCreds ::= SEQUENCE {
Packit 1fb8d4
 * 	pin        [0] OCTET STRING,
Packit 1fb8d4
 * 	cspData    [1] TSCspDataDetail,
Packit 1fb8d4
 * 	userHint   [2] OCTET STRING OPTIONAL,
Packit 1fb8d4
 * 	domainHint [3] OCTET STRING OPTIONAL
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * TSCspDataDetail ::= SEQUENCE {
Packit 1fb8d4
 * 	keySpec       [0] INTEGER,
Packit 1fb8d4
 * 	cardName      [1] OCTET STRING OPTIONAL,
Packit 1fb8d4
 * 	readerName    [2] OCTET STRING OPTIONAL,
Packit 1fb8d4
 * 	containerName [3] OCTET STRING OPTIONAL,
Packit 1fb8d4
 * 	cspName       [4] OCTET STRING OPTIONAL
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#define NLA_PKG_NAME	NEGO_SSP_NAME
Packit 1fb8d4
Packit 1fb8d4
#define TERMSRV_SPN_PREFIX	"TERMSRV/"
Packit 1fb8d4
Packit 1fb8d4
static BOOL nla_send(rdpNla* nla);
Packit 1fb8d4
static int nla_recv(rdpNla* nla);
Packit 1fb8d4
static void nla_buffer_print(rdpNla* nla);
Packit 1fb8d4
static void nla_buffer_free(rdpNla* nla);
Packit 1fb8d4
static SECURITY_STATUS nla_encrypt_public_key_echo(rdpNla* nla);
Packit 1fb8d4
static SECURITY_STATUS nla_encrypt_public_key_hash(rdpNla* nla);
Packit 1fb8d4
static SECURITY_STATUS nla_decrypt_public_key_echo(rdpNla* nla);
Packit 1fb8d4
static SECURITY_STATUS nla_decrypt_public_key_hash(rdpNla* nla);
Packit 1fb8d4
static SECURITY_STATUS nla_encrypt_ts_credentials(rdpNla* nla);
Packit 1fb8d4
static SECURITY_STATUS nla_decrypt_ts_credentials(rdpNla* nla);
Packit 1fb8d4
static BOOL nla_read_ts_password_creds(rdpNla* nla, wStream* s);
Packit 1fb8d4
static void nla_identity_free(SEC_WINNT_AUTH_IDENTITY* identity);
Packit 1fb8d4
Packit 1fb8d4
#define ber_sizeof_sequence_octet_string(length) ber_sizeof_contextual_tag(ber_sizeof_octet_string(length)) + ber_sizeof_octet_string(length)
Packit 1fb8d4
#define ber_write_sequence_octet_string(stream, context, value, length) ber_write_contextual_tag(stream, context, ber_sizeof_octet_string(length), TRUE) + ber_write_octet_string(stream, value, length)
Packit 1fb8d4
Packit 1fb8d4
/* CredSSP Client-To-Server Binding Hash\0 */
Packit 1fb8d4
static const BYTE ClientServerHashMagic[] =
Packit 1fb8d4
{
Packit 1fb8d4
	0x43, 0x72, 0x65, 0x64, 0x53, 0x53, 0x50, 0x20,
Packit 1fb8d4
	0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x2D, 0x54,
Packit 1fb8d4
	0x6F, 0x2D, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
Packit 1fb8d4
	0x20, 0x42, 0x69, 0x6E, 0x64, 0x69, 0x6E, 0x67,
Packit 1fb8d4
	0x20, 0x48, 0x61, 0x73, 0x68, 0x00
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
/* CredSSP Server-To-Client Binding Hash\0 */
Packit 1fb8d4
static const BYTE ServerClientHashMagic[] =
Packit 1fb8d4
{
Packit 1fb8d4
	0x43, 0x72, 0x65, 0x64, 0x53, 0x53, 0x50, 0x20,
Packit 1fb8d4
	0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2D, 0x54,
Packit 1fb8d4
	0x6F, 0x2D, 0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74,
Packit 1fb8d4
	0x20, 0x42, 0x69, 0x6E, 0x64, 0x69, 0x6E, 0x67,
Packit 1fb8d4
	0x20, 0x48, 0x61, 0x73, 0x68, 0x00
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static const UINT32 NonceLength = 32;
Packit 1fb8d4
Packit 1fb8d4
void nla_identity_free(SEC_WINNT_AUTH_IDENTITY* identity)
Packit 1fb8d4
{
Packit 1fb8d4
	if (identity)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Password authentication */
Packit 1fb8d4
		if (identity->User)
Packit 1fb8d4
		{
Packit 1fb8d4
			memset(identity->User, 0, identity->UserLength * 2);
Packit 1fb8d4
			free(identity->User);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (identity->Password)
Packit 1fb8d4
		{
Packit 1fb8d4
			size_t len = identity->PasswordLength;
Packit 1fb8d4
Packit 1fb8d4
			if (len > LB_PASSWORD_MAX_LENGTH) /* [pth] Password hash */
Packit 1fb8d4
				len -= LB_PASSWORD_MAX_LENGTH;
Packit 1fb8d4
Packit 1fb8d4
			memset(identity->Password, 0, len * 2);
Packit 1fb8d4
			free(identity->Password);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (identity->Domain)
Packit 1fb8d4
		{
Packit 1fb8d4
			memset(identity->Domain, 0, identity->DomainLength * 2);
Packit 1fb8d4
			free(identity->Domain);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(identity);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Initialize NTLM/Kerberos SSP authentication module (client).
Packit 1fb8d4
 * @param credssp
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static int nla_client_init(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	char* spn;
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	rdpTls* tls = NULL;
Packit 1fb8d4
	BOOL PromptPassword = FALSE;
Packit 1fb8d4
	freerdp* instance = nla->instance;
Packit 1fb8d4
	rdpSettings* settings = nla->settings;
Packit 1fb8d4
	WINPR_SAM* sam;
Packit 1fb8d4
	WINPR_SAM_ENTRY* entry;
Packit 1fb8d4
	nla->state = NLA_STATE_INITIAL;
Packit 1fb8d4
Packit 1fb8d4
	if (settings->RestrictedAdminModeRequired)
Packit 1fb8d4
		settings->DisableCredentialsDelegation = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if ((!settings->Username) || (!strlen(settings->Username))
Packit 1fb8d4
	    || ((!settings->Password) && (!settings->RedirectionPassword)))
Packit 1fb8d4
	{
Packit 1fb8d4
		PromptPassword = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (PromptPassword && settings->Username && strlen(settings->Username))
Packit 1fb8d4
	{
Packit 1fb8d4
		sam = SamOpen(NULL, TRUE);
Packit 1fb8d4
Packit 1fb8d4
		if (sam)
Packit 1fb8d4
		{
Packit 1fb8d4
			entry = SamLookupUserA(sam, settings->Username, strlen(settings->Username), NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
			if (entry)
Packit 1fb8d4
			{
Packit 1fb8d4
				/**
Packit 1fb8d4
				 * The user could be found in SAM database.
Packit 1fb8d4
				 * Use entry in SAM database later instead of prompt
Packit 1fb8d4
				 */
Packit 1fb8d4
				PromptPassword = FALSE;
Packit 1fb8d4
				SamFreeEntry(sam, entry);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			SamClose(sam);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
Packit 1fb8d4
	if (PromptPassword)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (settings->RestrictedAdminModeRequired)
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((settings->PasswordHash) && (strlen(settings->PasswordHash) > 0))
Packit 1fb8d4
				PromptPassword = FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	if (PromptPassword)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (instance->Authenticate)
Packit 1fb8d4
		{
Packit 1fb8d4
			BOOL proceed = instance->Authenticate(instance,
Packit 1fb8d4
			                                      &settings->Username, &settings->Password, &settings->Domain);
Packit 1fb8d4
Packit 1fb8d4
			if (!proceed)
Packit 1fb8d4
			{
Packit 1fb8d4
				freerdp_set_last_error(instance->context, FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS);
Packit 1fb8d4
				return 0;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!settings->Username)
Packit 1fb8d4
	{
Packit 1fb8d4
		nla_identity_free(nla->identity);
Packit 1fb8d4
		nla->identity = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (settings->RedirectionPassword && settings->RedirectionPasswordLength > 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (sspi_SetAuthIdentityWithUnicodePassword(nla->identity, settings->Username, settings->Domain,
Packit 1fb8d4
			        (UINT16*) settings->RedirectionPassword,
Packit 1fb8d4
			        settings->RedirectionPasswordLength / sizeof(WCHAR) - 1) < 0)
Packit 1fb8d4
				return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			BOOL usePassword = TRUE;
Packit 1fb8d4
Packit 1fb8d4
			if (settings->RestrictedAdminModeRequired)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (settings->PasswordHash)
Packit 1fb8d4
				{
Packit 1fb8d4
					if (strlen(settings->PasswordHash) == 32)
Packit 1fb8d4
					{
Packit 1fb8d4
						if (sspi_SetAuthIdentity(nla->identity, settings->Username, settings->Domain,
Packit 1fb8d4
						                         settings->PasswordHash) < 0)
Packit 1fb8d4
							return -1;
Packit 1fb8d4
Packit 1fb8d4
						/**
Packit 1fb8d4
						 * Increase password hash length by LB_PASSWORD_MAX_LENGTH to obtain a length exceeding
Packit 1fb8d4
						 * the maximum (LB_PASSWORD_MAX_LENGTH) and use it this for hash identification in WinPR.
Packit 1fb8d4
						 */
Packit 1fb8d4
						nla->identity->PasswordLength += LB_PASSWORD_MAX_LENGTH;
Packit 1fb8d4
						usePassword = FALSE;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (usePassword)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (sspi_SetAuthIdentity(nla->identity, settings->Username, settings->Domain,
Packit 1fb8d4
				                         settings->Password) < 0)
Packit 1fb8d4
					return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	tls = nla->transport->tls;
Packit 1fb8d4
Packit 1fb8d4
	if (!tls)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Unknown NLA transport layer");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!sspi_SecBufferAlloc(&nla->PublicKey, tls->PublicKeyLength))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Failed to allocate sspi secBuffer");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	CopyMemory(nla->PublicKey.pvBuffer, tls->PublicKey, tls->PublicKeyLength);
Packit 1fb8d4
	length = sizeof(TERMSRV_SPN_PREFIX) + strlen(settings->ServerHostname);
Packit 1fb8d4
	spn = (SEC_CHAR*) malloc(length + 1);
Packit 1fb8d4
Packit 1fb8d4
	if (!spn)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	sprintf_s(spn, length + 1, "%s%s", TERMSRV_SPN_PREFIX, settings->ServerHostname);
Packit 1fb8d4
#ifdef UNICODE
Packit 1fb8d4
	nla->ServicePrincipalName = NULL;
Packit 1fb8d4
	ConvertToUnicode(CP_UTF8, 0, spn, -1, &nla->ServicePrincipalName, 0);
Packit 1fb8d4
	free(spn);
Packit 1fb8d4
#else
Packit 1fb8d4
	nla->ServicePrincipalName = spn;
Packit 1fb8d4
#endif
Packit 1fb8d4
	nla->table = InitSecurityInterfaceEx(0);
Packit 1fb8d4
#ifdef WITH_GSSAPI /* KERBEROS SSP */
Packit 1fb8d4
	nla->status = nla->table->QuerySecurityPackageInfo(KERBEROS_SSP_NAME, &nla->pPackageInfo);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "QuerySecurityPackageInfo status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#else /* NTLM SSP */
Packit 1fb8d4
	nla->status = nla->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &nla->pPackageInfo);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "QuerySecurityPackageInfo status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	nla->cbMaxToken = nla->pPackageInfo->cbMaxToken;
Packit 1fb8d4
	nla->packageName = nla->pPackageInfo->Name;
Packit 1fb8d4
	WLog_DBG(TAG, "%s %"PRIu32" : packageName=%ls ; cbMaxToken=%d", __FUNCTION__, __LINE__,
Packit 1fb8d4
	         nla->packageName, nla->cbMaxToken);
Packit 1fb8d4
	nla->status = nla->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME,
Packit 1fb8d4
	              SECPKG_CRED_OUTBOUND, NULL, nla->identity, NULL, NULL, &nla->credentials,
Packit 1fb8d4
	              &nla->expiration);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "AcquireCredentialsHandle status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla->haveContext = FALSE;
Packit 1fb8d4
	nla->haveInputBuffer = FALSE;
Packit 1fb8d4
	nla->havePubKeyAuth = FALSE;
Packit 1fb8d4
	ZeroMemory(&nla->inputBuffer, sizeof(SecBuffer));
Packit 1fb8d4
	ZeroMemory(&nla->outputBuffer, sizeof(SecBuffer));
Packit 1fb8d4
	ZeroMemory(&nla->ContextSizes, sizeof(SecPkgContext_Sizes));
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * from tspkg.dll: 0x00000132
Packit 1fb8d4
	 * ISC_REQ_MUTUAL_AUTH
Packit 1fb8d4
	 * ISC_REQ_CONFIDENTIALITY
Packit 1fb8d4
	 * ISC_REQ_USE_SESSION_KEY
Packit 1fb8d4
	 * ISC_REQ_ALLOCATE_MEMORY
Packit 1fb8d4
	 */
Packit 1fb8d4
	nla->fContextReq = ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int nla_client_begin(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	if (nla_client_init(nla) < 1)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->state != NLA_STATE_INITIAL)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
	nla->outputBufferDesc.cBuffers = 1;
Packit 1fb8d4
	nla->outputBufferDesc.pBuffers = &nla->outputBuffer;
Packit 1fb8d4
	nla->outputBuffer.BufferType = SECBUFFER_TOKEN;
Packit 1fb8d4
	nla->outputBuffer.cbBuffer = nla->cbMaxToken;
Packit 1fb8d4
	nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer);
Packit 1fb8d4
Packit 1fb8d4
	if (!nla->outputBuffer.pvBuffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	nla->status = nla->table->InitializeSecurityContext(&nla->credentials,
Packit 1fb8d4
	              NULL, nla->ServicePrincipalName, nla->fContextReq, 0,
Packit 1fb8d4
	              SECURITY_NATIVE_DREP, NULL, 0, &nla->context,
Packit 1fb8d4
	              &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
Packit 1fb8d4
	WLog_VRB(TAG, " InitializeSecurityContext status %s [0x%08"PRIX32"]",
Packit 1fb8d4
	         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
Packit 1fb8d4
	/* Handle kerberos context initialization failure.
Packit 1fb8d4
	 * After kerberos failed initialize NTLM context */
Packit 1fb8d4
	if (nla->status == SEC_E_NO_CREDENTIALS)
Packit 1fb8d4
	{
Packit 1fb8d4
		nla->status = nla->table->InitializeSecurityContext(&nla->credentials,
Packit 1fb8d4
		              NULL, nla->ServicePrincipalName, nla->fContextReq, 0,
Packit 1fb8d4
		              SECURITY_NATIVE_DREP, NULL, 0, &nla->context,
Packit 1fb8d4
		              &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
Packit 1fb8d4
		WLog_VRB(TAG, " InitializeSecurityContext status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status)
Packit 1fb8d4
		{
Packit 1fb8d4
			SECURITY_STATUS status = nla->table->QuerySecurityPackageInfo(NTLM_SSP_NAME, &nla->pPackageInfo);
Packit 1fb8d4
Packit 1fb8d4
			if (status != SEC_E_OK)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "QuerySecurityPackageInfo status %s [0x%08"PRIX32"]",
Packit 1fb8d4
				         GetSecurityStatusString(nla->status), status);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			nla->cbMaxToken = nla->pPackageInfo->cbMaxToken;
Packit 1fb8d4
			nla->packageName = nla->pPackageInfo->Name;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (nla->table->CompleteAuthToken)
Packit 1fb8d4
		{
Packit 1fb8d4
			SECURITY_STATUS status;
Packit 1fb8d4
			status = nla->table->CompleteAuthToken(&nla->context, &nla->outputBufferDesc);
Packit 1fb8d4
Packit 1fb8d4
			if (status != SEC_E_OK)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_WARN(TAG, "CompleteAuthToken status %s [0x%08"PRIX32"]",
Packit 1fb8d4
				          GetSecurityStatusString(status), status);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status == SEC_I_COMPLETE_NEEDED)
Packit 1fb8d4
			nla->status = SEC_E_OK;
Packit 1fb8d4
		else if (nla->status == SEC_I_COMPLETE_AND_CONTINUE)
Packit 1fb8d4
			nla->status = SEC_I_CONTINUE_NEEDED;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (nla->status != SEC_I_CONTINUE_NEEDED)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->outputBuffer.cbBuffer < 1)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer;
Packit 1fb8d4
	nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer;
Packit 1fb8d4
	WLog_DBG(TAG, "Sending Authentication Token");
Packit 1fb8d4
	winpr_HexDump(TAG, WLOG_DEBUG, nla->negoToken.pvBuffer, nla->negoToken.cbBuffer);
Packit 1fb8d4
Packit 1fb8d4
	if (!nla_send(nla))
Packit 1fb8d4
	{
Packit 1fb8d4
		nla_buffer_free(nla);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla_buffer_free(nla);
Packit 1fb8d4
	nla->state = NLA_STATE_NEGO_TOKEN;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int nla_client_recv(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = -1;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->state == NLA_STATE_NEGO_TOKEN)
Packit 1fb8d4
	{
Packit 1fb8d4
		nla->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
		nla->inputBufferDesc.cBuffers = 1;
Packit 1fb8d4
		nla->inputBufferDesc.pBuffers = &nla->inputBuffer;
Packit 1fb8d4
		nla->inputBuffer.BufferType = SECBUFFER_TOKEN;
Packit 1fb8d4
		nla->inputBuffer.pvBuffer = nla->negoToken.pvBuffer;
Packit 1fb8d4
		nla->inputBuffer.cbBuffer = nla->negoToken.cbBuffer;
Packit 1fb8d4
		nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
		nla->outputBufferDesc.cBuffers = 1;
Packit 1fb8d4
		nla->outputBufferDesc.pBuffers = &nla->outputBuffer;
Packit 1fb8d4
		nla->outputBuffer.BufferType = SECBUFFER_TOKEN;
Packit 1fb8d4
		nla->outputBuffer.cbBuffer = nla->cbMaxToken;
Packit 1fb8d4
		nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer);
Packit 1fb8d4
Packit 1fb8d4
		if (!nla->outputBuffer.pvBuffer)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		nla->status = nla->table->InitializeSecurityContext(&nla->credentials,
Packit 1fb8d4
		              &nla->context, nla->ServicePrincipalName, nla->fContextReq, 0,
Packit 1fb8d4
		              SECURITY_NATIVE_DREP, &nla->inputBufferDesc,
Packit 1fb8d4
		              0, &nla->context, &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
Packit 1fb8d4
		WLog_VRB(TAG, "InitializeSecurityContext  %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		free(nla->inputBuffer.pvBuffer);
Packit 1fb8d4
		nla->inputBuffer.pvBuffer = NULL;
Packit 1fb8d4
Packit 1fb8d4
		if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (nla->table->CompleteAuthToken)
Packit 1fb8d4
			{
Packit 1fb8d4
				SECURITY_STATUS status;
Packit 1fb8d4
				status = nla->table->CompleteAuthToken(&nla->context, &nla->outputBufferDesc);
Packit 1fb8d4
Packit 1fb8d4
				if (status != SEC_E_OK)
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_WARN(TAG, "CompleteAuthToken status %s [0x%08"PRIX32"]",
Packit 1fb8d4
					          GetSecurityStatusString(status), status);
Packit 1fb8d4
					return -1;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (nla->status == SEC_I_COMPLETE_NEEDED)
Packit 1fb8d4
				nla->status = SEC_E_OK;
Packit 1fb8d4
			else if (nla->status == SEC_I_COMPLETE_AND_CONTINUE)
Packit 1fb8d4
				nla->status = SEC_I_CONTINUE_NEEDED;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status == SEC_E_OK)
Packit 1fb8d4
		{
Packit 1fb8d4
			nla->havePubKeyAuth = TRUE;
Packit 1fb8d4
			nla->status = nla->table->QueryContextAttributes(&nla->context, SECPKG_ATTR_SIZES,
Packit 1fb8d4
			              &nla->ContextSizes);
Packit 1fb8d4
Packit 1fb8d4
			if (nla->status != SEC_E_OK)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "QueryContextAttributes SECPKG_ATTR_SIZES failure %s [0x%08"PRIX32"]",
Packit 1fb8d4
				         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (nla->peerVersion < 5)
Packit 1fb8d4
				nla->status = nla_encrypt_public_key_echo(nla);
Packit 1fb8d4
			else
Packit 1fb8d4
				nla->status = nla_encrypt_public_key_hash(nla);
Packit 1fb8d4
Packit 1fb8d4
			if (nla->status != SEC_E_OK)
Packit 1fb8d4
				return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer;
Packit 1fb8d4
		nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer;
Packit 1fb8d4
		WLog_DBG(TAG, "Sending Authentication Token");
Packit 1fb8d4
		winpr_HexDump(TAG, WLOG_DEBUG, nla->negoToken.pvBuffer, nla->negoToken.cbBuffer);
Packit 1fb8d4
Packit 1fb8d4
		if (!nla_send(nla))
Packit 1fb8d4
		{
Packit 1fb8d4
			nla_buffer_free(nla);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		nla_buffer_free(nla);
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status == SEC_E_OK)
Packit 1fb8d4
			nla->state = NLA_STATE_PUB_KEY_AUTH;
Packit 1fb8d4
Packit 1fb8d4
		status = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (nla->state == NLA_STATE_PUB_KEY_AUTH)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Verify Server Public Key Echo */
Packit 1fb8d4
		if (nla->peerVersion < 5)
Packit 1fb8d4
			nla->status = nla_decrypt_public_key_echo(nla);
Packit 1fb8d4
		else
Packit 1fb8d4
			nla->status = nla_decrypt_public_key_hash(nla);
Packit 1fb8d4
Packit 1fb8d4
		nla_buffer_free(nla);
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status != SEC_E_OK)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Could not verify public key echo %s [0x%08"PRIX32"]",
Packit 1fb8d4
			         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		/* Send encrypted credentials */
Packit 1fb8d4
		nla->status = nla_encrypt_ts_credentials(nla);
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status != SEC_E_OK)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "nla_encrypt_ts_credentials status %s [0x%08"PRIX32"]",
Packit 1fb8d4
			         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!nla_send(nla))
Packit 1fb8d4
		{
Packit 1fb8d4
			nla_buffer_free(nla);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		nla_buffer_free(nla);
Packit 1fb8d4
Packit 1fb8d4
		if (SecIsValidHandle(&nla->credentials))
Packit 1fb8d4
		{
Packit 1fb8d4
			nla->table->FreeCredentialsHandle(&nla->credentials);
Packit 1fb8d4
			SecInvalidateHandle(&nla->credentials);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status != SEC_E_OK)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "FreeCredentialsHandle status %s [0x%08"PRIX32"]",
Packit 1fb8d4
			         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		nla->status = nla->table->FreeContextBuffer(nla->pPackageInfo);
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status != SEC_E_OK)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "FreeContextBuffer status %s [0x%08"PRIX32"]",
Packit 1fb8d4
			         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status != SEC_E_OK)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		nla->state = NLA_STATE_AUTH_INFO;
Packit 1fb8d4
		status = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int nla_client_authenticate(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	s = Stream_New(NULL, 4096);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (nla_client_begin(nla) < 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Free(s, TRUE);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	while (nla->state < NLA_STATE_AUTH_INFO)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_SetPosition(s, 0);
Packit 1fb8d4
		status = transport_read_pdu(nla->transport, s);
Packit 1fb8d4
Packit 1fb8d4
		if (status < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "nla_client_authenticate failure");
Packit 1fb8d4
			Stream_Free(s, TRUE);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		status = nla_recv_pdu(nla, s);
Packit 1fb8d4
Packit 1fb8d4
		if (status < 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			Stream_Free(s, TRUE);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Initialize NTLMSSP authentication module (server).
Packit 1fb8d4
 * @param credssp
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static int nla_server_init(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpTls* tls = nla->transport->tls;
Packit 1fb8d4
Packit 1fb8d4
	if (!sspi_SecBufferAlloc(&nla->PublicKey, tls->PublicKeyLength))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Failed to allocate SecBuffer for public key");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	CopyMemory(nla->PublicKey.pvBuffer, tls->PublicKey, tls->PublicKeyLength);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->SspiModule)
Packit 1fb8d4
	{
Packit 1fb8d4
		HMODULE hSSPI;
Packit 1fb8d4
		INIT_SECURITY_INTERFACE pInitSecurityInterface;
Packit 1fb8d4
		hSSPI = LoadLibrary(nla->SspiModule);
Packit 1fb8d4
Packit 1fb8d4
		if (!hSSPI)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to load SSPI module: %s", nla->SspiModule);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
#ifdef UNICODE
Packit 1fb8d4
		pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
Packit 1fb8d4
#else
Packit 1fb8d4
		pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
Packit 1fb8d4
#endif
Packit 1fb8d4
		nla->table = pInitSecurityInterface();
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		nla->table = InitSecurityInterfaceEx(0);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla->status = nla->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &nla->pPackageInfo);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "QuerySecurityPackageInfo status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla->cbMaxToken = nla->pPackageInfo->cbMaxToken;
Packit 1fb8d4
	nla->packageName = nla->pPackageInfo->Name;
Packit 1fb8d4
	nla->status = nla->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME,
Packit 1fb8d4
	              SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &nla->credentials, &nla->expiration);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "AcquireCredentialsHandle status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla->haveContext = FALSE;
Packit 1fb8d4
	nla->haveInputBuffer = FALSE;
Packit 1fb8d4
	nla->havePubKeyAuth = FALSE;
Packit 1fb8d4
	ZeroMemory(&nla->inputBuffer, sizeof(SecBuffer));
Packit 1fb8d4
	ZeroMemory(&nla->outputBuffer, sizeof(SecBuffer));
Packit 1fb8d4
	ZeroMemory(&nla->inputBufferDesc, sizeof(SecBufferDesc));
Packit 1fb8d4
	ZeroMemory(&nla->outputBufferDesc, sizeof(SecBufferDesc));
Packit 1fb8d4
	ZeroMemory(&nla->ContextSizes, sizeof(SecPkgContext_Sizes));
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * from tspkg.dll: 0x00000112
Packit 1fb8d4
	 * ASC_REQ_MUTUAL_AUTH
Packit 1fb8d4
	 * ASC_REQ_CONFIDENTIALITY
Packit 1fb8d4
	 * ASC_REQ_ALLOCATE_MEMORY
Packit 1fb8d4
	 */
Packit 1fb8d4
	nla->fContextReq = 0;
Packit 1fb8d4
	nla->fContextReq |= ASC_REQ_MUTUAL_AUTH;
Packit 1fb8d4
	nla->fContextReq |= ASC_REQ_CONFIDENTIALITY;
Packit 1fb8d4
	nla->fContextReq |= ASC_REQ_CONNECTION;
Packit 1fb8d4
	nla->fContextReq |= ASC_REQ_USE_SESSION_KEY;
Packit 1fb8d4
	nla->fContextReq |= ASC_REQ_REPLAY_DETECT;
Packit 1fb8d4
	nla->fContextReq |= ASC_REQ_SEQUENCE_DETECT;
Packit 1fb8d4
	nla->fContextReq |= ASC_REQ_EXTENDED_ERROR;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Authenticate with client using CredSSP (server).
Packit 1fb8d4
 * @param credssp
Packit 1fb8d4
 * @return 1 if authentication is successful
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static int nla_server_authenticate(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	if (nla_server_init(nla) < 1)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	while (TRUE)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* receive authentication token */
Packit 1fb8d4
		nla->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
		nla->inputBufferDesc.cBuffers = 1;
Packit 1fb8d4
		nla->inputBufferDesc.pBuffers = &nla->inputBuffer;
Packit 1fb8d4
		nla->inputBuffer.BufferType = SECBUFFER_TOKEN;
Packit 1fb8d4
Packit 1fb8d4
		if (nla_recv(nla) < 0)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		WLog_DBG(TAG, "Receiving Authentication Token");
Packit 1fb8d4
		nla_buffer_print(nla);
Packit 1fb8d4
		nla->inputBuffer.pvBuffer = nla->negoToken.pvBuffer;
Packit 1fb8d4
		nla->inputBuffer.cbBuffer = nla->negoToken.cbBuffer;
Packit 1fb8d4
Packit 1fb8d4
		if (nla->negoToken.cbBuffer < 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "CredSSP: invalid negoToken!");
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
		nla->outputBufferDesc.cBuffers = 1;
Packit 1fb8d4
		nla->outputBufferDesc.pBuffers = &nla->outputBuffer;
Packit 1fb8d4
		nla->outputBuffer.BufferType = SECBUFFER_TOKEN;
Packit 1fb8d4
		nla->outputBuffer.cbBuffer = nla->cbMaxToken;
Packit 1fb8d4
		nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer);
Packit 1fb8d4
Packit 1fb8d4
		if (!nla->outputBuffer.pvBuffer)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		nla->status = nla->table->AcceptSecurityContext(&nla->credentials,
Packit 1fb8d4
		              nla->haveContext ? &nla->context : NULL,
Packit 1fb8d4
		              &nla->inputBufferDesc, nla->fContextReq, SECURITY_NATIVE_DREP, &nla->context,
Packit 1fb8d4
		              &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
Packit 1fb8d4
		WLog_VRB(TAG, "AcceptSecurityContext status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer;
Packit 1fb8d4
		nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer;
Packit 1fb8d4
Packit 1fb8d4
		if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED))
Packit 1fb8d4
		{
Packit 1fb8d4
			freerdp_peer* peer = nla->instance->context->peer;
Packit 1fb8d4
Packit 1fb8d4
			if (peer->ComputeNtlmHash)
Packit 1fb8d4
			{
Packit 1fb8d4
				SECURITY_STATUS status;
Packit 1fb8d4
				status = nla->table->SetContextAttributes(&nla->context, SECPKG_ATTR_AUTH_NTLM_HASH_CB,
Packit 1fb8d4
				         peer->ComputeNtlmHash, 0);
Packit 1fb8d4
Packit 1fb8d4
				if (status != SEC_E_OK)
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_ERR(TAG, "SetContextAttributesA(hash cb) status %s [0x%08"PRIX32"]",
Packit 1fb8d4
					         GetSecurityStatusString(status), status);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				status = nla->table->SetContextAttributes(&nla->context, SECPKG_ATTR_AUTH_NTLM_HASH_CB_DATA, peer,
Packit 1fb8d4
				         0);
Packit 1fb8d4
Packit 1fb8d4
				if (status != SEC_E_OK)
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_ERR(TAG, "SetContextAttributesA(hash cb data) status %s [0x%08"PRIX32"]",
Packit 1fb8d4
					         GetSecurityStatusString(status), status);
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
			else if (nla->SamFile)
Packit 1fb8d4
			{
Packit 1fb8d4
				nla->table->SetContextAttributes(&nla->context, SECPKG_ATTR_AUTH_NTLM_SAM_FILE, nla->SamFile,
Packit 1fb8d4
				                                 strlen(nla->SamFile) + 1);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (nla->table->CompleteAuthToken)
Packit 1fb8d4
			{
Packit 1fb8d4
				SECURITY_STATUS status;
Packit 1fb8d4
				status = nla->table->CompleteAuthToken(&nla->context, &nla->outputBufferDesc);
Packit 1fb8d4
Packit 1fb8d4
				if (status != SEC_E_OK)
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_WARN(TAG, "CompleteAuthToken status %s [0x%08"PRIX32"]",
Packit 1fb8d4
					          GetSecurityStatusString(status), status);
Packit 1fb8d4
					return -1;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (nla->status == SEC_I_COMPLETE_NEEDED)
Packit 1fb8d4
				nla->status = SEC_E_OK;
Packit 1fb8d4
			else if (nla->status == SEC_I_COMPLETE_AND_CONTINUE)
Packit 1fb8d4
				nla->status = SEC_I_CONTINUE_NEEDED;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status == SEC_E_OK)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (nla->outputBuffer.cbBuffer != 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!nla_send(nla))
Packit 1fb8d4
				{
Packit 1fb8d4
					nla_buffer_free(nla);
Packit 1fb8d4
					return -1;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (nla_recv(nla) < 0)
Packit 1fb8d4
					return -1;
Packit 1fb8d4
Packit 1fb8d4
				WLog_DBG(TAG, "Receiving pubkey Token");
Packit 1fb8d4
				nla_buffer_print(nla);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			nla->havePubKeyAuth = TRUE;
Packit 1fb8d4
			nla->status = nla->table->QueryContextAttributes(&nla->context, SECPKG_ATTR_SIZES,
Packit 1fb8d4
			              &nla->ContextSizes);
Packit 1fb8d4
Packit 1fb8d4
			if (nla->status != SEC_E_OK)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "QueryContextAttributes SECPKG_ATTR_SIZES failure %s [0x%08"PRIX32"]",
Packit 1fb8d4
				         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (nla->peerVersion < 5)
Packit 1fb8d4
				nla->status = nla_decrypt_public_key_echo(nla);
Packit 1fb8d4
			else
Packit 1fb8d4
				nla->status = nla_decrypt_public_key_hash(nla);
Packit 1fb8d4
Packit 1fb8d4
			if (nla->status != SEC_E_OK)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Error: could not verify client's public key echo %s [0x%08"PRIX32"]",
Packit 1fb8d4
				         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			sspi_SecBufferFree(&nla->negoToken);
Packit 1fb8d4
			nla->negoToken.pvBuffer = NULL;
Packit 1fb8d4
			nla->negoToken.cbBuffer = 0;
Packit 1fb8d4
Packit 1fb8d4
			if (nla->peerVersion < 5)
Packit 1fb8d4
				nla->status = nla_encrypt_public_key_echo(nla);
Packit 1fb8d4
			else
Packit 1fb8d4
				nla->status = nla_encrypt_public_key_hash(nla);
Packit 1fb8d4
Packit 1fb8d4
			if (nla->status != SEC_E_OK)
Packit 1fb8d4
				return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if ((nla->status != SEC_E_OK) && (nla->status != SEC_I_CONTINUE_NEEDED))
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Special handling of these specific error codes as NTSTATUS_FROM_WIN32
Packit 1fb8d4
			   unfortunately does not map directly to the corresponding NTSTATUS values
Packit 1fb8d4
			 */
Packit 1fb8d4
			switch (GetLastError())
Packit 1fb8d4
			{
Packit 1fb8d4
				case ERROR_PASSWORD_MUST_CHANGE:
Packit 1fb8d4
					nla->errorCode = STATUS_PASSWORD_MUST_CHANGE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ERROR_PASSWORD_EXPIRED:
Packit 1fb8d4
					nla->errorCode = STATUS_PASSWORD_EXPIRED;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ERROR_ACCOUNT_DISABLED:
Packit 1fb8d4
					nla->errorCode = STATUS_ACCOUNT_DISABLED;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				default:
Packit 1fb8d4
					nla->errorCode = NTSTATUS_FROM_WIN32(GetLastError());
Packit 1fb8d4
					break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			WLog_ERR(TAG, "AcceptSecurityContext status %s [0x%08"PRIX32"]",
Packit 1fb8d4
			         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
			nla_send(nla);
Packit 1fb8d4
			return -1; /* Access Denied */
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		/* send authentication token */
Packit 1fb8d4
		WLog_DBG(TAG, "Sending Authentication Token");
Packit 1fb8d4
		nla_buffer_print(nla);
Packit 1fb8d4
Packit 1fb8d4
		if (!nla_send(nla))
Packit 1fb8d4
		{
Packit 1fb8d4
			nla_buffer_free(nla);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		nla_buffer_free(nla);
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status != SEC_I_CONTINUE_NEEDED)
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		nla->haveContext = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Receive encrypted credentials */
Packit 1fb8d4
Packit 1fb8d4
	if (nla_recv(nla) < 0)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	nla->status = nla_decrypt_ts_credentials(nla);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Could not decrypt TSCredentials status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla->status = nla->table->ImpersonateSecurityContext(&nla->context);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "ImpersonateSecurityContext status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		nla->status = nla->table->RevertSecurityContext(&nla->context);
Packit 1fb8d4
Packit 1fb8d4
		if (nla->status != SEC_E_OK)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "RevertSecurityContext status %s [0x%08"PRIX32"]",
Packit 1fb8d4
			         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla->status = nla->table->FreeContextBuffer(nla->pPackageInfo);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "DeleteSecurityContext status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(nla->status), nla->status);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Authenticate using CredSSP.
Packit 1fb8d4
 * @param credssp
Packit 1fb8d4
 * @return 1 if authentication is successful
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
int nla_authenticate(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	if (nla->server)
Packit 1fb8d4
		return nla_server_authenticate(nla);
Packit 1fb8d4
	else
Packit 1fb8d4
		return nla_client_authenticate(nla);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void ap_integer_increment_le(BYTE* number, int size)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < size; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (number[index] < 0xFF)
Packit 1fb8d4
		{
Packit 1fb8d4
			number[index]++;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			number[index] = 0;
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void ap_integer_decrement_le(BYTE* number, int size)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < size; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (number[index] > 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			number[index]--;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			number[index] = 0xFF;
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
SECURITY_STATUS nla_encrypt_public_key_echo(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	SecBuffer Buffers[2] = { { 0 } };
Packit 1fb8d4
	SecBufferDesc Message;
Packit 1fb8d4
	SECURITY_STATUS status;
Packit 1fb8d4
	ULONG public_key_length;
Packit 1fb8d4
	const BOOL krb = (_tcsncmp(nla->packageName, KERBEROS_SSP_NAME, ARRAYSIZE(KERBEROS_SSP_NAME)) == 0);
Packit 1fb8d4
	const BOOL nego = (_tcsncmp(nla->packageName, NEGO_SSP_NAME, ARRAYSIZE(NEGO_SSP_NAME)) == 0);
Packit 1fb8d4
	const BOOL ntlm = (_tcsncmp(nla->packageName,  NTLM_SSP_NAME, ARRAYSIZE(NTLM_SSP_NAME)) == 0);
Packit 1fb8d4
	public_key_length = nla->PublicKey.cbBuffer;
Packit 1fb8d4
Packit 1fb8d4
	if (!sspi_SecBufferAlloc(&nla->pubKeyAuth, public_key_length + nla->ContextSizes.cbSecurityTrailer))
Packit 1fb8d4
		return SEC_E_INSUFFICIENT_MEMORY;
Packit 1fb8d4
Packit 1fb8d4
	if (krb)
Packit 1fb8d4
	{
Packit 1fb8d4
		Message.cBuffers = 1;
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_DATA; /* TLS Public Key */
Packit 1fb8d4
		Buffers[0].cbBuffer = public_key_length;
Packit 1fb8d4
		Buffers[0].pvBuffer = nla->pubKeyAuth.pvBuffer;
Packit 1fb8d4
		CopyMemory(Buffers[0].pvBuffer, nla->PublicKey.pvBuffer, Buffers[0].cbBuffer);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (ntlm || nego)
Packit 1fb8d4
	{
Packit 1fb8d4
		Message.cBuffers = 2;
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
Packit 1fb8d4
		Buffers[0].cbBuffer = nla->ContextSizes.cbSecurityTrailer;
Packit 1fb8d4
		Buffers[0].pvBuffer = nla->pubKeyAuth.pvBuffer;
Packit 1fb8d4
		Buffers[1].BufferType = SECBUFFER_DATA; /* TLS Public Key */
Packit 1fb8d4
		Buffers[1].cbBuffer = public_key_length;
Packit 1fb8d4
		Buffers[1].pvBuffer = ((BYTE*) nla->pubKeyAuth.pvBuffer) + nla->ContextSizes.cbSecurityTrailer;
Packit 1fb8d4
		CopyMemory(Buffers[1].pvBuffer, nla->PublicKey.pvBuffer, Buffers[1].cbBuffer);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!krb && nla->server)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* server echos the public key +1 */
Packit 1fb8d4
		ap_integer_increment_le((BYTE*) Buffers[1].pvBuffer, Buffers[1].cbBuffer);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Message.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
	Message.pBuffers = (PSecBuffer) &Buffers;
Packit 1fb8d4
	status = nla->table->EncryptMessage(&nla->context, 0, &Message, nla->sendSeqNum++);
Packit 1fb8d4
Packit 1fb8d4
	if (status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "EncryptMessage status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(status), status);
Packit 1fb8d4
		return status;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (Message.cBuffers == 2 && Buffers[0].cbBuffer < nla->ContextSizes.cbSecurityTrailer)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* IMPORTANT: EncryptMessage may not use all the signature space, so we need to shrink the excess between the buffers */
Packit 1fb8d4
		MoveMemory(((BYTE*)Buffers[0].pvBuffer) + Buffers[0].cbBuffer, Buffers[1].pvBuffer, Buffers[1].cbBuffer);
Packit 1fb8d4
		nla->pubKeyAuth.cbBuffer = Buffers[0].cbBuffer + Buffers[1].cbBuffer;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
SECURITY_STATUS nla_encrypt_public_key_hash(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	SecBuffer Buffers[2] = { { 0 } };
Packit 1fb8d4
	SecBufferDesc Message;
Packit 1fb8d4
	SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
Packit 1fb8d4
	WINPR_DIGEST_CTX* sha256 = NULL;
Packit 1fb8d4
	const BOOL krb = (_tcsncmp(nla->packageName, KERBEROS_SSP_NAME, ARRAYSIZE(KERBEROS_SSP_NAME)) == 0);
Packit 1fb8d4
	const ULONG auth_data_length = (nla->ContextSizes.cbSecurityTrailer + WINPR_SHA256_DIGEST_LENGTH);
Packit 1fb8d4
	const BYTE* hashMagic = nla->server ? ServerClientHashMagic : ClientServerHashMagic;
Packit 1fb8d4
	const size_t hashSize = nla->server ? sizeof(ServerClientHashMagic) : sizeof(ClientServerHashMagic);
Packit 1fb8d4
Packit 1fb8d4
	if (!sspi_SecBufferAlloc(&nla->pubKeyAuth, auth_data_length))
Packit 1fb8d4
	{
Packit 1fb8d4
		status = SEC_E_INSUFFICIENT_MEMORY;
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* generate SHA256 of following data: ClientServerHashMagic, Nonce, SubjectPublicKey */
Packit 1fb8d4
	if (!(sha256 = winpr_Digest_New()))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	if (!winpr_Digest_Init(sha256, WINPR_MD_SHA256))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	/* include trailing \0 from hashMagic */
Packit 1fb8d4
	if (!winpr_Digest_Update(sha256, hashMagic, hashSize))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	if (!winpr_Digest_Update(sha256, nla->ClientNonce.pvBuffer, nla->ClientNonce.cbBuffer))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	/* SubjectPublicKey */
Packit 1fb8d4
	if (!winpr_Digest_Update(sha256, nla->PublicKey.pvBuffer, nla->PublicKey.cbBuffer))
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	if (krb)
Packit 1fb8d4
	{
Packit 1fb8d4
		Message.cBuffers = 1;
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_DATA; /* SHA256 hash */
Packit 1fb8d4
		Buffers[0].cbBuffer = WINPR_SHA256_DIGEST_LENGTH;
Packit 1fb8d4
		Buffers[0].pvBuffer = nla->pubKeyAuth.pvBuffer;
Packit 1fb8d4
Packit 1fb8d4
		if (!winpr_Digest_Final(sha256, Buffers[0].pvBuffer, Buffers[0].cbBuffer))
Packit 1fb8d4
			goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		Message.cBuffers = 2;
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
Packit 1fb8d4
		Buffers[0].cbBuffer = nla->ContextSizes.cbSecurityTrailer;
Packit 1fb8d4
		Buffers[0].pvBuffer = nla->pubKeyAuth.pvBuffer;
Packit 1fb8d4
		Buffers[1].BufferType = SECBUFFER_DATA; /* SHA256 hash */
Packit 1fb8d4
		Buffers[1].cbBuffer = WINPR_SHA256_DIGEST_LENGTH;
Packit 1fb8d4
		Buffers[1].pvBuffer = ((BYTE*)nla->pubKeyAuth.pvBuffer) + nla->ContextSizes.cbSecurityTrailer;
Packit 1fb8d4
Packit 1fb8d4
		if (!winpr_Digest_Final(sha256, Buffers[1].pvBuffer, Buffers[1].cbBuffer))
Packit 1fb8d4
			goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Message.pBuffers = (PSecBuffer) &Buffers;
Packit 1fb8d4
	Message.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
	status = nla->table->EncryptMessage(&nla->context, 0, &Message, nla->sendSeqNum++);
Packit 1fb8d4
Packit 1fb8d4
	if (status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "EncryptMessage status %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(status), status);
Packit 1fb8d4
		goto out;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (Message.cBuffers == 2 && Buffers[0].cbBuffer < nla->ContextSizes.cbSecurityTrailer)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* IMPORTANT: EncryptMessage may not use all the signature space, so we need to shrink the excess between the buffers */
Packit 1fb8d4
		MoveMemory(((BYTE*)Buffers[0].pvBuffer) + Buffers[0].cbBuffer, Buffers[1].pvBuffer, Buffers[1].cbBuffer);
Packit 1fb8d4
		nla->pubKeyAuth.cbBuffer = Buffers[0].cbBuffer + Buffers[1].cbBuffer;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
out:
Packit 1fb8d4
	winpr_Digest_Free(sha256);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
SECURITY_STATUS nla_decrypt_public_key_echo(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	ULONG length;
Packit 1fb8d4
	BYTE* buffer = NULL;
Packit 1fb8d4
	ULONG pfQOP = 0;
Packit 1fb8d4
	BYTE* public_key1 = NULL;
Packit 1fb8d4
	BYTE* public_key2 = NULL;
Packit 1fb8d4
	ULONG public_key_length = 0;
Packit 1fb8d4
	int signature_length;
Packit 1fb8d4
	SecBuffer Buffers[2] = { { 0 } };
Packit 1fb8d4
	SecBufferDesc Message;
Packit 1fb8d4
	BOOL krb, ntlm, nego;
Packit 1fb8d4
	SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
Packit 1fb8d4
Packit 1fb8d4
	if (!nla)
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	krb = (_tcsncmp(nla->packageName, KERBEROS_SSP_NAME, ARRAYSIZE(KERBEROS_SSP_NAME)) == 0);
Packit 1fb8d4
	nego = (_tcsncmp(nla->packageName, NEGO_SSP_NAME, ARRAYSIZE(NEGO_SSP_NAME)) == 0);
Packit 1fb8d4
	ntlm = (_tcsncmp(nla->packageName,  NTLM_SSP_NAME, ARRAYSIZE(NTLM_SSP_NAME)) == 0);
Packit 1fb8d4
	signature_length = nla->pubKeyAuth.cbBuffer - nla->PublicKey.cbBuffer;
Packit 1fb8d4
Packit 1fb8d4
	if ((signature_length < 0) || (signature_length > nla->ContextSizes.cbSecurityTrailer))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unexpected pubKeyAuth buffer size: %"PRIu32"", nla->pubKeyAuth.cbBuffer);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	length = nla->pubKeyAuth.cbBuffer;
Packit 1fb8d4
	buffer = (BYTE*) malloc(length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		status = SEC_E_INSUFFICIENT_MEMORY;
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (krb)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(buffer, nla->pubKeyAuth.pvBuffer, length);
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_DATA; /* Wrapped and encrypted TLS Public Key */
Packit 1fb8d4
		Buffers[0].cbBuffer = length;
Packit 1fb8d4
		Buffers[0].pvBuffer = buffer;
Packit 1fb8d4
		Message.cBuffers = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (ntlm || nego)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(buffer, nla->pubKeyAuth.pvBuffer, length);
Packit 1fb8d4
		public_key_length = nla->PublicKey.cbBuffer;
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
Packit 1fb8d4
		Buffers[0].cbBuffer = signature_length;
Packit 1fb8d4
		Buffers[0].pvBuffer = buffer;
Packit 1fb8d4
		Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
Packit 1fb8d4
		Buffers[1].cbBuffer = length - signature_length;
Packit 1fb8d4
		Buffers[1].pvBuffer = buffer + signature_length;
Packit 1fb8d4
		Message.cBuffers = 2;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Message.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
	Message.pBuffers = (PSecBuffer)&Buffers;
Packit 1fb8d4
	status = nla->table->DecryptMessage(&nla->context, &Message, nla->recvSeqNum++, &pfQOP);
Packit 1fb8d4
Packit 1fb8d4
	if (status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "DecryptMessage failure %s [%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(status), status);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (krb)
Packit 1fb8d4
	{
Packit 1fb8d4
		public_key1 = public_key2 = (BYTE*) nla->pubKeyAuth.pvBuffer ;
Packit 1fb8d4
		public_key_length = length;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (ntlm || nego)
Packit 1fb8d4
	{
Packit 1fb8d4
		public_key1 = (BYTE*) nla->PublicKey.pvBuffer;
Packit 1fb8d4
		public_key2 = (BYTE*) Buffers[1].pvBuffer;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!nla->server)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* server echos the public key +1 */
Packit 1fb8d4
		ap_integer_decrement_le(public_key2, public_key_length);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!public_key1 || !public_key2 || memcmp(public_key1, public_key2, public_key_length) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Could not verify server's public key echo");
Packit 1fb8d4
		WLog_ERR(TAG, "Expected (length = %d):", public_key_length);
Packit 1fb8d4
		winpr_HexDump(TAG, WLOG_ERROR, public_key1, public_key_length);
Packit 1fb8d4
		WLog_ERR(TAG, "Actual (length = %d):", public_key_length);
Packit 1fb8d4
		winpr_HexDump(TAG, WLOG_ERROR, public_key2, public_key_length);
Packit 1fb8d4
		status = SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = SEC_E_OK;
Packit 1fb8d4
fail:
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
SECURITY_STATUS nla_decrypt_public_key_hash(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	unsigned long length;
Packit 1fb8d4
	BYTE* buffer = NULL;
Packit 1fb8d4
	ULONG pfQOP = 0;
Packit 1fb8d4
	int signature_length;
Packit 1fb8d4
	SecBuffer Buffers[2] = { { 0 } };
Packit 1fb8d4
	SecBufferDesc Message;
Packit 1fb8d4
	WINPR_DIGEST_CTX* sha256 = NULL;
Packit 1fb8d4
	BYTE serverClientHash[WINPR_SHA256_DIGEST_LENGTH];
Packit 1fb8d4
	SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
Packit 1fb8d4
	const BOOL krb = (_tcsncmp(nla->packageName, KERBEROS_SSP_NAME, ARRAYSIZE(KERBEROS_SSP_NAME)) == 0);
Packit 1fb8d4
	const BYTE* hashMagic = nla->server ? ClientServerHashMagic : ServerClientHashMagic;
Packit 1fb8d4
	const size_t hashSize = nla->server ? sizeof(ClientServerHashMagic) : sizeof(ServerClientHashMagic);
Packit 1fb8d4
	signature_length = nla->pubKeyAuth.cbBuffer - WINPR_SHA256_DIGEST_LENGTH;
Packit 1fb8d4
Packit 1fb8d4
	if ((signature_length < 0) || (signature_length > (int)nla->ContextSizes.cbSecurityTrailer))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unexpected pubKeyAuth buffer size: %"PRIu32"", nla->pubKeyAuth.cbBuffer);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	length = nla->pubKeyAuth.cbBuffer;
Packit 1fb8d4
	buffer = (BYTE*)malloc(length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		status = SEC_E_INSUFFICIENT_MEMORY;
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (krb)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(buffer, nla->pubKeyAuth.pvBuffer, length);
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_DATA; /* Encrypted Hash */
Packit 1fb8d4
		Buffers[0].cbBuffer = length;
Packit 1fb8d4
		Buffers[0].pvBuffer = buffer;
Packit 1fb8d4
		Message.cBuffers = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(buffer, nla->pubKeyAuth.pvBuffer, length);
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
Packit 1fb8d4
		Buffers[0].cbBuffer = signature_length;
Packit 1fb8d4
		Buffers[0].pvBuffer = buffer;
Packit 1fb8d4
		Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted Hash */
Packit 1fb8d4
		Buffers[1].cbBuffer = WINPR_SHA256_DIGEST_LENGTH;
Packit 1fb8d4
		Buffers[1].pvBuffer = buffer + signature_length;
Packit 1fb8d4
		Message.cBuffers = 2;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Message.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
	Message.pBuffers = (PSecBuffer) &Buffers;
Packit 1fb8d4
	status = nla->table->DecryptMessage(&nla->context, &Message, nla->recvSeqNum++, &pfQOP);
Packit 1fb8d4
Packit 1fb8d4
	if (status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "DecryptMessage failure %s [%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(status), status);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* generate SHA256 of following data: ServerClientHashMagic, Nonce, SubjectPublicKey */
Packit 1fb8d4
	if (!(sha256 = winpr_Digest_New()))
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	if (!winpr_Digest_Init(sha256, WINPR_MD_SHA256))
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	/* include trailing \0 from hashMagic */
Packit 1fb8d4
	if (!winpr_Digest_Update(sha256, hashMagic, hashSize))
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	if (!winpr_Digest_Update(sha256, nla->ClientNonce.pvBuffer, nla->ClientNonce.cbBuffer))
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	/* SubjectPublicKey */
Packit 1fb8d4
	if (!winpr_Digest_Update(sha256, nla->PublicKey.pvBuffer, nla->PublicKey.cbBuffer))
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	if (!winpr_Digest_Final(sha256, serverClientHash, sizeof(serverClientHash)))
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	/* verify hash */
Packit 1fb8d4
	if (memcmp(serverClientHash, Buffers[krb ? 0 : 1].pvBuffer, WINPR_SHA256_DIGEST_LENGTH) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Could not verify server's hash");
Packit 1fb8d4
		status = SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = SEC_E_OK;
Packit 1fb8d4
fail:
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	winpr_Digest_Free(sha256);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static size_t nla_sizeof_ts_password_creds(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->identity)
Packit 1fb8d4
	{
Packit 1fb8d4
		length += ber_sizeof_sequence_octet_string(nla->identity->DomainLength * 2);
Packit 1fb8d4
		length += ber_sizeof_sequence_octet_string(nla->identity->UserLength * 2);
Packit 1fb8d4
		length += ber_sizeof_sequence_octet_string(nla->identity->PasswordLength * 2);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return length;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static size_t nla_sizeof_ts_credentials(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t size = 0;
Packit 1fb8d4
	size += ber_sizeof_integer(1);
Packit 1fb8d4
	size += ber_sizeof_contextual_tag(ber_sizeof_integer(1));
Packit 1fb8d4
	size += ber_sizeof_sequence_octet_string(ber_sizeof_sequence(nla_sizeof_ts_password_creds(nla)));
Packit 1fb8d4
	return size;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL nla_read_ts_password_creds(rdpNla* nla, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
Packit 1fb8d4
	if (!nla->identity)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "nla->identity is NULL!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* TSPasswordCreds (SEQUENCE)
Packit 1fb8d4
	 * Initialise to default values. */
Packit 1fb8d4
	nla->identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
Packit 1fb8d4
	nla->identity->UserLength = (UINT32) 0;
Packit 1fb8d4
	nla->identity->User = NULL;
Packit 1fb8d4
	nla->identity->DomainLength = (UINT32) 0;
Packit 1fb8d4
	nla->identity->Domain = NULL;
Packit 1fb8d4
	nla->identity->Password = NULL;
Packit 1fb8d4
	nla->identity->PasswordLength = (UINT32) 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* The sequence is empty, return early,
Packit 1fb8d4
	 * TSPasswordCreds (SEQUENCE) is optional. */
Packit 1fb8d4
	if (length == 0)
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit 1fb8d4
	/* [0] domainName (OCTET STRING) */
Packit 1fb8d4
	if (!ber_read_contextual_tag(s, 0, &length, TRUE) ||
Packit 1fb8d4
	    !ber_read_octet_string_tag(s, &length))
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla->identity->DomainLength = (UINT32) length;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->identity->DomainLength > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nla->identity->Domain = (UINT16*) malloc(length);
Packit 1fb8d4
Packit 1fb8d4
		if (!nla->identity->Domain)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(nla->identity->Domain, Stream_Pointer(s), nla->identity->DomainLength);
Packit 1fb8d4
		Stream_Seek(s, nla->identity->DomainLength);
Packit 1fb8d4
		nla->identity->DomainLength /= 2;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* [1] userName (OCTET STRING) */
Packit 1fb8d4
	if (!ber_read_contextual_tag(s, 1, &length, TRUE) ||
Packit 1fb8d4
	    !ber_read_octet_string_tag(s, &length))
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla->identity->UserLength = (UINT32) length;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->identity->UserLength > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nla->identity->User = (UINT16*) malloc(length);
Packit 1fb8d4
Packit 1fb8d4
		if (!nla->identity->User)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(nla->identity->User, Stream_Pointer(s), nla->identity->UserLength);
Packit 1fb8d4
		Stream_Seek(s, nla->identity->UserLength);
Packit 1fb8d4
		nla->identity->UserLength /= 2;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* [2] password (OCTET STRING) */
Packit 1fb8d4
	if (!ber_read_contextual_tag(s, 2, &length, TRUE) ||
Packit 1fb8d4
	    !ber_read_octet_string_tag(s, &length))
Packit 1fb8d4
	{
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla->identity->PasswordLength = (UINT32) length;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->identity->PasswordLength > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nla->identity->Password = (UINT16*) malloc(length);
Packit 1fb8d4
Packit 1fb8d4
		if (!nla->identity->Password)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(nla->identity->Password, Stream_Pointer(s), nla->identity->PasswordLength);
Packit 1fb8d4
		Stream_Seek(s, nla->identity->PasswordLength);
Packit 1fb8d4
		nla->identity->PasswordLength /= 2;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static size_t nla_write_ts_password_creds(rdpNla* nla, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t size = 0;
Packit 1fb8d4
	size_t innerSize = nla_sizeof_ts_password_creds(nla);
Packit 1fb8d4
	/* TSPasswordCreds (SEQUENCE) */
Packit 1fb8d4
	size += ber_write_sequence_tag(s, innerSize);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->identity)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* [0] domainName (OCTET STRING) */
Packit 1fb8d4
		size += ber_write_sequence_octet_string(
Packit 1fb8d4
		            s, 0, (BYTE*) nla->identity->Domain,
Packit 1fb8d4
		            nla->identity->DomainLength * 2);
Packit 1fb8d4
		/* [1] userName (OCTET STRING) */
Packit 1fb8d4
		size += ber_write_sequence_octet_string(
Packit 1fb8d4
		            s, 1, (BYTE*) nla->identity->User,
Packit 1fb8d4
		            nla->identity->UserLength * 2);
Packit 1fb8d4
		/* [2] password (OCTET STRING) */
Packit 1fb8d4
		size += ber_write_sequence_octet_string(
Packit 1fb8d4
		            s, 2, (BYTE*) nla->identity->Password,
Packit 1fb8d4
		            nla->identity->PasswordLength * 2);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return size;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL nla_read_ts_credentials(rdpNla* nla, PSecBuffer ts_credentials)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	size_t ts_password_creds_length = 0;
Packit 1fb8d4
	BOOL ret;
Packit 1fb8d4
Packit 1fb8d4
	if (!ts_credentials || !ts_credentials->pvBuffer)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New(ts_credentials->pvBuffer, ts_credentials->cbBuffer);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* TSCredentials (SEQUENCE) */
Packit 1fb8d4
	ret = ber_read_sequence_tag(s, &length) &&
Packit 1fb8d4
	      /* [0] credType (INTEGER) */
Packit 1fb8d4
	      ber_read_contextual_tag(s, 0, &length, TRUE) &&
Packit 1fb8d4
	      ber_read_integer(s, NULL) &&
Packit 1fb8d4
	      /* [1] credentials (OCTET STRING) */
Packit 1fb8d4
	      ber_read_contextual_tag(s, 1, &length, TRUE) &&
Packit 1fb8d4
	      ber_read_octet_string_tag(s, &ts_password_creds_length) &&
Packit 1fb8d4
	      nla_read_ts_password_creds(nla, s);
Packit 1fb8d4
	Stream_Free(s, FALSE);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static size_t nla_write_ts_credentials(rdpNla* nla, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t size = 0;
Packit 1fb8d4
	size_t passwordSize;
Packit 1fb8d4
	size_t innerSize = nla_sizeof_ts_credentials(nla);
Packit 1fb8d4
	/* TSCredentials (SEQUENCE) */
Packit 1fb8d4
	size += ber_write_sequence_tag(s, innerSize);
Packit 1fb8d4
	/* [0] credType (INTEGER) */
Packit 1fb8d4
	size += ber_write_contextual_tag(s, 0, ber_sizeof_integer(1), TRUE);
Packit 1fb8d4
	size += ber_write_integer(s, 1);
Packit 1fb8d4
	/* [1] credentials (OCTET STRING) */
Packit 1fb8d4
	passwordSize = ber_sizeof_sequence(nla_sizeof_ts_password_creds(nla));
Packit 1fb8d4
	size += ber_write_contextual_tag(s, 1, ber_sizeof_octet_string(passwordSize), TRUE);
Packit 1fb8d4
	size += ber_write_octet_string_tag(s, passwordSize);
Packit 1fb8d4
	size += nla_write_ts_password_creds(nla, s);
Packit 1fb8d4
	return size;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Encode TSCredentials structure.
Packit 1fb8d4
 * @param credssp
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static BOOL nla_encode_ts_credentials(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	int DomainLength = 0;
Packit 1fb8d4
	int UserLength = 0;
Packit 1fb8d4
	int PasswordLength = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->identity)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* TSPasswordCreds */
Packit 1fb8d4
		DomainLength = nla->identity->DomainLength;
Packit 1fb8d4
		UserLength = nla->identity->UserLength;
Packit 1fb8d4
		PasswordLength = nla->identity->PasswordLength;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (nla->settings->DisableCredentialsDelegation && nla->identity)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* TSPasswordCreds */
Packit 1fb8d4
		nla->identity->DomainLength = 0;
Packit 1fb8d4
		nla->identity->UserLength = 0;
Packit 1fb8d4
		nla->identity->PasswordLength = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	length = ber_sizeof_sequence(nla_sizeof_ts_credentials(nla));
Packit 1fb8d4
Packit 1fb8d4
	if (!sspi_SecBufferAlloc(&nla->tsCredentials, length))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "sspi_SecBufferAlloc failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New((BYTE*) nla->tsCredentials.pvBuffer, length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		sspi_SecBufferFree(&nla->tsCredentials);
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla_write_ts_credentials(nla, s);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->settings->DisableCredentialsDelegation && nla->identity)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* TSPasswordCreds */
Packit 1fb8d4
		nla->identity->DomainLength = DomainLength;
Packit 1fb8d4
		nla->identity->UserLength = UserLength;
Packit 1fb8d4
		nla->identity->PasswordLength = PasswordLength;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Free(s, FALSE);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static SECURITY_STATUS nla_encrypt_ts_credentials(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	SecBuffer Buffers[2] = { { 0 } };
Packit 1fb8d4
	SecBufferDesc Message;
Packit 1fb8d4
	SECURITY_STATUS status;
Packit 1fb8d4
	const BOOL krb = (_tcsncmp(nla->packageName, KERBEROS_SSP_NAME, ARRAYSIZE(KERBEROS_SSP_NAME)) == 0);
Packit 1fb8d4
	const BOOL nego = (_tcsncmp(nla->packageName, NEGO_SSP_NAME, ARRAYSIZE(NEGO_SSP_NAME)) == 0);
Packit 1fb8d4
	const BOOL ntlm = (_tcsncmp(nla->packageName,  NTLM_SSP_NAME, ARRAYSIZE(NTLM_SSP_NAME)) == 0);
Packit 1fb8d4
Packit 1fb8d4
	if (!nla_encode_ts_credentials(nla))
Packit 1fb8d4
		return SEC_E_INSUFFICIENT_MEMORY;
Packit 1fb8d4
Packit 1fb8d4
	if (!sspi_SecBufferAlloc(&nla->authInfo,
Packit 1fb8d4
	                         nla->tsCredentials.cbBuffer + nla->ContextSizes.cbSecurityTrailer))
Packit 1fb8d4
		return SEC_E_INSUFFICIENT_MEMORY;
Packit 1fb8d4
Packit 1fb8d4
	if (krb)
Packit 1fb8d4
	{
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_DATA; /* TSCredentials */
Packit 1fb8d4
		Buffers[0].cbBuffer = nla->tsCredentials.cbBuffer;
Packit 1fb8d4
		Buffers[0].pvBuffer = nla->authInfo.pvBuffer;
Packit 1fb8d4
		CopyMemory(Buffers[0].pvBuffer, nla->tsCredentials.pvBuffer, Buffers[0].cbBuffer);
Packit 1fb8d4
		Message.cBuffers = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (ntlm || nego)
Packit 1fb8d4
	{
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
Packit 1fb8d4
		Buffers[0].cbBuffer = nla->ContextSizes.cbSecurityTrailer;
Packit 1fb8d4
		Buffers[0].pvBuffer = nla->authInfo.pvBuffer;
Packit 1fb8d4
		MoveMemory(Buffers[0].pvBuffer, nla->authInfo.pvBuffer, Buffers[0].cbBuffer);
Packit 1fb8d4
		Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
Packit 1fb8d4
		Buffers[1].cbBuffer = nla->tsCredentials.cbBuffer;
Packit 1fb8d4
		Buffers[1].pvBuffer = &((BYTE*) nla->authInfo.pvBuffer)[Buffers[0].cbBuffer];
Packit 1fb8d4
		CopyMemory(Buffers[1].pvBuffer, nla->tsCredentials.pvBuffer, Buffers[1].cbBuffer);
Packit 1fb8d4
		Message.cBuffers = 2;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Message.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
	Message.pBuffers = (PSecBuffer) &Buffers;
Packit 1fb8d4
	status = nla->table->EncryptMessage(&nla->context, 0, &Message, nla->sendSeqNum++);
Packit 1fb8d4
Packit 1fb8d4
	if (status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "EncryptMessage failure %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(status), status);
Packit 1fb8d4
		return status;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (Message.cBuffers == 2 && Buffers[0].cbBuffer < nla->ContextSizes.cbSecurityTrailer)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* IMPORTANT: EncryptMessage may not use all the signature space, so we need to shrink the excess between the buffers */
Packit 1fb8d4
		MoveMemory(((BYTE*)Buffers[0].pvBuffer) + Buffers[0].cbBuffer, Buffers[1].pvBuffer, Buffers[1].cbBuffer);
Packit 1fb8d4
		nla->authInfo.cbBuffer = Buffers[0].cbBuffer + Buffers[1].cbBuffer;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return SEC_E_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static SECURITY_STATUS nla_decrypt_ts_credentials(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	int length;
Packit 1fb8d4
	BYTE* buffer;
Packit 1fb8d4
	ULONG pfQOP;
Packit 1fb8d4
	SecBuffer Buffers[2] = { { 0 } };
Packit 1fb8d4
	SecBufferDesc Message;
Packit 1fb8d4
	SECURITY_STATUS status;
Packit 1fb8d4
	const BOOL krb = (_tcsncmp(nla->packageName, KERBEROS_SSP_NAME, ARRAYSIZE(KERBEROS_SSP_NAME)) == 0);
Packit 1fb8d4
	const BOOL nego = (_tcsncmp(nla->packageName, NEGO_SSP_NAME, ARRAYSIZE(NEGO_SSP_NAME)) == 0);
Packit 1fb8d4
	const BOOL ntlm = (_tcsncmp(nla->packageName,  NTLM_SSP_NAME, ARRAYSIZE(NTLM_SSP_NAME)) == 0);
Packit 1fb8d4
Packit 1fb8d4
	if (nla->authInfo.cbBuffer < 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "nla_decrypt_ts_credentials missing authInfo buffer");
Packit 1fb8d4
		return SEC_E_INVALID_TOKEN;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	length = nla->authInfo.cbBuffer;
Packit 1fb8d4
	buffer = (BYTE*) malloc(length);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return SEC_E_INSUFFICIENT_MEMORY;
Packit 1fb8d4
Packit 1fb8d4
	if (krb)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(buffer, nla->authInfo.pvBuffer, length);
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_DATA; /* Wrapped and encrypted TSCredentials */
Packit 1fb8d4
		Buffers[0].cbBuffer = length;
Packit 1fb8d4
		Buffers[0].pvBuffer = buffer;
Packit 1fb8d4
		Message.cBuffers = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (ntlm || nego)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(buffer, nla->authInfo.pvBuffer, length);
Packit 1fb8d4
		Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
Packit 1fb8d4
		Buffers[0].cbBuffer = nla->ContextSizes.cbSecurityTrailer;
Packit 1fb8d4
		Buffers[0].pvBuffer = buffer;
Packit 1fb8d4
		Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
Packit 1fb8d4
		Buffers[1].cbBuffer = length - nla->ContextSizes.cbSecurityTrailer;
Packit 1fb8d4
		Buffers[1].pvBuffer = &buffer[ Buffers[0].cbBuffer ];
Packit 1fb8d4
		Message.cBuffers = 2;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Message.ulVersion = SECBUFFER_VERSION;
Packit 1fb8d4
	Message.pBuffers = (PSecBuffer) &Buffers;
Packit 1fb8d4
	status = nla->table->DecryptMessage(&nla->context, &Message, nla->recvSeqNum++, &pfQOP);
Packit 1fb8d4
Packit 1fb8d4
	if (status != SEC_E_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "DecryptMessage failure %s [0x%08"PRIX32"]",
Packit 1fb8d4
		         GetSecurityStatusString(status), status);
Packit 1fb8d4
		free(buffer);
Packit 1fb8d4
		return status;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!nla_read_ts_credentials(nla, &Buffers[1]))
Packit 1fb8d4
	{
Packit 1fb8d4
		free(buffer);
Packit 1fb8d4
		return SEC_E_INSUFFICIENT_MEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return SEC_E_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static size_t nla_sizeof_nego_token(size_t length)
Packit 1fb8d4
{
Packit 1fb8d4
	length = ber_sizeof_octet_string(length);
Packit 1fb8d4
	length += ber_sizeof_contextual_tag(length);
Packit 1fb8d4
	return length;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static size_t nla_sizeof_nego_tokens(size_t length)
Packit 1fb8d4
{
Packit 1fb8d4
	length = nla_sizeof_nego_token(length);
Packit 1fb8d4
	length += ber_sizeof_sequence_tag(length);
Packit 1fb8d4
	length += ber_sizeof_sequence_tag(length);
Packit 1fb8d4
	length += ber_sizeof_contextual_tag(length);
Packit 1fb8d4
	return length;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static size_t nla_sizeof_pub_key_auth(size_t length)
Packit 1fb8d4
{
Packit 1fb8d4
	length = ber_sizeof_octet_string(length);
Packit 1fb8d4
	length += ber_sizeof_contextual_tag(length);
Packit 1fb8d4
	return length;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static size_t nla_sizeof_auth_info(size_t length)
Packit 1fb8d4
{
Packit 1fb8d4
	length = ber_sizeof_octet_string(length);
Packit 1fb8d4
	length += ber_sizeof_contextual_tag(length);
Packit 1fb8d4
	return length;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static size_t nla_sizeof_client_nonce(size_t length)
Packit 1fb8d4
{
Packit 1fb8d4
	length = ber_sizeof_octet_string(length);
Packit 1fb8d4
	length += ber_sizeof_contextual_tag(length);
Packit 1fb8d4
	return length;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static size_t nla_sizeof_ts_request(size_t length)
Packit 1fb8d4
{
Packit 1fb8d4
	length += ber_sizeof_integer(2);
Packit 1fb8d4
	length += ber_sizeof_contextual_tag(3);
Packit 1fb8d4
	return length;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Send CredSSP message.
Packit 1fb8d4
 * @param credssp
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL nla_send(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL rc = TRUE;
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	size_t ts_request_length;
Packit 1fb8d4
	size_t nego_tokens_length = 0;
Packit 1fb8d4
	size_t pub_key_auth_length = 0;
Packit 1fb8d4
	size_t auth_info_length = 0;
Packit 1fb8d4
	size_t error_code_context_length = 0;
Packit 1fb8d4
	size_t error_code_length = 0;
Packit 1fb8d4
	size_t client_nonce_length = 0;
Packit 1fb8d4
	nego_tokens_length = (nla->negoToken.cbBuffer > 0) ? nla_sizeof_nego_tokens(
Packit 1fb8d4
	                         nla->negoToken.cbBuffer) : 0;
Packit 1fb8d4
	pub_key_auth_length = (nla->pubKeyAuth.cbBuffer > 0) ? nla_sizeof_pub_key_auth(
Packit 1fb8d4
	                          nla->pubKeyAuth.cbBuffer) : 0;
Packit 1fb8d4
	auth_info_length = (nla->authInfo.cbBuffer > 0) ? nla_sizeof_auth_info(nla->authInfo.cbBuffer) : 0;
Packit 1fb8d4
	client_nonce_length = (nla->ClientNonce.cbBuffer > 0) ? nla_sizeof_client_nonce(
Packit 1fb8d4
	                          nla->ClientNonce.cbBuffer) : 0;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->peerVersion >= 3 && nla->peerVersion != 5 && nla->errorCode != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		error_code_length = ber_sizeof_integer(nla->errorCode);
Packit 1fb8d4
		error_code_context_length = ber_sizeof_contextual_tag(error_code_length);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	length = nego_tokens_length + pub_key_auth_length + auth_info_length + error_code_context_length +
Packit 1fb8d4
	         error_code_length + client_nonce_length;
Packit 1fb8d4
	ts_request_length = nla_sizeof_ts_request(length);
Packit 1fb8d4
	s = Stream_New(NULL, ber_sizeof_sequence(ts_request_length));
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* TSRequest */
Packit 1fb8d4
	ber_write_sequence_tag(s, ts_request_length); /* SEQUENCE */
Packit 1fb8d4
	/* [0] version */
Packit 1fb8d4
	ber_write_contextual_tag(s, 0, 3, TRUE);
Packit 1fb8d4
	ber_write_integer(s, nla->version); /* INTEGER */
Packit 1fb8d4
Packit 1fb8d4
	/* [1] negoTokens (NegoData) */
Packit 1fb8d4
	if (nego_tokens_length > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		length = ber_write_contextual_tag(s, 1,
Packit 1fb8d4
		                                  ber_sizeof_sequence(ber_sizeof_sequence(ber_sizeof_sequence_octet_string(nla->negoToken.cbBuffer))),
Packit 1fb8d4
		                                  TRUE); /* NegoData */
Packit 1fb8d4
		length += ber_write_sequence_tag(s,
Packit 1fb8d4
		                                 ber_sizeof_sequence(ber_sizeof_sequence_octet_string(
Packit 1fb8d4
		                                         nla->negoToken.cbBuffer))); /* SEQUENCE OF NegoDataItem */
Packit 1fb8d4
		length += ber_write_sequence_tag(s,
Packit 1fb8d4
		                                 ber_sizeof_sequence_octet_string(nla->negoToken.cbBuffer)); /* NegoDataItem */
Packit 1fb8d4
		length += ber_write_sequence_octet_string(s, 0, (BYTE*) nla->negoToken.pvBuffer,
Packit 1fb8d4
		          nla->negoToken.cbBuffer);  /* OCTET STRING */
Packit 1fb8d4
Packit 1fb8d4
		if (length != nego_tokens_length)
Packit 1fb8d4
		{
Packit 1fb8d4
			Stream_Free(s, TRUE);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* [2] authInfo (OCTET STRING) */
Packit 1fb8d4
	if (auth_info_length > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (ber_write_sequence_octet_string(s, 2, nla->authInfo.pvBuffer,
Packit 1fb8d4
		                                    nla->authInfo.cbBuffer) != auth_info_length)
Packit 1fb8d4
		{
Packit 1fb8d4
			Stream_Free(s, TRUE);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* [3] pubKeyAuth (OCTET STRING) */
Packit 1fb8d4
	if (pub_key_auth_length > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (ber_write_sequence_octet_string(s, 3, nla->pubKeyAuth.pvBuffer,
Packit 1fb8d4
		                                    nla->pubKeyAuth.cbBuffer) != pub_key_auth_length)
Packit 1fb8d4
		{
Packit 1fb8d4
			Stream_Free(s, TRUE);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* [4] errorCode (INTEGER) */
Packit 1fb8d4
	if (error_code_length > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		ber_write_contextual_tag(s, 4, error_code_length, TRUE);
Packit 1fb8d4
		ber_write_integer(s, nla->errorCode);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* [5] clientNonce (OCTET STRING) */
Packit 1fb8d4
	if (client_nonce_length > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (ber_write_sequence_octet_string(s, 5, nla->ClientNonce.pvBuffer,
Packit 1fb8d4
		                                    nla->ClientNonce.cbBuffer) != client_nonce_length)
Packit 1fb8d4
		{
Packit 1fb8d4
			Stream_Free(s, TRUE);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_SealLength(s);
Packit 1fb8d4
Packit 1fb8d4
	if (transport_write(nla->transport, s) < 0)
Packit 1fb8d4
		rc = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return rc;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int nla_decode_ts_request(rdpNla* nla, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	UINT32 version = 0;
Packit 1fb8d4
Packit 1fb8d4
	/* TSRequest */
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length) ||
Packit 1fb8d4
	    !ber_read_contextual_tag(s, 0, &length, TRUE) ||
Packit 1fb8d4
	    !ber_read_integer(s, &version))
Packit 1fb8d4
	{
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (nla->peerVersion == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "CredSSP protocol support %"PRIu32", peer supports %"PRIu32,
Packit 1fb8d4
		         nla->version, version);
Packit 1fb8d4
		nla->peerVersion = version;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* if the peer suddenly changed its version - kick it */
Packit 1fb8d4
	if (nla->peerVersion != version)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "CredSSP peer changed protocol version from %"PRIu32" to %"PRIu32,
Packit 1fb8d4
		         nla->peerVersion, version);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* [1] negoTokens (NegoData) */
Packit 1fb8d4
	if (ber_read_contextual_tag(s, 1, &length, TRUE) != FALSE)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!ber_read_sequence_tag(s, &length) || /* SEQUENCE OF NegoDataItem */
Packit 1fb8d4
		    !ber_read_sequence_tag(s, &length) || /* NegoDataItem */
Packit 1fb8d4
		    !ber_read_contextual_tag(s, 0, &length, TRUE) || /* [0] negoToken */
Packit 1fb8d4
		    !ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
Packit 1fb8d4
		    Stream_GetRemainingLength(s) < length)
Packit 1fb8d4
		{
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!sspi_SecBufferAlloc(&nla->negoToken, length))
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Read(s, nla->negoToken.pvBuffer, length);
Packit 1fb8d4
		nla->negoToken.cbBuffer = length;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* [2] authInfo (OCTET STRING) */
Packit 1fb8d4
	if (ber_read_contextual_tag(s, 2, &length, TRUE) != FALSE)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
Packit 1fb8d4
		    Stream_GetRemainingLength(s) < length)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		if (!sspi_SecBufferAlloc(&nla->authInfo, length))
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Read(s, nla->authInfo.pvBuffer, length);
Packit 1fb8d4
		nla->authInfo.cbBuffer = length;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* [3] pubKeyAuth (OCTET STRING) */
Packit 1fb8d4
	if (ber_read_contextual_tag(s, 3, &length, TRUE) != FALSE)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
Packit 1fb8d4
		    Stream_GetRemainingLength(s) < length)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		if (!sspi_SecBufferAlloc(&nla->pubKeyAuth, length))
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Read(s, nla->pubKeyAuth.pvBuffer, length);
Packit 1fb8d4
		nla->pubKeyAuth.cbBuffer = length;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* [4] errorCode (INTEGER) */
Packit 1fb8d4
	if (nla->peerVersion >= 3)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (ber_read_contextual_tag(s, 4, &length, TRUE) != FALSE)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!ber_read_integer(s, &nla->errorCode))
Packit 1fb8d4
				return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (nla->peerVersion >= 5)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (ber_read_contextual_tag(s, 5, &length, TRUE) != FALSE)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
Packit 1fb8d4
				    Stream_GetRemainingLength(s) < length)
Packit 1fb8d4
					return -1;
Packit 1fb8d4
Packit 1fb8d4
				if (!sspi_SecBufferAlloc(&nla->ClientNonce, length))
Packit 1fb8d4
					return -1;
Packit 1fb8d4
Packit 1fb8d4
				Stream_Read(s, nla->ClientNonce.pvBuffer, length);
Packit 1fb8d4
				nla->ClientNonce.cbBuffer = length;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int nla_recv_pdu(rdpNla* nla, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	if (nla_decode_ts_request(nla, s) < 1)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->errorCode)
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 code;
Packit 1fb8d4
Packit 1fb8d4
		switch (nla->errorCode)
Packit 1fb8d4
		{
Packit 1fb8d4
			case STATUS_PASSWORD_MUST_CHANGE:
Packit 1fb8d4
				code = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case STATUS_PASSWORD_EXPIRED:
Packit 1fb8d4
				code = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case STATUS_ACCOUNT_DISABLED:
Packit 1fb8d4
				code = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case STATUS_LOGON_FAILURE:
Packit 1fb8d4
				code = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case STATUS_WRONG_PASSWORD:
Packit 1fb8d4
				code = FREERDP_ERROR_CONNECT_WRONG_PASSWORD;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case STATUS_ACCESS_DENIED:
Packit 1fb8d4
				code = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case STATUS_ACCOUNT_RESTRICTION:
Packit 1fb8d4
				code = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case STATUS_ACCOUNT_LOCKED_OUT:
Packit 1fb8d4
				code = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case STATUS_ACCOUNT_EXPIRED:
Packit 1fb8d4
				code = FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case STATUS_LOGON_TYPE_NOT_GRANTED:
Packit 1fb8d4
				code = FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				WLog_ERR(TAG, "SPNEGO failed with NTSTATUS: 0x%08"PRIX32"", nla->errorCode);
Packit 1fb8d4
				code = FREERDP_ERROR_AUTHENTICATION_FAILED;
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		freerdp_set_last_error(nla->instance->context, code);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (nla_client_recv(nla) < 1)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int nla_recv(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	s = Stream_New(NULL, 4096);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = transport_read_pdu(nla->transport, s);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "nla_recv() error: %d", status);
Packit 1fb8d4
		Stream_Free(s, TRUE);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (nla_decode_ts_request(nla, s) < 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Free(s, TRUE);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void nla_buffer_print(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	if (nla->negoToken.cbBuffer > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "NLA.negoToken (length = %"PRIu32"):", nla->negoToken.cbBuffer);
Packit 1fb8d4
		winpr_HexDump(TAG, WLOG_DEBUG, nla->negoToken.pvBuffer, nla->negoToken.cbBuffer);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (nla->pubKeyAuth.cbBuffer > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "NLA.pubKeyAuth (length = %"PRIu32"):", nla->pubKeyAuth.cbBuffer);
Packit 1fb8d4
		winpr_HexDump(TAG, WLOG_DEBUG, nla->pubKeyAuth.pvBuffer, nla->pubKeyAuth.cbBuffer);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (nla->authInfo.cbBuffer > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "NLA.authInfo (length = %"PRIu32"):", nla->authInfo.cbBuffer);
Packit 1fb8d4
		winpr_HexDump(TAG, WLOG_DEBUG, nla->authInfo.pvBuffer, nla->authInfo.cbBuffer);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void nla_buffer_free(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	sspi_SecBufferFree(&nla->negoToken);
Packit 1fb8d4
	sspi_SecBufferFree(&nla->pubKeyAuth);
Packit 1fb8d4
	sspi_SecBufferFree(&nla->authInfo);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
LPTSTR nla_make_spn(const char* ServiceClass, const char* hostname)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD status;
Packit 1fb8d4
	DWORD SpnLength;
Packit 1fb8d4
	LPTSTR hostnameX = NULL;
Packit 1fb8d4
	LPTSTR ServiceClassX = NULL;
Packit 1fb8d4
	LPTSTR ServicePrincipalName = NULL;
Packit 1fb8d4
#ifdef UNICODE
Packit 1fb8d4
	ConvertToUnicode(CP_UTF8, 0, hostname, -1, &hostnameX, 0);
Packit 1fb8d4
	ConvertToUnicode(CP_UTF8, 0, ServiceClass, -1, &ServiceClassX, 0);
Packit 1fb8d4
#else
Packit 1fb8d4
	hostnameX = _strdup(hostname);
Packit 1fb8d4
	ServiceClassX = _strdup(ServiceClass);
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	if (!hostnameX || !ServiceClassX)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(hostnameX);
Packit 1fb8d4
		free(ServiceClassX);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!ServiceClass)
Packit 1fb8d4
	{
Packit 1fb8d4
		ServicePrincipalName = (LPTSTR) _tcsdup(hostnameX);
Packit 1fb8d4
		free(ServiceClassX);
Packit 1fb8d4
		free(hostnameX);
Packit 1fb8d4
		return ServicePrincipalName;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	SpnLength = 0;
Packit 1fb8d4
	status = DsMakeSpn(ServiceClassX, hostnameX, NULL, 0, NULL, &SpnLength, NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (status != ERROR_BUFFER_OVERFLOW)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(ServiceClassX);
Packit 1fb8d4
		free(hostnameX);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ServicePrincipalName = (LPTSTR) calloc(SpnLength, sizeof(TCHAR));
Packit 1fb8d4
Packit 1fb8d4
	if (!ServicePrincipalName)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(ServiceClassX);
Packit 1fb8d4
		free(hostnameX);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = DsMakeSpn(ServiceClassX, hostnameX, NULL, 0, NULL, &SpnLength, ServicePrincipalName);
Packit 1fb8d4
Packit 1fb8d4
	if (status != ERROR_SUCCESS)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(ServicePrincipalName);
Packit 1fb8d4
		free(ServiceClassX);
Packit 1fb8d4
		free(hostnameX);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(ServiceClassX);
Packit 1fb8d4
	free(hostnameX);
Packit 1fb8d4
	return ServicePrincipalName;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Create new CredSSP state machine.
Packit 1fb8d4
 * @param transport
Packit 1fb8d4
 * @return new CredSSP state machine.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
rdpNla* nla_new(freerdp* instance, rdpTransport* transport, rdpSettings* settings)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpNla* nla = (rdpNla*) calloc(1, sizeof(rdpNla));
Packit 1fb8d4
Packit 1fb8d4
	if (!nla)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	nla->identity = calloc(1, sizeof(SEC_WINNT_AUTH_IDENTITY));
Packit 1fb8d4
Packit 1fb8d4
	if (!nla->identity)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(nla);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	nla->instance = instance;
Packit 1fb8d4
	nla->settings = settings;
Packit 1fb8d4
	nla->server = settings->ServerMode;
Packit 1fb8d4
	nla->transport = transport;
Packit 1fb8d4
	nla->sendSeqNum = 0;
Packit 1fb8d4
	nla->recvSeqNum = 0;
Packit 1fb8d4
	nla->version = 6;
Packit 1fb8d4
	ZeroMemory(&nla->ClientNonce, sizeof(SecBuffer));
Packit 1fb8d4
	ZeroMemory(&nla->negoToken, sizeof(SecBuffer));
Packit 1fb8d4
	ZeroMemory(&nla->pubKeyAuth, sizeof(SecBuffer));
Packit 1fb8d4
	ZeroMemory(&nla->authInfo, sizeof(SecBuffer));
Packit 1fb8d4
	SecInvalidateHandle(&nla->context);
Packit 1fb8d4
Packit 1fb8d4
	if (settings->NtlmSamFile)
Packit 1fb8d4
	{
Packit 1fb8d4
		nla->SamFile = _strdup(settings->NtlmSamFile);
Packit 1fb8d4
Packit 1fb8d4
		if (!nla->SamFile)
Packit 1fb8d4
			goto cleanup;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* init to 0 or we end up freeing a bad pointer if the alloc fails */
Packit 1fb8d4
	if (!sspi_SecBufferAlloc(&nla->ClientNonce, NonceLength))
Packit 1fb8d4
		goto cleanup;
Packit 1fb8d4
Packit 1fb8d4
	/* generate random 32-byte nonce */
Packit 1fb8d4
	if (winpr_RAND(nla->ClientNonce.pvBuffer, NonceLength) < 0)
Packit 1fb8d4
		goto cleanup;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->server)
Packit 1fb8d4
	{
Packit 1fb8d4
		LONG status;
Packit 1fb8d4
		HKEY hKey;
Packit 1fb8d4
		DWORD dwType;
Packit 1fb8d4
		DWORD dwSize;
Packit 1fb8d4
		status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, SERVER_KEY,
Packit 1fb8d4
		                       0, KEY_READ | KEY_WOW64_64KEY, &hKey);
Packit 1fb8d4
Packit 1fb8d4
		if (status != ERROR_SUCCESS)
Packit 1fb8d4
			return nla;
Packit 1fb8d4
Packit 1fb8d4
		status = RegQueryValueEx(hKey, _T("SspiModule"), NULL, &dwType, NULL, &dwSize);
Packit 1fb8d4
Packit 1fb8d4
		if (status != ERROR_SUCCESS)
Packit 1fb8d4
		{
Packit 1fb8d4
			RegCloseKey(hKey);
Packit 1fb8d4
			return nla;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		nla->SspiModule = (LPTSTR) malloc(dwSize + sizeof(TCHAR));
Packit 1fb8d4
Packit 1fb8d4
		if (!nla->SspiModule)
Packit 1fb8d4
		{
Packit 1fb8d4
			RegCloseKey(hKey);
Packit 1fb8d4
			goto cleanup;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		status = RegQueryValueEx(hKey, _T("SspiModule"), NULL, &dwType,
Packit 1fb8d4
		                         (BYTE*) nla->SspiModule, &dwSize);
Packit 1fb8d4
Packit 1fb8d4
		if (status == ERROR_SUCCESS)
Packit 1fb8d4
			WLog_INFO(TAG, "Using SSPI Module: %s", nla->SspiModule);
Packit 1fb8d4
Packit 1fb8d4
		RegCloseKey(hKey);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return nla;
Packit 1fb8d4
cleanup:
Packit 1fb8d4
	nla_free(nla);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Free CredSSP state machine.
Packit 1fb8d4
 * @param credssp
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void nla_free(rdpNla* nla)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!nla)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	if (nla->table)
Packit 1fb8d4
	{
Packit 1fb8d4
		SECURITY_STATUS status;
Packit 1fb8d4
Packit 1fb8d4
		if (SecIsValidHandle(&nla->credentials))
Packit 1fb8d4
		{
Packit 1fb8d4
			status = nla->table->FreeCredentialsHandle(&nla->credentials);
Packit 1fb8d4
Packit 1fb8d4
			if (status != SEC_E_OK)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_WARN(TAG, "FreeCredentialsHandle status %s [0x%08"PRIX32"]",
Packit 1fb8d4
				          GetSecurityStatusString(status), status);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			SecInvalidateHandle(&nla->credentials);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		status = nla->table->DeleteSecurityContext(&nla->context);
Packit 1fb8d4
Packit 1fb8d4
		if (status != SEC_E_OK)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_WARN(TAG, "DeleteSecurityContext status %s [0x%08"PRIX32"]",
Packit 1fb8d4
			          GetSecurityStatusString(status), status);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(nla->SamFile);
Packit 1fb8d4
	nla->SamFile = NULL;
Packit 1fb8d4
	sspi_SecBufferFree(&nla->ClientNonce);
Packit 1fb8d4
	sspi_SecBufferFree(&nla->PublicKey);
Packit 1fb8d4
	sspi_SecBufferFree(&nla->tsCredentials);
Packit 1fb8d4
	free(nla->ServicePrincipalName);
Packit 1fb8d4
	nla_identity_free(nla->identity);
Packit 1fb8d4
	free(nla);
Packit 1fb8d4
}