You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1692 lines
74 KiB
1692 lines
74 KiB
/****************************************************************************/
|
|
/* asmapi.c */
|
|
/* */
|
|
/* Security Manager API */
|
|
/* */
|
|
/* Copyright (C) 1997-1999 Microsoft Corporation */
|
|
/****************************************************************************/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
#define TRC_FILE "asmapi"
|
|
#define pTRCWd (pRealSMHandle->pWDHandle)
|
|
|
|
#include <adcg.h>
|
|
#include <aprot.h>
|
|
#include <acomapi.h>
|
|
#include <nwdwapi.h>
|
|
#include <anmapi.h>
|
|
#include <asmint.h>
|
|
#include <slicense.h>
|
|
#include <regapi.h>
|
|
|
|
#define DC_INCLUDE_DATA
|
|
#include <asmdata.c>
|
|
#undef DC_INCLUDE_DATA
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_GetDataSize */
|
|
/* */
|
|
/* Purpose: Returns size of per-instance SM data required */
|
|
/* */
|
|
/* Returns: size of data required */
|
|
/* */
|
|
/* Operation: SM stores per-instance data in a piece of memory allocated */
|
|
/* by WDW. This function returns the size of the data required. */
|
|
/* A pointer to this data (the 'SM Handle') is passed into all */
|
|
/* subsequent SM functions. */
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SM_GetDataSize(void)
|
|
{
|
|
DC_BEGIN_FN("SM_GetDataSize");
|
|
|
|
DC_END_FN();
|
|
return(sizeof(SM_HANDLE_DATA) + NM_GetDataSize());
|
|
} /* SM_GetDataSize */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_GetEncryptionMethods */
|
|
/* */
|
|
/* Purpose: Return the security settings supported by this server for use */
|
|
/* in shadowing operations. The shadow target server dictates */
|
|
/* the final selected method & level. */
|
|
/* */
|
|
/* Params: pSMHandle - SM handle */
|
|
/****************************************************************************/
|
|
VOID RDPCALL SM_GetEncryptionMethods(PVOID pSMHandle, PRNS_UD_CS_SEC pSecurityData)
|
|
{
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
ULONG ulMethods ;
|
|
|
|
DC_BEGIN_FN("SM_SM_GetEncryptionMethods");
|
|
|
|
// Allow a FIPS shadow client to remote control servers with lesser
|
|
// encryption strength
|
|
ulMethods = pRealSMHandle->encryptionMethodsSupported;
|
|
if (ulMethods & SM_FIPS_ENCRYPTION_FLAG) {
|
|
ulMethods |= (SM_128BIT_ENCRYPTION_FLAG | SM_40BIT_ENCRYPTION_FLAG | SM_56BIT_ENCRYPTION_FLAG);
|
|
TRC_ALT((TB, "Allow FIPS client to shadow a lower security target: %lx",
|
|
ulMethods));
|
|
}
|
|
else {
|
|
// Allow a 128-bit shadow client to remote control servers with lesser
|
|
// encryption strength
|
|
if (ulMethods & SM_128BIT_ENCRYPTION_FLAG) {
|
|
ulMethods |= (SM_40BIT_ENCRYPTION_FLAG | SM_56BIT_ENCRYPTION_FLAG);
|
|
TRC_ALT((TB, "Allow 128-bit client to shadow a lower security target: %lx",
|
|
ulMethods));
|
|
}
|
|
}
|
|
|
|
if( !pRealSMHandle->frenchClient ) {
|
|
pSecurityData->encryptionMethods = ulMethods;
|
|
pSecurityData->extEncryptionMethods = 0;
|
|
|
|
}
|
|
else {
|
|
pSecurityData->encryptionMethods = 0;
|
|
pSecurityData->extEncryptionMethods = ulMethods;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_GetDefaultSecuritySettings */
|
|
/* */
|
|
/* Purpose: Returns the security settings supported by this server */
|
|
/* for shadowing operations. */
|
|
/* */
|
|
/* Params: pClientSecurityData - GCC user data identical to a standard */
|
|
/* conference connection. */
|
|
/****************************************************************************/
|
|
NTSTATUS RDPCALL SM_GetDefaultSecuritySettings(PRNS_UD_CS_SEC pClientSecurityData)
|
|
{
|
|
pClientSecurityData->header.type = RNS_UD_CS_SEC_ID;
|
|
pClientSecurityData->header.length = sizeof(*pClientSecurityData);
|
|
|
|
pClientSecurityData->encryptionMethods =
|
|
SM_40BIT_ENCRYPTION_FLAG |
|
|
SM_56BIT_ENCRYPTION_FLAG |
|
|
SM_128BIT_ENCRYPTION_FLAG |
|
|
SM_FIPS_ENCRYPTION_FLAG;
|
|
|
|
pClientSecurityData->extEncryptionMethods = 0;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_Init */
|
|
/* */
|
|
/* Purpose: Initialize SM */
|
|
/* */
|
|
/* Params: pSMHandle - SM handle */
|
|
/* pWDHandle - WD Handle (to be passed back on WDW_SMCallback) */
|
|
/****************************************************************************/
|
|
NTSTATUS RDPCALL SM_Init(PVOID pSMHandle,
|
|
PTSHARE_WD pWDHandle,
|
|
BOOLEAN bOldShadow)
|
|
{
|
|
BOOL rc;
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
unsigned i;
|
|
unsigned regRc;
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
INT32 regValue;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
static UINT32 keyInfoBuffer[16];
|
|
ULONG keyInfoLength;
|
|
HANDLE RegistryKeyHandle;
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
|
|
|
|
DC_BEGIN_FN("SM_Init");
|
|
|
|
SM_CHECK_STATE(SM_EVT_INIT);
|
|
|
|
/************************************************************************/
|
|
/* Store the WDW Handle before we do anything else, as we can't trace */
|
|
/* until we do so. */
|
|
/************************************************************************/
|
|
pRealSMHandle->pWDHandle = pWDHandle;
|
|
pRealSMHandle->bForwardDataToSC = FALSE;
|
|
|
|
/************************************************************************/
|
|
/* Get default DONTDISPLAYLASTUSERNAME setting */
|
|
/************************************************************************/
|
|
pWDHandle->fDontDisplayLastUserName = FALSE;
|
|
|
|
RtlInitUnicodeString(&UnicodeString, W2K_GROUP_POLICY_WINLOGON_KEY);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
status = ZwOpenKey(&RegistryKeyHandle, GENERIC_READ, &ObjectAttributes);
|
|
if (NT_SUCCESS(status)) {
|
|
RtlInitUnicodeString(&UnicodeString, WIN_DONTDISPLAYLASTUSERNAME);
|
|
KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)keyInfoBuffer;
|
|
status = ZwQueryValueKey(RegistryKeyHandle,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
KeyValueInformation,
|
|
sizeof(keyInfoBuffer),
|
|
&keyInfoLength);
|
|
|
|
// For W2K the value should be a DWORD.
|
|
if ((NT_SUCCESS(status)) &&
|
|
(KeyValueInformation->Type == REG_DWORD) &&
|
|
(KeyValueInformation->DataLength >= sizeof(DWORD))) {
|
|
pWDHandle->fDontDisplayLastUserName =
|
|
(BOOLEAN)(*(PDWORD)(KeyValueInformation->Data) == 1);
|
|
}
|
|
|
|
ZwClose(RegistryKeyHandle);
|
|
}
|
|
|
|
// Starting with W2K the place where the DontDislpayLastUserName policy
|
|
// is store has moved to another key (W2K_GROUP_POLICY_WINLOGON_KEY). But
|
|
// we still have to look at the old key in case we could not read the
|
|
// value in the post W2K key (the policy is not definde). We want to follow
|
|
// the winlogon behavior in the console.
|
|
// In case there is a value set in the new policy key we will use that
|
|
// value. In case there isn't one we look in the old place. As I said this
|
|
// is what winlogon does.
|
|
//
|
|
if (!NT_SUCCESS(status)) {
|
|
RtlInitUnicodeString(&UnicodeString, WINLOGON_KEY);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
status = ZwOpenKey(&RegistryKeyHandle, GENERIC_READ, &ObjectAttributes);
|
|
if (NT_SUCCESS(status)) {
|
|
RtlInitUnicodeString(&UnicodeString, WIN_DONTDISPLAYLASTUSERNAME);
|
|
KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)keyInfoBuffer;
|
|
status = ZwQueryValueKey(RegistryKeyHandle,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
KeyValueInformation,
|
|
sizeof(keyInfoBuffer),
|
|
&keyInfoLength);
|
|
if (NT_SUCCESS(status)) {
|
|
pWDHandle->fDontDisplayLastUserName =
|
|
(BOOLEAN)(KeyValueInformation->Data[0] == '1');
|
|
}
|
|
|
|
ZwClose(RegistryKeyHandle);
|
|
}
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* We don't run without encryption in a retail build */
|
|
/************************************************************************/
|
|
|
|
TRC_NRM((TB, "encryption level is %d", pRealSMHandle->encryptionLevel));
|
|
|
|
if (pRealSMHandle->encryptionLevel < 1)
|
|
{
|
|
TRC_ALT((TB, "Forcing encryption back to level 1!"));
|
|
pRealSMHandle->encryptionLevel = 1;
|
|
}
|
|
|
|
#ifdef INSTRUM_TRACK_DISCARDED
|
|
pRealSMHandle->nDiscardNonVCPDUWhenDead = 0;
|
|
pRealSMHandle->nDiscardPDUBadState = 0;
|
|
pRealSMHandle->nDiscardVCDataWhenDead = 0;
|
|
#endif
|
|
|
|
if (pRealSMHandle->encryptionLevel == 0) {
|
|
TRC_ALT((TB, "Not encrypting"));
|
|
|
|
pRealSMHandle->encryptionMethodsSupported = 0;
|
|
pRealSMHandle->encrypting = FALSE;
|
|
pRealSMHandle->encryptDisplayData = FALSE;
|
|
pRealSMHandle->encryptingLicToClient = FALSE;
|
|
pRealSMHandle->encryptionMethodSelected = 0;
|
|
pRealSMHandle->frenchClient = FALSE;
|
|
pRealSMHandle->recvdClientRandom = FALSE;
|
|
pRealSMHandle->bSessionKeysMade = FALSE;
|
|
pRealSMHandle->encryptHeaderLen = 0;
|
|
pRealSMHandle->encryptHeaderLenIfForceEncrypt = sizeof(RNS_SECURITY_HEADER1);
|
|
}
|
|
else {
|
|
pRealSMHandle->encrypting = TRUE;
|
|
pRealSMHandle->frenchClient = FALSE;
|
|
TRC_NRM((TB, "Encrypting"));
|
|
|
|
/********************************************************************/
|
|
/* encrypt the display data if encryptionLevel is 2 (or above). */
|
|
/********************************************************************/
|
|
if (pRealSMHandle->encryptionLevel == 1) {
|
|
pRealSMHandle->encryptDisplayData = FALSE;
|
|
pRealSMHandle->encryptHeaderLen = sizeof(RNS_SECURITY_HEADER);
|
|
pRealSMHandle->encryptHeaderLenIfForceEncrypt = sizeof(RNS_SECURITY_HEADER1);
|
|
TRC_NRM((TB, "Displaydata not encrypted"));
|
|
}
|
|
else {
|
|
pRealSMHandle->encryptDisplayData = TRUE;
|
|
pRealSMHandle->encryptHeaderLen = sizeof(RNS_SECURITY_HEADER1);
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* for down level compatibility, support both 40bit, 56bit */
|
|
/* and 128bit default. */
|
|
/********************************************************************/
|
|
pRealSMHandle->encryptionMethodsSupported =
|
|
SM_128BIT_ENCRYPTION_FLAG |
|
|
SM_56BIT_ENCRYPTION_FLAG |
|
|
SM_40BIT_ENCRYPTION_FLAG |
|
|
SM_FIPS_ENCRYPTION_FLAG;
|
|
|
|
/********************************************************************/
|
|
/* encrypt 128bit and above if encryptionLevel is 3 */
|
|
/********************************************************************/
|
|
if (pRealSMHandle->encryptionLevel == 3) {
|
|
pRealSMHandle->encryptionMethodsSupported =
|
|
SM_128BIT_ENCRYPTION_FLAG | SM_FIPS_ENCRYPTION_FLAG;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* encrypt in FIPS only if encryption level is 4 or above. */
|
|
/********************************************************************/
|
|
if (pRealSMHandle->encryptionLevel >= 4) {
|
|
pRealSMHandle->encryptionMethodsSupported = SM_FIPS_ENCRYPTION_FLAG;
|
|
}
|
|
|
|
TRC_NRM((TB, "Encryption methods supported %08lx: Level %ld\n",
|
|
pRealSMHandle->encryptionMethodsSupported,
|
|
pRealSMHandle->encryptionLevel));
|
|
|
|
/********************************************************************/
|
|
/* initally set the encryption method selected as */
|
|
/* SM_56BIT_ENCRYPTION_FLAG, later it will be set according to the */
|
|
/* client support. */
|
|
/********************************************************************/
|
|
pRealSMHandle->encryptionMethodSelected = SM_56BIT_ENCRYPTION_FLAG;
|
|
|
|
/********************************************************************/
|
|
/* misc init. */
|
|
/********************************************************************/
|
|
pRealSMHandle->recvdClientRandom = FALSE;
|
|
pRealSMHandle->bSessionKeysMade = FALSE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* We do not know the certificate type used in the key exchange till */
|
|
/* after the exchange has taken place. */
|
|
/************************************************************************/
|
|
pRealSMHandle->CertType = CERT_TYPE_INVALID;
|
|
|
|
#ifdef USE_LICENSE
|
|
/************************************************************************/
|
|
/* Initialize the Server license manager */
|
|
/************************************************************************/
|
|
pRealSMHandle->pLicenseHandle = SLicenseInit();
|
|
if (!pRealSMHandle->pLicenseHandle)
|
|
{
|
|
TRC_ERR((TB, "Failed to initialize License Manager"));
|
|
DC_QUIT;
|
|
}
|
|
pWDHandle->pSLicenseHandle = pRealSMHandle->pLicenseHandle;
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* Initialize the console buffer stuff */
|
|
/************************************************************************/
|
|
InitializeListHead(&pRealSMHandle->consoleBufferList);
|
|
pRealSMHandle->consoleBufferCount = 0;
|
|
|
|
/************************************************************************/
|
|
/* Finally, initialize the Network Manager */
|
|
/************************************************************************/
|
|
rc = NM_Init(pRealSMHandle->pWDHandle->pNMInfo,
|
|
pSMHandle,
|
|
pWDHandle,
|
|
pWDHandle->hDomainKernel);
|
|
if (!rc)
|
|
{
|
|
TRC_ERR((TB, "Failed to init NM"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Update the state */
|
|
/************************************************************************/
|
|
SM_SET_STATE(SM_STATE_INITIALIZED);
|
|
|
|
/************************************************************************/
|
|
/* All worked */
|
|
/************************************************************************/
|
|
status = STATUS_SUCCESS;
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
/************************************************************************/
|
|
/* If anything failed, clean up. Must be done after calling */
|
|
/* FreeContextBuffer as this clears the function table. */
|
|
/************************************************************************/
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
TRC_ERR((TB, "Something failed - clean up"));
|
|
SMFreeInitResources(pRealSMHandle);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return(status);
|
|
} /* SM_Init */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_Term */
|
|
/****************************************************************************/
|
|
void RDPCALL SM_Term(PVOID pSMHandle)
|
|
{
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
DC_BEGIN_FN("SM_Term");
|
|
|
|
/************************************************************************/
|
|
/* SM_Term is called from WD_Close. This can be called on the */
|
|
/* listening stack (and maybe in other situations) where SM_Init has */
|
|
/* not been called. Check for state != SM_STATE_STARTED before going */
|
|
/* any further. */
|
|
/* */
|
|
/* AND DON'T TRACE IF SM_INIT HASN'T BEEN CALLED. */
|
|
/************************************************************************/
|
|
if (pRealSMHandle->state == SM_STATE_STARTED)
|
|
{
|
|
DC_QUIT;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Free connection resources */
|
|
/************************************************************************/
|
|
TRC_NRM((TB, "Free connection resources"));
|
|
SMFreeConnectResources(pRealSMHandle);
|
|
|
|
/************************************************************************/
|
|
/* Free initialization resources */
|
|
/************************************************************************/
|
|
TRC_NRM((TB, "Free initialization resources"));
|
|
SMFreeInitResources(pRealSMHandle);
|
|
|
|
#ifdef USE_LICENSE
|
|
/************************************************************************/
|
|
/* Terminate License Manager */
|
|
/************************************************************************/
|
|
SLicenseTerm(pRealSMHandle->pLicenseHandle);
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* Terminate Network Manager */
|
|
/************************************************************************/
|
|
NM_Term(pRealSMHandle->pWDHandle->pNMInfo);
|
|
|
|
/************************************************************************/
|
|
/* Terminate FIPS */
|
|
/************************************************************************/
|
|
TSFIPS_Term(&(pRealSMHandle->FIPSData));
|
|
|
|
/************************************************************************/
|
|
/* Free the console buffers */
|
|
/************************************************************************/
|
|
while (!IsListEmpty(&pRealSMHandle->consoleBufferList)) {
|
|
PSM_CONSOLE_BUFFER pBlock;
|
|
|
|
pBlock = CONTAINING_RECORD(pRealSMHandle->consoleBufferList.Flink, SM_CONSOLE_BUFFER, links);
|
|
|
|
RemoveEntryList(&pBlock->links);
|
|
|
|
COM_Free(pBlock);
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* Update the state */
|
|
/************************************************************************/
|
|
SM_SET_STATE(SM_STATE_STARTED);
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
} /* SM_Term */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_Connect */
|
|
/* */
|
|
/* Purpose: Accept or Reject an incoming Client */
|
|
/* */
|
|
/* Returns: TRUE - Connect started OK */
|
|
/* FALSE - Connect failed to start */
|
|
/* */
|
|
/* Params: ppSMHandle - handle for subsequent SM calls on behalf of */
|
|
/* this Client */
|
|
/* pUserDataIn - SM user data received from Client */
|
|
/* pNetUserData - Net user data received from Client */
|
|
/* bOldShadow - indicates this is a B3 shadow request */
|
|
/* */
|
|
/* Operation: Note that this function completes asynchronously. The caller */
|
|
/* must wait for an SM_CB_CONNECTED or SM_CB_DISCONNECTED */
|
|
/* callback to find out whether the Connect succeeded or failed. */
|
|
/****************************************************************************/
|
|
NTSTATUS RDPCALL SM_Connect(PVOID pSMHandle,
|
|
PRNS_UD_CS_SEC pUserDataIn,
|
|
PRNS_UD_CS_NET pNetUserData,
|
|
BOOLEAN bOldShadow)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
BOOL rc = FALSE;
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
UINT32 encMethodPicked = 0;
|
|
|
|
DC_BEGIN_FN("SM_Connect");
|
|
|
|
SM_CHECK_STATE(SM_EVT_CONNECT);
|
|
|
|
pRealSMHandle->pUserData = NULL;
|
|
|
|
/************************************************************************/
|
|
/* pick a matching encryption method. */
|
|
/************************************************************************/
|
|
TRC_ALT((TB, "Client supports encryption: %lx",
|
|
pUserDataIn->encryptionMethods));
|
|
TRC_NRM((TB, "Server supports encryption: %lx",
|
|
pRealSMHandle->encryptionMethodsSupported));
|
|
|
|
/************************************************************************/
|
|
/* if the server does not require any encryption .. */
|
|
/************************************************************************/
|
|
if( pRealSMHandle->encryptionMethodsSupported == 0 ) {
|
|
|
|
encMethodPicked = 0;
|
|
goto DC_ENC_PICKED;
|
|
}
|
|
|
|
//
|
|
// French Client (old and new) set the encryptionMethods value 0.
|
|
//
|
|
|
|
if (pUserDataIn->encryptionMethods == 0) {
|
|
|
|
pRealSMHandle->frenchClient = TRUE;
|
|
|
|
//
|
|
// check to see the request is from a new client, if so
|
|
// use the new field to set the appropriate encryption level.
|
|
//
|
|
|
|
if( pUserDataIn->header.length >= sizeof(RNS_UD_CS_SEC) ) {
|
|
|
|
pUserDataIn->encryptionMethods = pUserDataIn->extEncryptionMethods;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// force old client to use 40-bit encryption.
|
|
//
|
|
|
|
pUserDataIn->encryptionMethods = SM_40BIT_ENCRYPTION_FLAG;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* pick a matching encryption method. */
|
|
/************************************************************************/
|
|
TRC_ALT((TB, "French Client supports encryption: %lx",
|
|
pUserDataIn->encryptionMethods));
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* if the client only supports FIPS */
|
|
/************************************************************************/
|
|
if (pUserDataIn->encryptionMethods == SM_FIPS_ENCRYPTION_FLAG) {
|
|
/********************************************************************/
|
|
/* if the server supports FIPS .... */
|
|
/********************************************************************/
|
|
if (pRealSMHandle->encryptionMethodsSupported & SM_FIPS_ENCRYPTION_FLAG) {
|
|
encMethodPicked = SM_FIPS_ENCRYPTION_FLAG;
|
|
goto DC_ENC_PICKED;
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* if the server only supports FIPS .... */
|
|
/********************************************************************/
|
|
if (pRealSMHandle->encryptionMethodsSupported == SM_FIPS_ENCRYPTION_FLAG) {
|
|
/************************************************************************/
|
|
/* if the client supports FIPS */
|
|
/************************************************************************/
|
|
if (pUserDataIn->encryptionMethods & SM_FIPS_ENCRYPTION_FLAG) {
|
|
encMethodPicked = SM_FIPS_ENCRYPTION_FLAG;
|
|
goto DC_ENC_PICKED;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* if the client supports 128 bit */
|
|
/************************************************************************/
|
|
if (pUserDataIn->encryptionMethods & SM_128BIT_ENCRYPTION_FLAG) {
|
|
/********************************************************************/
|
|
/* if the server supports 128bit .... */
|
|
/********************************************************************/
|
|
if (pRealSMHandle->encryptionMethodsSupported &
|
|
SM_128BIT_ENCRYPTION_FLAG) {
|
|
encMethodPicked = SM_128BIT_ENCRYPTION_FLAG;
|
|
goto DC_ENC_PICKED;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* if the client supports 56 bit */
|
|
/************************************************************************/
|
|
if( pUserDataIn->encryptionMethods & SM_56BIT_ENCRYPTION_FLAG ) {
|
|
/********************************************************************/
|
|
/* if the server supports 56bit ... */
|
|
/********************************************************************/
|
|
if( pRealSMHandle->encryptionMethodsSupported &
|
|
SM_56BIT_ENCRYPTION_FLAG ) {
|
|
encMethodPicked = SM_56BIT_ENCRYPTION_FLAG;
|
|
goto DC_ENC_PICKED;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* if the client supports 40 bit */
|
|
/************************************************************************/
|
|
if( pUserDataIn->encryptionMethods & SM_40BIT_ENCRYPTION_FLAG ) {
|
|
/********************************************************************/
|
|
/* if the server supports 40bit ... */
|
|
/********************************************************************/
|
|
if( pRealSMHandle->encryptionMethodsSupported &
|
|
SM_40BIT_ENCRYPTION_FLAG ) {
|
|
encMethodPicked = SM_40BIT_ENCRYPTION_FLAG;
|
|
goto DC_ENC_PICKED;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* if we are here, we did not find a match */
|
|
/************************************************************************/
|
|
TRC_ERR((TB, "Failed to match encryption package: %lx",
|
|
pUserDataIn->encryptionMethods));
|
|
status = STATUS_ENCRYPTION_FAILED;
|
|
|
|
/****************************************************************/
|
|
/* Log an error and disconnect the Client */
|
|
/****************************************************************/
|
|
if (pRealSMHandle->pWDHandle->StackClass == Stack_Primary) {
|
|
WDW_LogAndDisconnect(
|
|
pRealSMHandle->pWDHandle, TRUE,
|
|
Log_RDP_ENC_EncPkgMismatch,
|
|
NULL,
|
|
0);
|
|
|
|
}
|
|
DC_QUIT;
|
|
|
|
DC_ENC_PICKED:
|
|
|
|
TRC_ALT((TB, "Encryption Method=%d, Level=%ld, Display=%ld",
|
|
encMethodPicked,
|
|
pRealSMHandle->encryptionLevel,
|
|
pRealSMHandle->encryptDisplayData));
|
|
|
|
/************************************************************************/
|
|
/* remember the encryption method that we picked. */
|
|
/************************************************************************/
|
|
pRealSMHandle->encryptionMethodSelected = encMethodPicked;
|
|
|
|
// For FIPS, do initialization
|
|
// Even the enc method is not FIPS, we need to do initialization since we might
|
|
// shadow a FIPS later
|
|
if (TSFIPS_Init(&(pRealSMHandle->FIPSData))) {
|
|
TRC_NRM((TB, "Init Fips succeed\n"));
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Init Fips Failed\n"));
|
|
|
|
// This is only a fatal failure if FIPS was selected as the encryption
|
|
// method. If we chose something other than FIPS, then we should
|
|
// proceed, although shadowing a FIPS session later should fail.
|
|
//
|
|
if (SM_FIPS_ENCRYPTION_FLAG == encMethodPicked)
|
|
{
|
|
status = STATUS_ENCRYPTION_FAILED;
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Build user data to return to Client */
|
|
/************************************************************************/
|
|
pRealSMHandle->pUserData =
|
|
(PRNS_UD_SC_SEC)COM_Malloc(sizeof(RNS_UD_SC_SEC));
|
|
if (pRealSMHandle->pUserData == NULL)
|
|
{
|
|
TRC_ERR((TB, "Failed to allocated %d bytes for user data",
|
|
sizeof(RNS_UD_SC_SEC)));
|
|
status = STATUS_NO_MEMORY;
|
|
DC_QUIT;
|
|
}
|
|
|
|
pRealSMHandle->pUserData->header.type = RNS_UD_SC_SEC_ID;
|
|
pRealSMHandle->pUserData->header.length = sizeof(RNS_UD_SC_SEC);
|
|
pRealSMHandle->pUserData->encryptionMethod =
|
|
(bOldShadow ? 0xffffffff : encMethodPicked);
|
|
pRealSMHandle->pUserData->encryptionLevel =
|
|
pRealSMHandle->encryptionLevel;
|
|
|
|
/************************************************************************/
|
|
/* Call Network Manager */
|
|
/************************************************************************/
|
|
SM_SET_STATE(SM_STATE_NM_CONNECTING);
|
|
|
|
TRC_NRM((TB, "Connect to Network Manager"));
|
|
rc = NM_Connect(pRealSMHandle->pWDHandle->pNMInfo, pNetUserData);
|
|
|
|
if (rc != TRUE)
|
|
{
|
|
status = STATUS_CANCELLED;
|
|
DC_QUIT;
|
|
}
|
|
|
|
// Shadow/passthru stacks start out with no encryption. If the target end
|
|
// determines that the client server supports encryption, an encrypted
|
|
// context will be set up by rdpwsx.
|
|
if (pRealSMHandle->pWDHandle->StackClass != Stack_Primary) {
|
|
pRealSMHandle->pWDHandle->connected = TRUE;
|
|
pRealSMHandle->encrypting = FALSE;
|
|
pRealSMHandle->encryptDisplayData = FALSE;
|
|
pRealSMHandle->encryptHeaderLen = 0;
|
|
pRealSMHandle->encryptHeaderLenIfForceEncrypt = 0;
|
|
SM_SET_STATE(SM_STATE_CONNECTED);
|
|
SM_SET_STATE(SM_STATE_SC_REGISTERED);
|
|
SM_Dead(pRealSMHandle, FALSE);
|
|
TRC_ALT((TB, "%s stack: Suspending encryption during key exchange",
|
|
pRealSMHandle->pWDHandle->StackClass == Stack_Shadow ?
|
|
"Shadow" : "Passthru"));
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
/************************************************************************/
|
|
/* If anything failed, release resources */
|
|
/************************************************************************/
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
TRC_ERR((TB, "Failed - free connect resources"));
|
|
SMFreeConnectResources(pRealSMHandle);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return status;
|
|
} /* SM_Connect */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_Disconnect */
|
|
/* */
|
|
/* Purpose: Disconnect from a Client */
|
|
/* */
|
|
/* Returns: TRUE - Disconnect started OK */
|
|
/* FALSE - Disconnect failed */
|
|
/* */
|
|
/* Params: pSMHandle - SM handle */
|
|
/* */
|
|
/* Operation: Detach the user from the domain. */
|
|
/* Note that this function completes asynchronously. The caller */
|
|
/* must wait for an SM_CB_DISCONNECTED callback to find whether */
|
|
/* the Disconnect succeeded or failed. */
|
|
/****************************************************************************/
|
|
BOOL RDPCALL SM_Disconnect(PVOID pSMHandle)
|
|
{
|
|
BOOL rc = FALSE;
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
|
|
DC_BEGIN_FN("SM_Disconnect");
|
|
|
|
if (SM_CHECK_STATE_Q(SM_EVT_DISCONNECT)) {
|
|
// Call Network Layer.
|
|
SM_SET_STATE(SM_STATE_DISCONNECTING);
|
|
rc = NM_Disconnect(pRealSMHandle->pWDHandle->pNMInfo);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
void SM_BreakConnectionWorker(PTSHARE_WD pTSWd, PVOID pParam)
|
|
{
|
|
NTSTATUS status;
|
|
ICA_CHANNEL_COMMAND Command;
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pTSWd->pSmInfo;
|
|
|
|
DC_BEGIN_FN("SM_BreakConnectionWorker");
|
|
|
|
Command.Header.Command = ICA_COMMAND_BROKEN_CONNECTION;
|
|
Command.BrokenConnection.Reason = Broken_Unexpected;
|
|
Command.BrokenConnection.Source = BrokenSource_Server;
|
|
|
|
status = IcaChannelInput(pTSWd->pContext, Channel_Command, 0, NULL, (BYTE *)&Command, sizeof(Command));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
TRC_NRM((TB, "Can't send ICA_COMMAND_BROKEN_CONNECTION, error code 0x%08x", status));
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_AllocBuffer */
|
|
/* */
|
|
/* Purpose: Allocate a buffer */
|
|
/* */
|
|
/* Returns: TRUE - buffer allocated OK */
|
|
/* FALSE - failed to allocate buffer */
|
|
/* */
|
|
/* Params: pSMHandle - SM Handle */
|
|
/* ppBuffer - pointer to packet (returned) */
|
|
/* bufferLen - length of buffer */
|
|
/* fForceEncrypt - Always encrypt or not */
|
|
/* Used only if encryptDisplayData is FALSE */
|
|
/* i.e., encryptionLevel is less than 2 */
|
|
/****************************************************************************/
|
|
NTSTATUS __fastcall SM_AllocBuffer(PVOID pSMHandle,
|
|
PPVOID ppBuffer,
|
|
UINT32 bufferLen,
|
|
BOOLEAN fWait,
|
|
BOOLEAN fForceEncrypt)
|
|
{
|
|
NTSTATUS status;
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
PRNS_SECURITY_HEADER2 pSecHeader2;
|
|
UINT32 newBufferLen, padLen;
|
|
|
|
DC_BEGIN_FN("SM_AllocBuffer");
|
|
|
|
if (SM_CHECK_STATE_Q(SM_EVT_ALLOCBUFFER)) {
|
|
if (pRealSMHandle->pWDHandle->StackClass != Stack_Console) {
|
|
|
|
// If FIPS, adjust the BufferLen to the whole FIPS_BLOCK_LEN size
|
|
if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG) {
|
|
newBufferLen = TSFIPS_AdjustDataLen(bufferLen);
|
|
padLen = newBufferLen - bufferLen;
|
|
bufferLen = newBufferLen;
|
|
}
|
|
|
|
// Add enough space for a security header. We always send at least
|
|
// a short security header.
|
|
if (pRealSMHandle->encryptDisplayData) {
|
|
bufferLen += pRealSMHandle->encryptHeaderLen;
|
|
}
|
|
else {
|
|
if (!fForceEncrypt) {
|
|
bufferLen += pRealSMHandle->encryptHeaderLen;
|
|
}
|
|
else {
|
|
bufferLen += pRealSMHandle->encryptHeaderLenIfForceEncrypt;
|
|
}
|
|
}
|
|
|
|
status = NM_AllocBuffer(pRealSMHandle->pWDHandle->pNMInfo, ppBuffer,
|
|
bufferLen, fWait);
|
|
if ( STATUS_SUCCESS == status ) {
|
|
TRC_NRM((TB, "Alloc buffer size %d at %p", bufferLen,
|
|
*ppBuffer));
|
|
|
|
// If FIPS, fill in padSize in Header
|
|
if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG) {
|
|
pSecHeader2 = (PRNS_SECURITY_HEADER2)(*ppBuffer);
|
|
pSecHeader2->padlen = (TSUINT8)padLen;
|
|
}
|
|
|
|
// Adjust return pointer for security header.
|
|
if (pRealSMHandle->encryptDisplayData) {
|
|
*ppBuffer = (PVOID)((PBYTE)(*ppBuffer) +
|
|
pRealSMHandle->encryptHeaderLen);
|
|
}
|
|
else {
|
|
if (!fForceEncrypt) {
|
|
*ppBuffer = (PVOID)((PBYTE)(*ppBuffer) +
|
|
pRealSMHandle->encryptHeaderLen);
|
|
}
|
|
else {
|
|
*ppBuffer = (PVOID)((PBYTE)(*ppBuffer) +
|
|
pRealSMHandle->encryptHeaderLenIfForceEncrypt);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( status == STATUS_IO_TIMEOUT && TRUE == fWait ) {
|
|
|
|
//
|
|
// WARNING : Disconnect client on first allocation failure, different
|
|
// result ranging from TS client AV to immediate lock up on
|
|
// re-connect if this scheme is changed disconnect on 2nd
|
|
// try, 3rd try ...
|
|
//
|
|
|
|
TRC_NRM((TB, "Failed to alloc buffer size %d, disconnecting client", bufferLen));
|
|
|
|
// 254514 STRESS: TS: Tdtcp!TdRawWrite needs synchronization with the write complete routine
|
|
// Calling the following function will hold the connection lock in tdtcp TDSyncWrite to wait
|
|
// for all pending IRP to finish. This will cause deadlock in the system.
|
|
//WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, FALSE, Log_RDP_AllocOutBuf, NULL, 0);
|
|
|
|
// return STATUS_IO_TIMEOUT back to caller,
|
|
// looks like we use this return code.
|
|
|
|
if (!pRealSMHandle->bDisconnectWorkerSent) {
|
|
status = IcaQueueWorkItem(pRealSMHandle->pWDHandle->pContext,
|
|
SM_BreakConnectionWorker,
|
|
0,
|
|
ICALOCK_DRIVER);
|
|
if (!NT_SUCCESS(status)) {
|
|
TRC_NRM((TB, "IcaQueueWorkItem failed, error code 0x%08x", status));
|
|
} else {
|
|
pRealSMHandle->bDisconnectWorkerSent = TRUE;
|
|
}
|
|
}
|
|
|
|
status = STATUS_IO_TIMEOUT;
|
|
}
|
|
else {
|
|
|
|
// NM_AllocBuffer will have traced appropriately if the alloc
|
|
// failed, no need for TRC_ERR here.
|
|
|
|
TRC_NRM((TB, "Failed to alloc buffer size %d", bufferLen));
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
PSM_CONSOLE_BUFFER pBlock;
|
|
// For a console stack, just alloc a suitable block - we're not
|
|
// actually going to send it!
|
|
TRC_NRM((TB, "console stack requesting %d bytes", bufferLen));
|
|
|
|
*ppBuffer = NULL;
|
|
|
|
if (!IsListEmpty(&pRealSMHandle->consoleBufferList)) {
|
|
|
|
pBlock = CONTAINING_RECORD(pRealSMHandle->consoleBufferList.Flink, SM_CONSOLE_BUFFER, links);
|
|
|
|
do {
|
|
// we could improve this by taking the smaller of the suitable blocks
|
|
// it can be also faster if we order the list
|
|
if (pBlock->length >= bufferLen) {
|
|
RemoveEntryList(&pBlock->links);
|
|
pRealSMHandle->consoleBufferCount -= 1;
|
|
*ppBuffer = pBlock->buffer;
|
|
break;
|
|
}
|
|
|
|
pBlock = CONTAINING_RECORD(pBlock->links.Flink, SM_CONSOLE_BUFFER, links);
|
|
|
|
} while(pBlock != (PSM_CONSOLE_BUFFER)(&pRealSMHandle->consoleBufferList));
|
|
|
|
}
|
|
|
|
if (*ppBuffer == NULL) {
|
|
// allocate a new block
|
|
pBlock = COM_Malloc(sizeof(SM_CONSOLE_BUFFER) + bufferLen);
|
|
if (pBlock != NULL) {
|
|
|
|
pBlock->buffer = (PVOID)((PBYTE)pBlock + sizeof(SM_CONSOLE_BUFFER));
|
|
pBlock->length = bufferLen;
|
|
|
|
*ppBuffer = pBlock->buffer;
|
|
} else {
|
|
*ppBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
if (*ppBuffer != NULL) {
|
|
TRC_NRM((TB, "and returning buffer at %p", *ppBuffer));
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "failed to alloc buffer"));
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
status = STATUS_UNSUCCESSFUL; // right error code?
|
|
}
|
|
|
|
DC_END_FN();
|
|
return status;
|
|
} /* SM_AllocBuffer */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_FreeBuffer */
|
|
/* */
|
|
/* Purpose: Free a buffer */
|
|
/* */
|
|
/* Params: pSMHandle - SM Handle */
|
|
/* pBuffer - buffer to free */
|
|
/* fForceEncrypt - Always encrypt or not */
|
|
/* Used only if encryptDisplayData is FALSE */
|
|
/* i.e., encryptionLevel is less than 2 */
|
|
/****************************************************************************/
|
|
void __fastcall SM_FreeBuffer(PVOID pSMHandle, PVOID pBuffer, BOOLEAN fForceEncrypt)
|
|
{
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
|
|
DC_BEGIN_FN("SM_FreeBuffer");
|
|
|
|
// Note that, unlike SM_AllocBuffer, we don't check the state table here,
|
|
// since if we were able to allocate the buffer, we should always be
|
|
// able to free it. Otherwise we may end up leaking buffers during
|
|
// warn states.
|
|
if (pRealSMHandle->pWDHandle->StackClass != Stack_Console) {
|
|
// Adjust for security header.
|
|
if (pRealSMHandle->encryptDisplayData) {
|
|
pBuffer = (PVOID)((PBYTE)pBuffer -
|
|
pRealSMHandle->encryptHeaderLen);
|
|
}
|
|
else {
|
|
if (!fForceEncrypt) {
|
|
pBuffer = (PVOID)((PBYTE)pBuffer -
|
|
pRealSMHandle->encryptHeaderLen);
|
|
}
|
|
else {
|
|
pBuffer = (PVOID)((PBYTE)pBuffer -
|
|
pRealSMHandle->encryptHeaderLenIfForceEncrypt);
|
|
}
|
|
}
|
|
|
|
TRC_NRM((TB, "Free buffer at %p", pBuffer));
|
|
NM_FreeBuffer(pRealSMHandle->pWDHandle->pNMInfo, pBuffer);
|
|
}
|
|
else {
|
|
PSM_CONSOLE_BUFFER pBlock;
|
|
|
|
pBlock = (PSM_CONSOLE_BUFFER)((PBYTE)pBuffer - sizeof(SM_CONSOLE_BUFFER));
|
|
|
|
// For console session, insert it in the list of freed blocks.
|
|
TRC_NRM((TB, "console stack freeing buffer at %p", pBuffer));
|
|
|
|
// Since this block was freshly used,
|
|
// insert it at the beginning of the list.
|
|
InsertHeadList(&pRealSMHandle->consoleBufferList, &pBlock->links);
|
|
|
|
if (pRealSMHandle->consoleBufferCount >= 2) {
|
|
PVOID listEntry;
|
|
|
|
// Free a buffer since we have enough buffers.
|
|
// Remove and free the last one (tail of the list),
|
|
// assuming it's the less used.
|
|
listEntry = RemoveTailList(&pRealSMHandle->consoleBufferList);
|
|
pBlock = CONTAINING_RECORD(listEntry, SM_CONSOLE_BUFFER, links);
|
|
|
|
COM_Free(pBlock);
|
|
|
|
} else {
|
|
pRealSMHandle->consoleBufferCount += 1;
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
} /* SM_FreeBuffer */
|
|
|
|
|
|
/****************************************************************************/
|
|
// SM_SendData
|
|
//
|
|
// Sends a network buffer. Note that upper layers assume that, if the send
|
|
// fails, the buffer will get deallocated. Returns FALSE on failure.
|
|
//
|
|
// Params: pSMHandle - SM Handle
|
|
// pData - data to send
|
|
// dataLen - length if data to send
|
|
// priority - priority to use
|
|
// channelID - channel ID (ignored in this version)
|
|
// bFastPathOutput - whether pData contains fast-path output
|
|
// flags - the flag that should be put in RNS_SECURITY_HEADER.flags
|
|
// fForceEncrypt - Always encrypt or not
|
|
// Used only if encryptDisplayData is FALSE
|
|
// i.e., encryptionLevel is less than 2
|
|
/****************************************************************************/
|
|
BOOL __fastcall SM_SendData(
|
|
PVOID pSMHandle,
|
|
PVOID pData,
|
|
UINT32 dataLen,
|
|
UINT32 priority,
|
|
UINT32 channelID,
|
|
BOOL bFastPathOutput,
|
|
UINT16 flags,
|
|
BOOLEAN fForceEncrypt)
|
|
{
|
|
BOOL rc = FALSE;
|
|
PRNS_SECURITY_HEADER pSecHeader;
|
|
PRNS_SECURITY_HEADER2 pSecHeader2;
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
UINT32 sendLen;
|
|
BOOL fUseSafeChecksum = FALSE;
|
|
UINT32 encryptHeaderLen = 0;
|
|
|
|
DC_BEGIN_FN("SM_SendData");
|
|
|
|
if (SM_CHECK_STATE_Q(SM_EVT_SENDDATA)) {
|
|
if (pRealSMHandle->pWDHandle->StackClass != Stack_Console) {
|
|
// Send the packet unchanged if we're not encrypting at all.
|
|
if ((!pRealSMHandle->encrypting) && (!fForceEncrypt)) {
|
|
TRC_DATA_DBG("Send never-encrypted data", pData, dataLen);
|
|
rc = NM_SendData(pRealSMHandle->pWDHandle->pNMInfo,
|
|
(BYTE *)pData, dataLen, priority, channelID,
|
|
bFastPathOutput | NM_NO_SECURITY_HEADER);
|
|
DC_QUIT;
|
|
}
|
|
|
|
// Get interesting pointers and lengths.
|
|
if ((!pRealSMHandle->encryptDisplayData) && !fForceEncrypt) {
|
|
// S->C is not encrypted
|
|
encryptHeaderLen = pRealSMHandle->encryptHeaderLen;
|
|
sendLen = dataLen + encryptHeaderLen;
|
|
}
|
|
else {
|
|
if (pRealSMHandle->encryptDisplayData) {
|
|
// S->C is encrypted
|
|
encryptHeaderLen = pRealSMHandle->encryptHeaderLen;
|
|
}
|
|
else {
|
|
// S->C is not encrypted, but we want to encrypt this packet
|
|
encryptHeaderLen = pRealSMHandle->encryptHeaderLenIfForceEncrypt;
|
|
}
|
|
|
|
if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG) {
|
|
pSecHeader2 = (PRNS_SECURITY_HEADER2)((PBYTE)pData - encryptHeaderLen);
|
|
pSecHeader2->padlen = (TSUINT8)TSFIPS_AdjustDataLen(dataLen) - dataLen;
|
|
sendLen = dataLen + encryptHeaderLen + pSecHeader2->padlen;
|
|
|
|
pSecHeader2->length = sizeof(RNS_SECURITY_HEADER2);
|
|
pSecHeader2->version = TSFIPS_VERSION1;
|
|
}
|
|
else {
|
|
sendLen = dataLen + encryptHeaderLen;
|
|
}
|
|
}
|
|
|
|
pSecHeader = (PRNS_SECURITY_HEADER)((PBYTE)pData - encryptHeaderLen);
|
|
|
|
|
|
// Encrypt display data if we are asked to do so.
|
|
if ((!pRealSMHandle->encryptDisplayData) && !fForceEncrypt) {
|
|
pSecHeader->flags = 0;
|
|
// We are implicitly not setting TS_OUTPUT_FASTPATH_ENCRYPTED
|
|
// bit in bFastPathOutput before passing to NM_SendData.
|
|
TRC_DBG((TB, "Data not encrypted"));
|
|
}
|
|
else {
|
|
// Check to see if we need to update the session key.
|
|
if (pRealSMHandle->encryptCount == UPDATE_SESSION_KEY_COUNT) {
|
|
rc = TRUE;
|
|
// Don't need to update the session key if using FIPS
|
|
if (pRealSMHandle->encryptionMethodSelected != SM_FIPS_ENCRYPTION_FLAG) {
|
|
rc = UpdateSessionKey(
|
|
pRealSMHandle->startEncryptKey,
|
|
pRealSMHandle->currentEncryptKey,
|
|
pRealSMHandle->encryptionMethodSelected,
|
|
pRealSMHandle->keyLength,
|
|
&pRealSMHandle->rc4EncryptKey,
|
|
pRealSMHandle->encryptionLevel);
|
|
}
|
|
if (rc) {
|
|
// Reset counter.
|
|
pRealSMHandle->encryptCount = 0;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "SM failed to update session key"));
|
|
WDW_LogAndDisconnect(
|
|
pRealSMHandle->pWDHandle, TRUE,
|
|
Log_RDP_ENC_UpdateSessionKeyFailed,
|
|
NULL,
|
|
0);
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
TRC_DATA_DBG("Data buffer before encryption", pData, dataLen);
|
|
|
|
|
|
//
|
|
// Disable the safe checksumming in the shadow pipe as there
|
|
// is currently no way to reliably do caps negotiation in the
|
|
// pipe.
|
|
//
|
|
// This is not an issue because we don't have fastpath in
|
|
// the shadow pipe and as a result of this we're not vulnerable
|
|
// to the checksum frequency analysis security vulnerability.
|
|
//
|
|
//
|
|
fUseSafeChecksum = pRealSMHandle->useSafeChecksumMethod &&
|
|
(pRealSMHandle->pWDHandle->StackClass == Stack_Primary);
|
|
|
|
if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG) {
|
|
rc = TSFIPS_EncryptData(
|
|
&(pRealSMHandle->FIPSData),
|
|
pData,
|
|
dataLen + pSecHeader2->padlen,
|
|
pSecHeader2->padlen,
|
|
pSecHeader2->dataSignature,
|
|
pRealSMHandle->totalEncryptCount);
|
|
}
|
|
else {
|
|
rc = EncryptData(
|
|
pRealSMHandle->encryptionLevel,
|
|
pRealSMHandle->currentEncryptKey,
|
|
&pRealSMHandle->rc4EncryptKey,
|
|
pRealSMHandle->keyLength,
|
|
pData,
|
|
dataLen,
|
|
pRealSMHandle->macSaltKey,
|
|
((PRNS_SECURITY_HEADER1)pSecHeader)->dataSignature,
|
|
fUseSafeChecksum,
|
|
pRealSMHandle->totalEncryptCount);
|
|
}
|
|
if (rc) {
|
|
TRC_DBG((TB, "Data encrypted"));
|
|
TRC_DATA_DBG("Data buffer after encryption", pData,
|
|
dataLen);
|
|
|
|
// Successfully encrypted a packet, increment the
|
|
// encryption counter and set the header.
|
|
pRealSMHandle->encryptCount++;
|
|
pRealSMHandle->totalEncryptCount++;
|
|
TRC_ASSERT(((flags == RNS_SEC_ENCRYPT) ||
|
|
(flags == RDP_SEC_REDIRECTION_PKT3) ||
|
|
(flags == (RNS_SEC_ENCRYPT | RNS_SEC_LICENSE_PKT | RDP_SEC_LICENSE_ENCRYPT_CS))),
|
|
(TB,"SM_SendData shouldn't get this flag %d", flags));
|
|
pSecHeader->flags = flags;
|
|
if (fUseSafeChecksum) {
|
|
bFastPathOutput |= TS_OUTPUT_FASTPATH_SECURE_CHECKSUM;
|
|
pSecHeader->flags |= RDP_SEC_SECURE_CHECKSUM;
|
|
}
|
|
bFastPathOutput |= TS_OUTPUT_FASTPATH_ENCRYPTED;
|
|
}
|
|
else {
|
|
// If we failed, the in-place encryption probably
|
|
// destroyed part or all of the data. The stream is
|
|
// now corrupted, we need to disconnect.
|
|
TRC_ERR((TB, "SM failed to encrypt data"));
|
|
WDW_LogAndDisconnect(
|
|
pRealSMHandle->pWDHandle, TRUE,
|
|
Log_RDP_ENC_EncryptFailed,
|
|
NULL,
|
|
0);
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
// Send it!
|
|
rc = NM_SendData(pRealSMHandle->pWDHandle->pNMInfo, (BYTE *)pSecHeader,
|
|
sendLen, priority, channelID, bFastPathOutput);
|
|
}
|
|
else {
|
|
// For console session, simply claim to have sent it.
|
|
TRC_NRM((TB, "console stack sending buffer at %p", pData));
|
|
rc = TRUE;
|
|
|
|
// Note that we will have to free it.
|
|
SM_FreeBuffer(pSMHandle, pData, fForceEncrypt);
|
|
}
|
|
}
|
|
else {
|
|
// Bad state - we need to free the data.
|
|
TRC_ALT((TB,"Freeing buffer on bad state"));
|
|
SM_FreeBuffer(pSMHandle, pData, fForceEncrypt);
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return rc;
|
|
} /* SM_SendData */
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_Dead */
|
|
/****************************************************************************/
|
|
void RDPCALL SM_Dead(PVOID pSMHandle, BOOL dead)
|
|
{
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
|
|
DC_BEGIN_FN("SM_Dead");
|
|
|
|
pRealSMHandle->dead = (BOOLEAN)dead;
|
|
NM_Dead(pRealSMHandle->pWDHandle->pNMInfo, dead);
|
|
if (dead)
|
|
{
|
|
/********************************************************************/
|
|
/* SM_Dead(TRUE) can be called in any state to kill SM. Don't */
|
|
/* check the existing state - simply set the new state to */
|
|
/* DISCONNECTING. */
|
|
/********************************************************************/
|
|
TRC_ALT((TB, "SM Dead - change state to DISCONNECTING"));
|
|
SM_SET_STATE(SM_STATE_DISCONNECTING);
|
|
}
|
|
else
|
|
{
|
|
/********************************************************************/
|
|
/* SM_Dead(FALSE) is called on (re)connect. The SM state will be */
|
|
/* - SC_REGISTERED on connect */
|
|
/* - SM_DISCONNECTING on reconnect */
|
|
/* In both cases, set the state to SC_REGISTERED */
|
|
/********************************************************************/
|
|
SM_CHECK_STATE(SM_EVT_ALIVE);
|
|
TRC_ALT((TB, "SM Alive - change state to SC_REGISTERED"));
|
|
SM_SET_STATE(SM_STATE_SC_REGISTERED);
|
|
pRealSMHandle->bDisconnectWorkerSent = FALSE;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
} /* SM_Dead */
|
|
|
|
|
|
#ifdef USE_LICENSE
|
|
/****************************************************************************/
|
|
/* Name: SM_LicenseOK */
|
|
/****************************************************************************/
|
|
void RDPCALL SM_LicenseOK(PVOID pSMHandle)
|
|
{
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
|
|
DC_BEGIN_FN("SM_LicenseOK");
|
|
|
|
TRC_NRM((TB, "Licensing Done"));
|
|
SM_SET_STATE(SM_STATE_CONNECTED);
|
|
|
|
DC_END_FN();
|
|
} /* SM_LicenseOK */
|
|
#endif
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_GetSecurityData */
|
|
/* */
|
|
/* Purpose: Retrieve security data. This will be the encrypted client */
|
|
/* random for a Primary or Shadow connection. For passthru */
|
|
/* stacks the shadow server random and certificate is returned. */
|
|
/* */
|
|
/* Params: pSMHandle - SM handle */
|
|
/* INOUT PSD_IOCTL - pointer to received IOCtl */
|
|
/****************************************************************************/
|
|
NTSTATUS RDPCALL SM_GetSecurityData(PVOID pSMHandle, PSD_IOCTL pSdIoctl)
|
|
{
|
|
NTSTATUS status;
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
PSECURITYTIMEOUT pSecurityTimeout = (PSECURITYTIMEOUT)
|
|
pSdIoctl->InputBuffer;
|
|
|
|
DC_BEGIN_FN("SM_GetSecurityData");
|
|
|
|
// Wait for the connected indication from SM.
|
|
TRC_ERR((TB, "About to wait for security data"));
|
|
|
|
if (pSdIoctl->InputBufferLength == sizeof(SECURITYTIMEOUT)) {
|
|
status = WDW_WaitForConnectionEvent(pRealSMHandle->pWDHandle,
|
|
pRealSMHandle->pWDHandle->pSecEvent,
|
|
pSecurityTimeout->ulTimeout);
|
|
}
|
|
else {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
TRC_ERR((TB, "Bogus timeout value: %ld", pSecurityTimeout->ulTimeout));
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRC_DBG((TB, "Back from wait for security data"));
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
TRC_ERR((TB, "SM connected indication timed out: (%lx), msec=%ld",
|
|
status, pSecurityTimeout->ulTimeout));
|
|
status = STATUS_IO_TIMEOUT;
|
|
|
|
DC_QUIT;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* check to see the given buffer is sufficient. */
|
|
/********************************************************************/
|
|
if ((pSdIoctl->OutputBuffer == NULL) ||
|
|
(pSdIoctl->OutputBufferLength <=
|
|
pRealSMHandle->encClientRandomLen)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
DC_QUIT;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* check to see security info is available. */
|
|
/********************************************************************/
|
|
TRC_ASSERT((pRealSMHandle->encryptionMethodSelected != 0),
|
|
(TB,"SM_GetSecurityData is called when encryption is not ON"));
|
|
if (pRealSMHandle->encryptionMethodSelected == 0) {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRC_ASSERT((pRealSMHandle->recvdClientRandom == TRUE),
|
|
(TB,"SM_GetSecurityData issued before the client random received"));
|
|
if (pRealSMHandle->recvdClientRandom == FALSE) {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
DC_QUIT;
|
|
}
|
|
|
|
if (pRealSMHandle->pEncClientRandom == NULL) {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRC_ASSERT((pRealSMHandle->encClientRandomLen != 0 ),
|
|
(TB,"SM_GetSecurityData invalid pEncClientRandom buffer"));
|
|
if (pRealSMHandle->encClientRandomLen == 0) {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
DC_QUIT;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* copy return data. */
|
|
/********************************************************************/
|
|
memcpy(
|
|
pSdIoctl->OutputBuffer,
|
|
pRealSMHandle->pEncClientRandom,
|
|
pRealSMHandle->encClientRandomLen);
|
|
|
|
/********************************************************************/
|
|
/* set returned buffer size. */
|
|
/********************************************************************/
|
|
pSdIoctl->BytesReturned = pRealSMHandle->encClientRandomLen;
|
|
|
|
/********************************************************************/
|
|
/* Free up the client pEncClientRandom Buffer, we don't need this */
|
|
/* any more. */
|
|
/********************************************************************/
|
|
COM_Free(pRealSMHandle->pEncClientRandom);
|
|
pRealSMHandle->pEncClientRandom = NULL;
|
|
pRealSMHandle->encClientRandomLen = 0;
|
|
|
|
/************************************************************************/
|
|
/* All worked OK */
|
|
/************************************************************************/
|
|
status = STATUS_SUCCESS;
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return (status);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_SetSecurityData */
|
|
/* */
|
|
/* Purpose: Set security data and compute session key. */
|
|
/* */
|
|
/* Params: pSMHandle - SM Handle */
|
|
/* pSecinfo - pointer to random key pair */
|
|
/****************************************************************************/
|
|
NTSTATUS RDPCALL SM_SetSecurityData(PVOID pSMHandle, PSECINFO pSecInfo)
|
|
{
|
|
BOOL rc;
|
|
NTSTATUS status;
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
|
|
DC_BEGIN_FN("SM_SetSecurityData");
|
|
|
|
|
|
/************************************************************************/
|
|
/* use the given client and server random key pairs and arrive at */
|
|
/* session keys. */
|
|
/************************************************************************/
|
|
if ((pRealSMHandle->pWDHandle->StackClass == Stack_Primary) ||
|
|
(pRealSMHandle->pWDHandle->StackClass == Stack_Shadow)) {
|
|
if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG) {
|
|
rc = TSFIPS_MakeSessionKeys(&(pRealSMHandle->FIPSData), (LPRANDOM_KEYS_PAIR)&pSecInfo->KeyPair, NULL, FALSE);
|
|
}
|
|
else {
|
|
rc = MakeSessionKeys(
|
|
(LPRANDOM_KEYS_PAIR)&pSecInfo->KeyPair,
|
|
pRealSMHandle->startEncryptKey,
|
|
&pRealSMHandle->rc4EncryptKey,
|
|
pRealSMHandle->startDecryptKey,
|
|
&pRealSMHandle->rc4DecryptKey,
|
|
pRealSMHandle->macSaltKey,
|
|
pRealSMHandle->encryptionMethodSelected,
|
|
&pRealSMHandle->keyLength,
|
|
pRealSMHandle->encryptionLevel );
|
|
}
|
|
}
|
|
|
|
// Passthru stack looks like a client
|
|
else {
|
|
if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG) {
|
|
rc = TSFIPS_MakeSessionKeys(&(pRealSMHandle->FIPSData), (LPRANDOM_KEYS_PAIR)&pSecInfo->KeyPair, NULL, TRUE);
|
|
}
|
|
else {
|
|
rc = MakeSessionKeys(
|
|
(LPRANDOM_KEYS_PAIR)&pSecInfo->KeyPair,
|
|
pRealSMHandle->startDecryptKey,
|
|
&pRealSMHandle->rc4DecryptKey,
|
|
pRealSMHandle->startEncryptKey,
|
|
&pRealSMHandle->rc4EncryptKey,
|
|
pRealSMHandle->macSaltKey,
|
|
pRealSMHandle->encryptionMethodSelected,
|
|
&pRealSMHandle->keyLength,
|
|
pRealSMHandle->encryptionLevel );
|
|
}
|
|
}
|
|
|
|
if (!rc) {
|
|
TRC_ERR((TB, "Could not create session keys!"));
|
|
status = STATUS_UNSUCCESSFUL;
|
|
DC_QUIT;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* validate the key length returned. */
|
|
/************************************************************************/
|
|
if (pRealSMHandle->encryptionMethodSelected != SM_FIPS_ENCRYPTION_FLAG) {
|
|
if (pRealSMHandle->encryptionMethodSelected == SM_128BIT_ENCRYPTION_FLAG) {
|
|
TRC_ASSERT((pRealSMHandle->keyLength == MAX_SESSION_KEY_SIZE),
|
|
(TB,"Invalid session key length"));
|
|
}
|
|
else {
|
|
TRC_ASSERT((pRealSMHandle->keyLength == (MAX_SESSION_KEY_SIZE / 2)),
|
|
(TB,"Invalid session key length"));
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* copy start session key to current. */
|
|
/************************************************************************/
|
|
memcpy(
|
|
pRealSMHandle->currentEncryptKey,
|
|
pRealSMHandle->startEncryptKey,
|
|
MAX_SESSION_KEY_SIZE);
|
|
memcpy(
|
|
pRealSMHandle->currentDecryptKey,
|
|
pRealSMHandle->startDecryptKey,
|
|
MAX_SESSION_KEY_SIZE);
|
|
}
|
|
|
|
pRealSMHandle->encryptCount = 0;
|
|
pRealSMHandle->decryptCount = 0;
|
|
pRealSMHandle->totalDecryptCount = 0;
|
|
pRealSMHandle->totalEncryptCount = 0;
|
|
pRealSMHandle->bSessionKeysMade = TRUE;
|
|
|
|
// Whenever we change the state of encrypting, we need to make sure
|
|
// we get the right header size for buffer allocations. If encrypting
|
|
// if FALSE, the header size is zero.
|
|
pRealSMHandle->encrypting = TRUE;
|
|
if (pRealSMHandle->encryptionLevel == 1) {
|
|
pRealSMHandle->encryptHeaderLen = sizeof(RNS_SECURITY_HEADER);
|
|
pRealSMHandle->encryptDisplayData = FALSE;
|
|
if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG)
|
|
pRealSMHandle->encryptHeaderLenIfForceEncrypt = sizeof(RNS_SECURITY_HEADER2);
|
|
else
|
|
pRealSMHandle->encryptHeaderLenIfForceEncrypt = sizeof(RNS_SECURITY_HEADER1);
|
|
}
|
|
else if (pRealSMHandle->encryptionLevel >= 2) {
|
|
if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG)
|
|
pRealSMHandle->encryptHeaderLen = sizeof(RNS_SECURITY_HEADER2);
|
|
else
|
|
pRealSMHandle->encryptHeaderLen = sizeof(RNS_SECURITY_HEADER1);
|
|
pRealSMHandle->encryptDisplayData = TRUE;
|
|
}
|
|
|
|
TRC_ALT((TB, "%s stack -> encryption %s: level=%ld, method=%ld, display=%ld",
|
|
pRealSMHandle->pWDHandle->StackClass == Stack_Primary ? "Primary" :
|
|
(pRealSMHandle->pWDHandle->StackClass == Stack_Shadow ? "Shadow" :
|
|
"PassThru"),
|
|
rc ? "ON" : "OFF",
|
|
pRealSMHandle->encryptionLevel,
|
|
pRealSMHandle->encryptionMethodSelected,
|
|
pRealSMHandle->encryptDisplayData));
|
|
|
|
/************************************************************************/
|
|
/* Remember the certificate type that was used for the key exchange */
|
|
/************************************************************************/
|
|
pRealSMHandle->CertType = pSecInfo->CertType;
|
|
|
|
/************************************************************************/
|
|
/* All worked OK */
|
|
/************************************************************************/
|
|
status = STATUS_SUCCESS;
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return (status);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_SetEncryptionParams */
|
|
/* */
|
|
/* Purpose: Updates the encryption level and method. Used to set */
|
|
/* negotiated encryption level for passthru stack. */
|
|
/* */
|
|
/* Params: pSMHandle - SM Handle */
|
|
/* ulLevel - negotiated encryption level */
|
|
/* ulMethod - negotiated encryption method */
|
|
/****************************************************************************/
|
|
NTSTATUS RDPCALL SM_SetEncryptionParams(
|
|
PVOID pSMHandle,
|
|
ULONG ulLevel,
|
|
ULONG ulMethod)
|
|
{
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
|
|
DC_BEGIN_FN("SM_SetEncryptionParams");
|
|
|
|
// The passthru stack is simulating a client for the target server. As
|
|
// such, if we negotiated client input encryption, we've got to turn on
|
|
// output encryption for this stack since it conveys all client input
|
|
// to the target server.
|
|
if (ulLevel == 1) {
|
|
ulLevel = 2;
|
|
TRC_ALT((TB, "Passthru stack switching to duplex encryption."));
|
|
}
|
|
|
|
pRealSMHandle->encryptionLevel = ulLevel;
|
|
pRealSMHandle->encryptionMethodSelected = ulMethod;
|
|
|
|
DC_END_FN();
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_IsSecurityExchangeCompleted */
|
|
/* */
|
|
/* Purpose: Ask SM if the security exchange protocol has already been */
|
|
/* completed. */
|
|
/* */
|
|
/* Returns: TRUE if the protocol has already been completed or FALSE */
|
|
/* otherwise. */
|
|
/* */
|
|
/* Params: pSMHandle - SM Handle */
|
|
/* pCertType - The type of certificate that is used in the */
|
|
/* security exchange. */
|
|
/****************************************************************************/
|
|
BOOL RDPCALL SM_IsSecurityExchangeCompleted(
|
|
PVOID pSMHandle,
|
|
CERT_TYPE *pCertType)
|
|
{
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
|
|
DC_BEGIN_FN("SM_IsSecurityExchangeCompleted");
|
|
|
|
*pCertType = pRealSMHandle->CertType;
|
|
|
|
DC_END_FN();
|
|
return pRealSMHandle->encrypting;
|
|
}
|
|
|
|
#ifdef DC_DEBUG
|
|
|
|
/****************************************************************************/
|
|
// SMCheckState
|
|
//
|
|
// Debug-only embodiment of the SM_CHECK_STATE logic.
|
|
/****************************************************************************/
|
|
BOOL RDPCALL SMCheckState(PSM_HANDLE_DATA pRealSMHandle, unsigned event)
|
|
{
|
|
BOOL rc;
|
|
|
|
DC_BEGIN_FN("SMCheckState");
|
|
|
|
if (smStateTable[event][pRealSMHandle->state] == SM_TABLE_OK) {
|
|
rc = TRUE;
|
|
}
|
|
else {
|
|
rc = FALSE;
|
|
if (smStateTable[event][pRealSMHandle->state] == SM_TABLE_WARN) {
|
|
TRC_ALT((TB, "Unusual event %s in state %s",
|
|
smEventName[event], smStateName[pRealSMHandle->state]));
|
|
}
|
|
else {
|
|
TRC_ABORT((TB, "Invalid event %s in state %s",
|
|
smEventName[event], smStateName[pRealSMHandle->state]));
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/* Name: SM_SetSafeChecksumMethod
|
|
/*
|
|
/* Purpose: Sets flag to use safe checksum style
|
|
/*
|
|
/* Params: pSMHandle - SM Handle
|
|
// fEncryptChecksummedData -
|
|
/****************************************************************************/
|
|
NTSTATUS RDPCALL SM_SetSafeChecksumMethod(
|
|
PVOID pSMHandle,
|
|
BOOLEAN fSafeChecksumMethod
|
|
)
|
|
{
|
|
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pSMHandle;
|
|
|
|
DC_BEGIN_FN("SM_SetSafeChecksumMethod");
|
|
|
|
pRealSMHandle->useSafeChecksumMethod = fSafeChecksumMethod;
|
|
|
|
DC_END_FN();
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|