Blame libfreerdp/core/nla.c

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