Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3747 lines
150 KiB

/****************************************************************************/
// nwdwcpp.cpp
//
// WDW internal functions.
//
// Copyright (C) 1997-2000 Microsoft Corporation
/****************************************************************************/
#include <precomp.h>
#pragma hdrstop
#define pTRCWd pTSWd
#define TRC_FILE "nwdwcpp"
#include <as_conf.hpp>
extern "C" {
#include <nwdwint.h>
#include <asmint.h>
#include <asmapi.h>
#include <ntverp.h>
}
#include "slicense.h"
#include <anmapi.h>
#include <mcsioctl.h>
#include "domain.h"
//Client side error reporting
#include "tserrs.h"
#ifdef DC_DEBUG
extern "C" {
VOID IcaBreakOnDebugger( );
}
#endif
extern "C" {
/****************************************************************************/
/* Data returned on IOCTL_VIDEO_QUERY_CURRENT_MODE */
/* */
/* This code unashamedly filched from Remotedd code developed for */
/* NetMeeting. */
/****************************************************************************/
const VIDEO_MODE_INFORMATION wdSimModes[] =
{
sizeof(VIDEO_MODE_INFORMATION), /* length */
0, /* Mode index */
/************************************************************************/
/* VisScreenWidth and VisScreenHeight can be in two forms: */
/* - 0xaaaabbbb - range of values supported (aaaa = max, bbbb = min) */
/* - 0x0000aaaa - single value supported */
/* For example: */
/* - 0x07d0012c = 2000-300 */
/* - 0x0640012c = 1600-300 */
/* - 0x04b000c8 = 1200-200 */
/* */
/* @@@MF For now, support 800x600 only */
/************************************************************************/
0x00000320, /* VisScreenWidth */
0x00000258, /* VisScrenHeight */
0x00000320, /* ScreenStride (0xffff0000 = any) */
0x00000001, /* NumberOfPlanes */
0x00000008, /* BitsPerPlane */
0, /* Frequency */
0, /* XMillimeter */
0, /* YMillimeter */
0, /* NumberRedBits */
0, /* NumberGreenBits */
0, /* NumberBlueBits */
0x00000000, /* RedMask */
0x00000000, /* GreenMask */
0x00000000, /* BlueMask */
VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS,
/* AttributeFlags */
0x00000320, /* VideoMemoryBitmapWidth */
0x00000258, /* VideoMemoryBitmapHeight */
0 /* DriverSpecificAttributeFlags */
};
#ifdef DC_DEBUG
/****************************************************************************/
/* IOCtl descriptions (debug build only) */
/****************************************************************************/
const char *wdIoctlA[] =
{
"IOCTL_ICA_SET_TRACE",
"IOCTL_ICA_TRACE",
"IOCTL_ICA_SET_SYSTEM_TRACE",
"IOCTL_ICA_SYSTEM_TRACE",
"IOCTL_ICA_UNBIND_VIRTUAL_CHANNEL",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"IOCTL_ICA_STACK_PUSH",
"IOCTL_ICA_STACK_POP",
"IOCTL_ICA_STACK_CREATE_ENDPOINT",
"IOCTL_ICA_STACK_CD_CREATE_ENDPOINT",
"IOCTL_ICA_STACK_OPEN_ENDPOINT",
"IOCTL_ICA_STACK_CLOSE_ENDPOINT",
"IOCTL_ICA_STACK_ENABLE_DRIVER",
"IOCTL_ICA_STACK_CONNECTION_WAIT",
"IOCTL_ICA_STACK_WAIT_FOR_ICA",
"IOCTL_ICA_STACK_CONNECTION_QUERY",
"IOCTL_ICA_STACK_CONNECTION_SEND",
"IOCTL_ICA_STACK_CONNECTION_REQUEST",
"IOCTL_ICA_STACK_QUERY_PARAMS",
"IOCTL_ICA_STACK_SET_PARAMS",
"IOCTL_ICA_STACK_ENCRYPTION_OFF",
"IOCTL_ICA_STACK_ENCRYPTION_PERM",
"IOCTL_ICA_STACK_CALLBACK_INITIATE",
"IOCTL_ICA_STACK_QUERY_LAST_ERROR",
"IOCTL_ICA_STACK_WAIT_FOR_STATUS",
"IOCTL_ICA_STACK_QUERY_STATUS",
"IOCTL_ICA_STACK_REGISTER_HOTKEY",
"IOCTL_ICA_STACK_CANCEL_IO",
"IOCTL_ICA_STACK_QUERY_STATE",
"IOCTL_ICA_STACK_SET_STATE",
"IOCTL_ICA_STACK_QUERY_LAST_INPUT_TIME",
"IOCTL_ICA_STACK_TRACE",
"IOCTL_ICA_STACK_CALLBACK_COMPLETE",
"IOCTL_ICA_STACK_CD_CANCEL_IO",
"IOCTL_ICA_STACK_QUERY_CLIENT",
"IOCTL_ICA_STACK_QUERY_MODULE_DATA",
"IOCTL_ICA_STACK_REGISTER_BROKEN",
"IOCTL_ICA_STACK_ENABLE_IO",
"IOCTL_ICA_STACK_DISABLE_IO",
"IOCTL_ICA_STACK_SET_CONNECTED",
"IOCTL_ICA_STACK_SET_CLIENT_DATA",
"IOCTL_ICA_STACK_QUERY_BUFFER",
"IOCTL_ICA_STACK_DISCONNECT",
"IOCTL_ICA_STACK_RECONNECT",
"IOCTL_ICA_STACK_CONSOLE_CONNECT",
"IOCTL_ICA_STACK_SET_CONFIG"
};
const char *wdIoctlB[] =
{
"IOCTL_ICA_CHANNEL_TRACE",
"IOCTL_ICA_CHANNEL_ENABLE_SHADOW",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"IOCTL_ICA_VIRTUAL_LOAD_FILTER",
"IOCTL_ICA_VIRTUAL_UNLOAD_FILTER",
"IOCTL_ICA_VIRTUAL_ENABLE_FILTER",
"IOCTL_ICA_VIRTUAL_DISABLE_FILTER",
"IOCTL_ICA_VIRTUAL_BOUND",
"IOCTL_ICA_VIRTUAL_CANCEL_INPUT",
"IOCTL_ICA_VIRTUAL_CANCEL_OUTPUT",
"IOCTL_ICA_VIRTUAL_QUERY_MODULE_DATA",
"IOCTL_ICA_VIRTUAL_QUERY_BINDINGS",
"IOCTL_ICA_STACK_QUERY_LICENSE_CAPABILITIES",
"IOCTL_ICA_STACK_REQUEST_CLIENT_LICENSE",
"IOCTL_ICA_STACK_SEND_CLIENT_LICENSE",
"IOCTL_ICA_STACK_LICENSE_PROTOCOL_COMPLETE",
"IOCTL_ICA_STACK_GET_LICENSE_DATA",
"IOCTL_ICA_STACK_SEND_KEEPALIVE_PDU",
"IOCTL_TS_STACK_QUERY_LOAD_BALANCE_INFO",
"IOCTL_TS_STACK_SEND_CLIENT_REDIRECTION",
"IOCTL_ICA_STACK_QUERY_CLIENT_EXTENDED",
"IOCTL_ICA_STACK_QUERY_AUTORECONNECT"
};
const char *wdIoctlC[] =
{
"IOCTL_VIDEO_QUERY_AVAIL_MODES",
"IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES",
"IOCTL_VIDEO_QUERY_CURRENT_MODE",
"IOCTL_VIDEO_SET_CURRENT_MODE",
"IOCTL_VIDEO_RESET_DEVICE",
"IOCTL_VIDEO_LOAD_AND_SET_FONT",
"IOCTL_VIDEO_SET_PALETTE_REGISTERS",
"IOCTL_VIDEO_SET_COLOR_REGISTERS",
"IOCTL_VIDEO_ENABLE_CURSOR",
"IOCTL_VIDEO_DISABLE_CURSOR",
"IOCTL_VIDEO_SET_CURSOR_ATTR",
"IOCTL_VIDEO_QUERY_CURSOR_ATTR",
"IOCTL_VIDEO_SET_CURSOR_POSITION",
"IOCTL_VIDEO_QUERY_CURSOR_POSITION",
"IOCTL_VIDEO_ENABLE_POINTER",
"IOCTL_VIDEO_DISABLE_POINTER",
"IOCTL_VIDEO_SET_POINTER_ATTR",
"IOCTL_VIDEO_QUERY_POINTER_ATTR",
"IOCTL_VIDEO_SET_POINTER_POSITION",
"IOCTL_VIDEO_QUERY_POINTER_POSITION",
"IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES",
"IOCTL_VIDEO_GET_BANK_SELECT_CODE",
"IOCTL_VIDEO_MAP_VIDEO_MEMORY",
"IOCTL_VIDEO_UNMAP_VIDEO_MEMORY",
"IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES",
"IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES",
"IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES",
"IOCTL_VIDEO_SET_POWER_MANAGEMENT",
"IOCTL_VIDEO_GET_POWER_MANAGEMENT",
"IOCTL_VIDEO_SHARE_VIDEO_MEMORY",
"IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY",
};
const char *wdIoctlD[] =
{
"IOCTL_KEYBOARD_ICA_INPUT",
"IOCTL_KEYBOARD_ICA_LAYOUT",
"IOCTL_KEYBOARD_ICA_SCANMAP",
"IOCTL_KEYBOARD_ICA_TYPE"
};
const char *wdIoctlE[] =
{
"IOCTL_VIDEO_ICA_QUERY_FONT_PAIRS",
"IOCTL_VIDEO_ICA_ENABLE_GRAPHICS",
"IOCTL_VIDEO_ICA_DISABLE_GRAPHICS",
"IOCTL_VIDEO_ICA_SET_CP",
"IOCTL_VIDEO_ICA_STOP_OK",
"IOCTL_VIDEO_ICA_REVERSE_MOUSE_POINTER",
"IOCTL_VIDEO_ICA_COPY_FRAME_BUFFER",
"IOCTL_VIDEO_ICA_WRITE_TO_FRAME_BUFFER",
"IOCTL_VIDEO_ICA_INVALIDATE_MODES",
"IOCTL_VIDEO_ICA_SCROLL",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"IOCTL_ICA_STACK_ENCRYPTION_ENTER",
"IOCTL_ICA_STACK_ENCRYPTION_EXIT",
};
const char *wdIoctlTsh[] =
{
"IOCTL_WDTS_DD_CONNECT",
"IOCTL_WDTS_DD_DISCONNECT",
"IOCTL_WDTS_DD_RECONNECT",
"IOCTL_WDTS_DD_OUTPUT_AVAILABLE",
"IOCTL_WDTS_DD_TIMER_INFO",
"IOCTL_WDTS_DD_CLIP",
"IOCTL_WDTS_DD_SHADOW_CONNECT",
"IOCTL_WDTS_DD_SHADOW_DISCONNECT",
"IOCTL_WDTS_DD_SHADOW_SYNCHRONIZE",
"IOCTL_WDTS_DD_REDRAW_SCREEN",
"IOCTL_WDTS_DD_QUERY_SHADOW_CAPS",
"IOCTL_WDTS_DD_GET_BITMAP_KEYDATABASE",
};
#endif /* DC_DEBUG */
/****************************************************************************/
// WD_Ioctl
//
// Query/Set configuration information for the WD.
/****************************************************************************/
NTSTATUS WD_Ioctl(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
{
NTSTATUS status = STATUS_SUCCESS;
UINT32 bufferLen;
unsigned fn;
PVIDEO_MODE_INFORMATION pVidInfo;
DC_BEGIN_FN("WD_Ioctl");
// Special-case output-available DD ioctl for speed - separating the
// most commonly-run case into a separate if that will tend to fall
// through greatly speeds up Pentium Pro branch prediction and cache
// line hit probability.
if (pSdIoctl->IoControlCode == IOCTL_WDTS_DD_OUTPUT_AVAILABLE) {
PTSHARE_DD_OUTPUT_IN pOutputIn;
PTSHARE_DD_OUTPUT_OUT pOutputOut;
ShareClass *dcShare;
// Local variables to make the code more readable.
pOutputIn = (PTSHARE_DD_OUTPUT_IN)pSdIoctl->InputBuffer;
pOutputOut = (PTSHARE_DD_OUTPUT_OUT)pSdIoctl->OutputBuffer;
dcShare = (ShareClass *)(pTSWd->dcShare);
dcShare->m_pShm = (PSHM_SHARED_MEMORY)pOutputIn->pShm;
WDW_CHECK_SHM((pOutputIn->pShm));
if ((pTSWd->StackClass == Stack_Primary) ||
(pTSWd->StackClass == Stack_Console)) {
INT32 milliSecs;
TRC_DBG((TB, "IOCTL_WDTS_DD_OUTPUT_AVAILABLE"));
if (!pTSWd->dead) {
TRC_DBG((TB, "OK to process the IOCtl"));
TRC_ASSERT((dcShare != NULL), (TB, "NULL Share Class"));
// NB There is no code here to check the size of the buffers
// on the IOCtl. This is a performance critical path which
// can do without it.
TRC_DBG((TB, "OutputAvailable IOCtl: force send=%d",
pOutputIn->forceSend));
// Check if the framebuffer is valid
if (pOutputIn->pFrameBuf != NULL &&
pOutputIn->frameBufHeight != 0 &&
pOutputIn->frameBufWidth != 0) {
// For normal output IOCTLs, call DCS_TTDS.
if (!pOutputIn->schedOnly) {
TRC_DBG((TB, "Normal output"));
// Stop the timer (in the main we don't use it, so
// avoid excess context switches).
WDWStopRITTimer(pTSWd);
// Call the Share Core to do the work.
// need to return status code so caller can bail out
// in case of error
status = dcShare->DCS_TimeToDoStuff(pOutputIn,
&(pOutputOut->schCurrentMode), &milliSecs);
// Restart the timer if requested by the core.
if (milliSecs != -1L) {
TRC_DBG((TB, "Run the RIT timer for %ld ms", milliSecs));
WDW_StartRITTimer(pTSWd, milliSecs);
}
else {
TRC_DBG((TB, "Skipped starting the timer!"));
}
}
else {
// It's just a wake-up call to the scheduler.
TRC_NRM((TB, "Just wake up the scheduler"));
dcShare->SCH_ContinueScheduling(SCH_MODE_NORMAL);
// Be sure to set the current scheduler mode.
pOutputOut->schCurrentMode = dcShare->SCH_GetCurrentMode();
}
pOutputOut->schInputKickMode = dcShare->SCH_GetInputKickMode();
}
else {
TRC_ERR((TB, "Bad FrameBuffer input parameter"));
status = STATUS_INVALID_PARAMETER;
}
}
else {
dcShare->DCS_DiscardAllOutput();
TRC_ERR((TB, "Dead - ignoring IOCTL_WDTS_DD_OUTPUT_AVAILABLE"));
status = STATUS_DEVICE_NOT_READY;
}
dcShare->m_pShm = NULL;
WDW_CHECK_SHM((pOutputIn->pShm));
DC_QUIT;
}
// Shadow stack: Duplicate the data send. Note that the target's primary
// stack will have already placed the data in the shadow buffer so we
// don't need to re-encode it. There may be multiple shadow stacks
// consuming data from the primary stack so don't touch it!
else {
PSHADOW_INFO pShadowInfo = dcShare->m_pShm->pShadowInfo;
if (pShadowInfo && pShadowInfo->messageSize) {
PBYTE pShadowBuffer;
//
//find out if the stack doesn't want a low water mark
//if so, allocate out of the ring (8192)
//
UINT32 sizeToAlloc = IcaGetSizeForNoLowWaterMark(pTSWd->pContext);
// fWait is TRUE means that we will always wait for a buffer to be avail
status = SM_AllocBuffer(dcShare->m_pSmInfo, (PPVOID) &pShadowBuffer,
sizeToAlloc > pShadowInfo->messageSize? sizeToAlloc : pShadowInfo->messageSize,
TRUE, FALSE);
if ( STATUS_SUCCESS == status ) {
memcpy(pShadowBuffer, pShadowInfo->data,
pShadowInfo->messageSize);
if (SM_SendData(dcShare->m_pSmInfo, pShadowBuffer,
pShadowInfo->messageSize, PROT_PRIO_MISC, 0,
FALSE, RNS_SEC_ENCRYPT, FALSE)) {
status = STATUS_SUCCESS;
TRC_NRM((TB, "Shadow stack send: %ld",
pShadowInfo->messageSize));
}
else {
status = STATUS_UNEXPECTED_IO_ERROR;
TRC_ALT((TB, "Shadow stack send failed: %ld",
pShadowInfo->messageSize));
}
#ifdef DC_HICOLOR
// Is there any overflow data too send?
if (pShadowInfo->messageSizeEx)
{
status = SM_AllocBuffer(dcShare->m_pSmInfo,(PPVOID)&pShadowBuffer,
(sizeToAlloc > pShadowInfo->messageSizeEx )?
sizeToAlloc : pShadowInfo->messageSizeEx,
TRUE, FALSE);
if ( STATUS_SUCCESS == status )
{
memcpy(
pShadowBuffer,
&pShadowInfo->data[WD_MAX_SHADOW_BUFFER],
pShadowInfo->messageSizeEx);
if (SM_SendData(dcShare->m_pSmInfo,
pShadowBuffer,
pShadowInfo->messageSizeEx,
PROT_PRIO_MISC, 0, FALSE, RNS_SEC_ENCRYPT, FALSE))
{
status = STATUS_SUCCESS;
TRC_NRM((TB, "Shadow stack send: %ld",
pShadowInfo->messageSizeEx));
}
else
{
status = STATUS_UNEXPECTED_IO_ERROR;
TRC_ALT((TB, "Shadow stack send failed: %ld",
pShadowInfo->messageSizeEx));
}
}
else
{
// Prevent regression, keep original return code
status = STATUS_UNEXPECTED_IO_ERROR;
TRC_ERR((TB, "Failed to allocate shadow stack send buffer"));
}
}
#endif
}
else {
// Prevent regression, keep original return code
status = STATUS_UNEXPECTED_IO_ERROR;
TRC_ERR((TB, "Failed to allocate shadow stack send buffer"));
}
}
dcShare->m_pShm = NULL;
WDW_CHECK_SHM((pOutputIn->pShm));
DC_QUIT;
}
}
else {
// Non-perf path IOCTLs.
fn = WDW_IOCTL_FUNCTION(pSdIoctl->IoControlCode);
TRC_NRM((TB, "%s (%d)",
fn == 6 ? "IOCTL_VIDEO_ENUM_MONITOR_PDO" :
fn < 49 ? wdIoctlA[fn] :
fn < 50 ? "Unknown Ioctl" :
fn < 77 ? wdIoctlB[fn - 50] :
fn < 0x100 ? "Unknown Ioctl" :
fn < 0x11f ? wdIoctlC[fn - 0x100] :
fn < 0x200 ? "Unknown Ioctl" :
fn < 0x204 ? wdIoctlD[fn - 0x200] :
fn == 0x300 ? "IOCTL_MOUSE_ICA_INPUT" :
fn < 0x400 ? "Unknown Ioctl" :
fn < 0x412 ? wdIoctlE[fn - 0x400] :
fn == 0x500 ? "IOCTL_T120_REQUEST" :
fn < 0x510 ? "Unknown Ioctl" :
fn < 0x520 ? wdIoctlTsh[fn - 0x510] :
fn == 0x900 ? "IOCTL_TSHARE_CONF_CONNECT" :
fn == 0x901 ? "IOCTL_TSHARE_CONF_DISCONNECT" :
fn == 0x903 ? "IOCTL_TSHARE_USER_LOGON" :
fn == 0x904 ? "IOCTL_TSHARE_GET_SEC_DATA" :
fn == 0x905 ? "IOCTL_TSHARE_SET_SEC_DATA" :
fn == 0x906 ? "IOCTL_TSHARE_SET_NO_ENCRYPT" :
fn == 0x907 ? "IOCTL_TSHARE_QUERY_CHANNELS" :
fn == 0x908 ? "IOCTL_TSHARE_CONSOLE_CONNECT" :
fn == 0x909 ? "IOCTL_TSHARE_SEND_CERT_DATA" :
fn == 0x90A ? "IOCTL_TSHARE_GET_CERT_DATA" :
fn == 0x90B ? "IOCTL_TSHARE_SEND_CLIENT_RANDOM" :
fn == 0x90C ? "IOCTL_TSHARE_GET_CLIENT_RANDOM" :
fn == 0x90D ? "IOCTL_TSHARE_SHADOW_CONNECT" :
fn == 0x90E ? "IOCTL_TSHARE_SET_ERROR_INFO" :
"Unknown Ioctl",
fn));
}
/************************************************************************/
/* Firstly, zero the no. of returned bytes. */
/************************************************************************/
pSdIoctl->BytesReturned = 0;
switch ( pSdIoctl->IoControlCode ) {
/********************************************************************/
// We expect IOCTL_ICA_TRACE before tracing anything. Check for NULL
// Inbuf - we've seen this happen.
//
// *** DO NOT TRACE IN THIS BRANCH ***
/********************************************************************/
case IOCTL_ICA_TRACE:
{
PICA_TRACE_BUFFER pTrc = (PICA_TRACE_BUFFER)pSdIoctl->InputBuffer;
if (pTrc != NULL)
{
IcaStackTrace(pTSWd->pContext,
TC_DISPLAY, // @@@MF Should be pTrc->TraceClass
// but it's overwritten with '7'
pTrc->TraceEnable,
(char *)pTrc->Data);
}
break;
}
/****************************************************************************/
/****************************************************************************/
/* Firstly, for debug purposes, group together those IOCtls that we do not */
/* expect to get (ICA uses them for text mode support, which we do not */
/* implement). */
/****************************************************************************/
/****************************************************************************/
case IOCTL_VIDEO_QUERY_CURSOR_ATTR :
case IOCTL_VIDEO_SET_CURSOR_ATTR :
case IOCTL_VIDEO_QUERY_CURSOR_POSITION :
case IOCTL_VIDEO_SET_CURSOR_POSITION :
case IOCTL_VIDEO_ENABLE_CURSOR :
case IOCTL_VIDEO_DISABLE_CURSOR :
case IOCTL_VIDEO_QUERY_POINTER_ATTR :
case IOCTL_VIDEO_SET_POINTER_ATTR :
case IOCTL_VIDEO_QUERY_POINTER_POSITION :
case IOCTL_VIDEO_ENABLE_POINTER :
case IOCTL_VIDEO_DISABLE_POINTER :
case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES :
case IOCTL_VIDEO_SET_PALETTE_REGISTERS :
case IOCTL_VIDEO_LOAD_AND_SET_FONT :
case IOCTL_VIDEO_MAP_VIDEO_MEMORY :
case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY :
case IOCTL_VIDEO_ICA_QUERY_FONT_PAIRS :
case IOCTL_VIDEO_ICA_COPY_FRAME_BUFFER :
case IOCTL_VIDEO_ICA_WRITE_TO_FRAME_BUFFER :
case IOCTL_VIDEO_ICA_REVERSE_MOUSE_POINTER :
case IOCTL_VIDEO_ICA_SET_CP :
case IOCTL_VIDEO_ICA_SCROLL :
{
TRC_ALT((TB, "Unexpected IOCtl %x (function %d)",
pSdIoctl->IoControlCode,
WDW_IOCTL_FUNCTION(pSdIoctl->IoControlCode)));
}
break;
/****************************************************************************/
/****************************************************************************/
/* Now the IOCtls that we do nothing with but just return OK. */
/****************************************************************************/
/****************************************************************************/
/********************************************************************/
/* Both of the following are expected (they occur whenever we */
/* enable or disable graphics - typically when the client is */
/* minimized and restored). However we don't need to do anything */
/* with them. */
/********************************************************************/
case IOCTL_VIDEO_ICA_ENABLE_GRAPHICS :
case IOCTL_VIDEO_ICA_DISABLE_GRAPHICS :
/********************************************************************/
/* Miscellaneous IOCTLs we don't process. */
/********************************************************************/
case IOCTL_ICA_STACK_DISCONNECT:
case IOCTL_VIDEO_SET_POINTER_POSITION :
case IOCTL_VIDEO_ICA_STOP_OK :
case IOCTL_ICA_STACK_SET_CLIENT_DATA:
case IOCTL_ICA_STACK_ENCRYPTION_OFF:
case IOCTL_ICA_STACK_ENCRYPTION_PERM:
case IOCTL_VIDEO_ICA_INVALIDATE_MODES :
{
TRC_NRM((TB, "Nothing to do"));
}
break;
/****************************************************************************/
/****************************************************************************/
/* Here are a block of IOCtls that we process exactly as per Citrix. The */
/* calls are to unmodified Citrix routines. */
/****************************************************************************/
/****************************************************************************/
case IOCTL_KEYBOARD_QUERY_ATTRIBUTES :
{
status = KeyboardQueryAttributes( pTSWd, pSdIoctl );
}
break;
case IOCTL_KEYBOARD_QUERY_TYPEMATIC :
{
status = KeyboardQueryTypematic( pTSWd, pSdIoctl );
}
break;
case IOCTL_KEYBOARD_SET_TYPEMATIC :
{
status = KeyboardSetTypematic( pTSWd, pSdIoctl );
}
break;
case IOCTL_KEYBOARD_QUERY_INDICATORS :
{
status = KeyboardQueryIndicators( pTSWd, pSdIoctl );
}
break;
case IOCTL_KEYBOARD_SET_INDICATORS :
{
status = KeyboardSetIndicators( pTSWd, pSdIoctl );
}
break;
case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION :
{
status = KeyboardQueryIndicatorTranslation( pTSWd, pSdIoctl );
}
break;
case IOCTL_KEYBOARD_SET_IME_STATUS :
{
status = KeyboardSetImeStatus( pTSWd, pSdIoctl );
}
break;
case IOCTL_MOUSE_QUERY_ATTRIBUTES :
{
status = MouseQueryAttributes( pTSWd, pSdIoctl );
}
break;
case IOCTL_KEYBOARD_ICA_LAYOUT :
status = KeyboardSetLayout( pTSWd, pSdIoctl );
break;
case IOCTL_KEYBOARD_ICA_SCANMAP :
status = KeyboardSetScanMap( pTSWd, pSdIoctl );
break;
case IOCTL_KEYBOARD_ICA_TYPE :
status = KeyboardSetType( pTSWd, pSdIoctl );
break;
/****************************************************************************/
/****************************************************************************/
/* The next set of cases are the IOCtls with which we do significant real */
/* work. */
/****************************************************************************/
/****************************************************************************/
// stash our new session ID
case IOCTL_ICA_STACK_RECONNECT:
{
TRC_NRM((TB, "Got reconnect IOCTL"));
TRC_ASSERT((pSdIoctl->InputBufferLength == sizeof(ICA_STACK_RECONNECT)),
(TB, "Bad Reconnect Info"));
pTSWd->sessionId =
((PICA_STACK_RECONNECT)(pSdIoctl->InputBuffer))->sessionId;
}
break;
case IOCTL_ICA_SET_TRACE:
{
#ifdef DC_DEBUG
TRC_UpdateConfig(pTSWd, pSdIoctl);
TRC_NRM((TB, "Got Set Trace IOCtl"));
#endif
}
break;
case IOCTL_BEEP_SET:
{
TRC_NRM((TB, "Got Beep Set IOCtl"));
WDWSendBeep(pTSWd, pSdIoctl);
}
break;
case IOCTL_TSHARE_USER_LOGON:
{
TRC_NRM((TB, "Got user logon IOCtl"));
WDWUserLoggedOn(pTSWd, pSdIoctl);
pSdIoctl->BytesReturned = 0;
}
break;
case IOCTL_TSHARE_GET_SEC_DATA:
{
TRC_NRM((TB, "Got GetSecurityData IOCtl"));
status = SM_GetSecurityData(pTSWd->pSmInfo, pSdIoctl);
}
break;
case IOCTL_TSHARE_SET_SEC_DATA:
{
TRC_NRM((TB, "Got SetSecurityData IOCtl"));
if ((pSdIoctl->InputBuffer != NULL) &&
(pSdIoctl->InputBufferLength >= sizeof(SECINFO))) {
status = pTSWd->SessKeyCreationStatus =
SM_SetSecurityData(pTSWd->pSmInfo,
(PSECINFO) pSdIoctl->InputBuffer);
}
else {
// NULL data is sent when the client random or shadow
// stack random could not be generated in user mode,
// likely because of decryption failure on the random value.
// We need to succeedd the IOCTL, but fail the key creation
// return to the pSessKeyEvent waiter.
status = STATUS_SUCCESS;
pTSWd->SessKeyCreationStatus = STATUS_UNSUCCESSFUL;
}
// We always set the session key event to prevent a deadlock
// if we are being attacked with bad client security data. This
// set used to be in SM_SetSecurityData(), but there it might
// not have been set if any encryption errors occurred.
KeSetEvent(pTSWd->pSessKeyEvent, 0, FALSE);
}
break;
// The shadow server sends it's certificate and shadow random to the
// shadow client, which then sends an encrypted client random. This
// is identical to the standard connection sequence.
case IOCTL_TSHARE_SEND_CERT_DATA:
{
ShareClass *dcShare;
dcShare = (ShareClass *)(pTSWd->dcShare);
status = dcShare->SC_SendServerCert(
(PSHADOWCERT) pSdIoctl->InputBuffer,
pSdIoctl->InputBufferLength);
}
break;
case IOCTL_TSHARE_SEND_CLIENT_RANDOM:
{
ShareClass *dcShare;
dcShare = (ShareClass *)(pTSWd->dcShare);
status = dcShare->SC_SendClientRandom((PBYTE) pSdIoctl->InputBuffer,
pSdIoctl->InputBufferLength);
}
break;
case IOCTL_TSHARE_GET_CERT_DATA:
case IOCTL_TSHARE_GET_CLIENT_RANDOM:
{
ShareClass *dcShare;
dcShare = (ShareClass *)(pTSWd->dcShare);
status = dcShare->SC_GetSecurityData(pSdIoctl);
}
break;
case IOCTL_ICA_STACK_SET_CONFIG:
{
PICA_STACK_CONFIG_DATA pConfigData;
pConfigData = (PICA_STACK_CONFIG_DATA) pSdIoctl->InputBuffer;
TRC_NRM((TB, "Got stack config data"));
WDWSetConfigData(pTSWd, pConfigData);
}
break;
case IOCTL_ICA_STACK_WAIT_FOR_ICA :
{
/****************************************************************/
/* Return the "default query stack," meaning reuse these */
/* drivers. */
/****************************************************************/
TRC_NRM((TB, "Stack wait for ICA"));
}
break;
case IOCTL_ICA_STACK_CONSOLE_CONNECT :
{
/****************************************************************/
/* Return the "default query stack," meaning reuse these */
/* drivers. */
/****************************************************************/
TRC_NRM((TB, "Stack Console Connect"));
}
break;
case IOCTL_ICA_STACK_QUERY_BUFFER :
{
ICA_STACK_QUERY_BUFFER *pBuffers;
pBuffers = (ICA_STACK_QUERY_BUFFER *) pSdIoctl->OutputBuffer;
pBuffers->WdBufferCount = TSHARE_WD_BUFFER_COUNT;
pBuffers->TdBufferSize = TSHARE_TD_BUFFER_SIZE;
pSdIoctl->BytesReturned = sizeof(ICA_STACK_QUERY_BUFFER);
TRC_NRM((TB, "Stack query buffer, num %d, size %d",
pBuffers->WdBufferCount,
pBuffers->TdBufferSize));
}
break;
case IOCTL_TSHARE_CONF_CONNECT:
{
TRC_NRM((TB, "Got TSHARE_CONF_CONNECT IOCtl"));
status = WDWConfConnect(pTSWd, pSdIoctl);
}
break;
case IOCTL_TSHARE_CONSOLE_CONNECT:
{
TRC_NRM((TB, "Got TSHARE_CONSOLE_CONNECT IOCtl"));
status = WDWConsoleConnect(pTSWd, pSdIoctl);
}
break;
case IOCTL_TSHARE_SHADOW_CONNECT:
status = WDWShadowConnect(pTSWd, pSdIoctl) ;
break;
case IOCTL_TSHARE_SET_ERROR_INFO:
{
TRC_NRM((TB, "Got SetErrorInfo IOCtl"));
status = WDWSetErrorInfo(pTSWd, pSdIoctl);
pSdIoctl->BytesReturned = 0;
}
break;
case IOCTL_TSHARE_SEND_ARC_STATUS:
{
TRC_NRM((TB, "Got SetArcStatus IOCtl"));
status = WDWSendArcStatus(pTSWd, pSdIoctl);
pSdIoctl->BytesReturned = 0;
}
break;
case IOCTL_ICA_STACK_SET_CONNECTED:
status = STATUS_SUCCESS;
break;
case IOCTL_ICA_STACK_CONNECTION_QUERY :
{
PICA_STACK_CONFIG pIcaStackConfig;
pIcaStackConfig = (PICA_STACK_CONFIG) pSdIoctl->OutputBuffer;
memcpy(pIcaStackConfig->WdDLL,
pTSWd->DLLName,
sizeof(pIcaStackConfig->WdDLL));
pIcaStackConfig->SdClass[0] = SdNone;
pSdIoctl->BytesReturned = pSdIoctl->OutputBufferLength;
TRC_NRM((TB, "Stack Connection Query"));
}
break;
case IOCTL_TSHARE_QUERY_CHANNELS:
{
TRC_NRM((TB, "Query Virtual Channel data"));
status = NM_QueryChannels(pTSWd->pNMInfo,
pSdIoctl->OutputBuffer,
pSdIoctl->OutputBufferLength,
&(pSdIoctl->BytesReturned));
}
break;
case IOCTL_WDTS_DD_CONNECT:
{
if (pSdIoctl->InputBuffer &&
(((PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer)->pShm)) {
WDW_CHECK_SHM(
(((PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer)->pShm));
TRC_DBG((TB, "Got TSHARE_DD_CONNECT IOCtl"));
status = WDWDDConnect(pTSWd, pSdIoctl, FALSE);
WDW_CHECK_SHM(
(((PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer)->pShm));
}
else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
case IOCTL_WDTS_DD_DISCONNECT:
{
if (pSdIoctl->InputBuffer &&
(((PTSHARE_DD_DISCONNECT_IN)pSdIoctl->InputBuffer)->pShm)) {
WDW_CHECK_SHM(
(((PTSHARE_DD_DISCONNECT_IN)pSdIoctl->InputBuffer)->pShm));
TRC_ALT((TB, "Got TSHARE_DD_DISCONNECT IOCtl: Stack (%ld)",
pTSWd->StackClass));
if ((pTSWd->StackClass == Stack_Primary) ||
(pTSWd->StackClass == Stack_Console)) {
status = WDWDDDisconnect(pTSWd, pSdIoctl, FALSE);
}
WDW_CHECK_SHM(
(((PTSHARE_DD_DISCONNECT_IN)pSdIoctl->InputBuffer)->pShm));
}
else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
case IOCTL_WDTS_DD_RECONNECT:
{
if (pSdIoctl->InputBuffer &&
(((PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer)->pShm)) {
WDW_CHECK_SHM(
(((PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer)->pShm));
TRC_DBG((TB, "Got TSHARE_DD_RECONNECT IOCtl"));
if (pTSWd->shadowState == SHADOW_CLIENT) {
TRC_ALT((TB, "Shadow termination on reconnect, in share(%ld)",
pTSWd->bInShadowShare));
pTSWd->shadowState = SHADOW_NONE;
// If we were formerly in an active shadow, then we need to
// deactivate the client before reconnecting in a new share
if (pTSWd->bInShadowShare) {
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
pSC->SC_EndShare(TRUE);
pTSWd->bInShadowShare = FALSE;
}
// Make sure that Domain.StatusDead is consistent with TSWd.dead
pTSWd->dead = TRUE;
((PDomain)(pTSWd->hDomainKernel))->StatusDead = TRUE;
SM_Dead(pTSWd->pSmInfo, TRUE);
if (pTSWd->bCompress == TRUE) {
// the compression history will be flushed
pTSWd->bFlushed = PACKET_FLUSHED;
// the compression will restart over
initsendcontext(pTSWd->pMPPCContext, pTSWd->pMPPCContext->ClientComprType);
}
}
status = WDWDDConnect(pTSWd, pSdIoctl, TRUE);
WDW_CHECK_SHM(
(((PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer)->pShm));
}
else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
case IOCTL_WDTS_DD_TIMER_INFO:
{
if (pSdIoctl->InputBufferLength < sizeof(TSHARE_DD_TIMER_INFO))
{
TRC_ERR((TB, "Timer info IOCtl too small at %lu",
pSdIoctl->InputBufferLength));
status = STATUS_BUFFER_TOO_SMALL;
}
else
{
/************************************************************/
/* Store the timer handle */
/************************************************************/
pTSWd->ritTimer =
((PTSHARE_DD_TIMER_INFO)(pSdIoctl->InputBuffer))->
pKickTimer;
TRC_DBG((TB, "Got TSHARE_DD_TIMER_INFO IOCtl, handle %p",
pTSWd->ritTimer));
/************************************************************/
/* Start a timer to get things moving */
/************************************************************/
WDW_StartRITTimer(pTSWd, pTSWd->outBufDelay);
}
}
break;
case IOCTL_WDTS_DD_REDRAW_SCREEN :
{
ShareClass *dcShare;
dcShare = (ShareClass *)(pTSWd->dcShare);
TRC_NRM((TB, "RDPDD requests to redraw screen\n"));
if (dcShare != NULL) {
// We have a valid share class, do screen redraw
dcShare->SC_RedrawScreen();
}
}
break;
case IOCTL_ICA_STACK_CONNECTION_SEND :
{
// Wait for the connected indication from SM.
TRC_DBG((TB, "About to wait for connected indication"));
status = WDW_WaitForConnectionEvent(pTSWd,
pTSWd->pConnEvent, 60000);
TRC_DBG((TB, "Back from wait for connected indication"));
if (status != STATUS_SUCCESS) {
TRC_ERR((TB, "Connected indication timed out (%x)",
status));
status = STATUS_IO_TIMEOUT;
DC_QUIT;
}
// Pass the IOCtl on to the next driver.
status = IcaCallNextDriver(pTSWd->pContext, SD$IOCTL, pSdIoctl);
}
break;
case IOCTL_ICA_STACK_QUERY_CLIENT :
{
status = WDWGetClientData( pTSWd, pSdIoctl );
TRC_NRM((TB, "Return client data"));
}
break;
// This IOCTL was introduced to support long UserName, Password and Domain names
case IOCTL_ICA_STACK_QUERY_CLIENT_EXTENDED :
{
status = WDWGetExtendedClientData(pTSWd->pInfoPkt, pSdIoctl);
TRC_NRM((TB, "Return Extended client data"));
}
break;
case IOCTL_ICA_STACK_QUERY_AUTORECONNECT:
{
TRC_NRM((TB, "Query autoreconnect information"));
status = WDWGetAutoReconnectInfo(pTSWd, pTSWd->pInfoPkt, pSdIoctl);
}
break;
/****************************************************************************/
/****************************************************************************/
/* Here are some IOCtls that we have to deal with in our guise of miniport */
/* driver. */
/****************************************************************************/
/****************************************************************************/
case IOCTL_VIDEO_QUERY_CURRENT_MODE:
{
TRC_NRM((TB, "QueryCurrentModes"));
if (pSdIoctl->OutputBufferLength <
sizeof(VIDEO_MODE_INFORMATION))
{
TRC_ERR((TB,
"QueryCurrentMode buffer too small: got/expected %d/%d",
pSdIoctl->OutputBufferLength,
sizeof(VIDEO_MODE_INFORMATION) ));
status = STATUS_BUFFER_TOO_SMALL;
}
else
{
TRC_NRM((TB, "Return current mode"));
/************************************************************/
/* Copy the default mode information, and then update it */
/* with our current screen dimensions. */
/************************************************************/
pVidInfo =
(PVIDEO_MODE_INFORMATION)pSdIoctl->OutputBuffer;
memcpy(pVidInfo,
wdSimModes,
sizeof(wdSimModes));
pVidInfo->Length = sizeof(VIDEO_MODE_INFORMATION);
pVidInfo->VisScreenWidth = pTSWd->desktopWidth;
pVidInfo->VisScreenHeight = pTSWd->desktopHeight;
pVidInfo->BitsPerPlane = pTSWd->desktopBpp;
pVidInfo->VideoMemoryBitmapWidth = pTSWd->desktopWidth;
pVidInfo->VideoMemoryBitmapHeight = pTSWd->desktopHeight;
#ifdef DC_HICOLOR
switch (pTSWd->desktopBpp)
{
case 24:
{
pVidInfo->RedMask = TS_RED_MASK_24BPP;
pVidInfo->GreenMask = TS_GREEN_MASK_24BPP;
pVidInfo->BlueMask = TS_BLUE_MASK_24BPP;
}
break;
case 16:
{
pVidInfo->RedMask = TS_RED_MASK_16BPP;
pVidInfo->GreenMask = TS_GREEN_MASK_16BPP;
pVidInfo->BlueMask = TS_BLUE_MASK_16BPP;
}
break;
case 15:
{
pVidInfo->RedMask = TS_RED_MASK_15BPP;
pVidInfo->GreenMask = TS_GREEN_MASK_15BPP;
pVidInfo->BlueMask = TS_BLUE_MASK_15BPP;
}
break;
default:
{
pVidInfo->RedMask = 0;
pVidInfo->GreenMask = 0;
pVidInfo->BlueMask = 0;
}
break;
}
#endif
pSdIoctl->BytesReturned = sizeof(wdSimModes);
}
}
break;
case IOCTL_VIDEO_QUERY_AVAIL_MODES:
{
TRC_NRM((TB, "QueryAvailableModes"));
if (pSdIoctl->OutputBufferLength <
sizeof(VIDEO_MODE_INFORMATION))
{
TRC_ERR((TB,
"QueryCurrentMode buffer too small: got/expected %d/%d",
pSdIoctl->OutputBufferLength,
sizeof(VIDEO_MODE_INFORMATION) ));
status = STATUS_BUFFER_TOO_SMALL;
}
else
{
TRC_NRM((TB, "Return just one mode"));
// Copy the default mode information, and then update it
// with our current screen dimensions.
pVidInfo = (PVIDEO_MODE_INFORMATION)pSdIoctl->OutputBuffer;
memcpy(pVidInfo,
wdSimModes,
sizeof(wdSimModes));
pVidInfo->Length = sizeof(VIDEO_MODE_INFORMATION);
pVidInfo->VisScreenWidth = pTSWd->desktopWidth;
pVidInfo->VisScreenHeight = pTSWd->desktopHeight;
pVidInfo->BitsPerPlane = pTSWd->desktopBpp;
pVidInfo->VideoMemoryBitmapWidth = pTSWd->desktopWidth;
pVidInfo->VideoMemoryBitmapHeight = pTSWd->desktopHeight;
pVidInfo->Frequency = 42; // required by the display cpl
#ifdef DC_HICOLOR
switch (pTSWd->desktopBpp)
{
case 24:
{
pVidInfo->RedMask = TS_RED_MASK_24BPP;
pVidInfo->GreenMask = TS_GREEN_MASK_24BPP;
pVidInfo->BlueMask = TS_BLUE_MASK_24BPP;
}
break;
case 16:
{
pVidInfo->RedMask = TS_RED_MASK_16BPP;
pVidInfo->GreenMask = TS_GREEN_MASK_16BPP;
pVidInfo->BlueMask = TS_BLUE_MASK_16BPP;
}
break;
case 15:
{
pVidInfo->RedMask = TS_RED_MASK_15BPP;
pVidInfo->GreenMask = TS_GREEN_MASK_15BPP;
pVidInfo->BlueMask = TS_BLUE_MASK_15BPP;
}
break;
default:
{
pVidInfo->RedMask = 0;
pVidInfo->GreenMask = 0;
pVidInfo->BlueMask = 0;
}
break;
}
#endif
pSdIoctl->BytesReturned = sizeof(wdSimModes);
}
}
break;
case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
{
TRC_NRM((TB, "QueryNumAvailableModes"));
if (pSdIoctl->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
{
TRC_ERR((TB,
"QueryNumAvailableModes buffer too small: got/expected %d/%d",
pSdIoctl->OutputBufferLength,
sizeof(VIDEO_NUM_MODES)));
status = STATUS_BUFFER_TOO_SMALL;
}
else
{
PVIDEO_NUM_MODES pNumModes =
(PVIDEO_NUM_MODES)(pSdIoctl->OutputBuffer);
TRC_NRM((TB, "Return 1 mode available"));
pNumModes->NumModes = 1;
pNumModes->ModeInformationLength =
sizeof(VIDEO_MODE_INFORMATION);
pSdIoctl->BytesReturned = sizeof(VIDEO_NUM_MODES);
}
}
break;
case IOCTL_VIDEO_SET_CURRENT_MODE:
{
/****************************************************************/
/* Not clear why we might get this, hence we trace at high */
/* level for now. In any case, the IOCtl is sent to set a */
/* particular VGA mode: we have told Win32 what we support: */
/* either it is setting that, or we have a problem waiting to */
/* happen. */
/****************************************************************/
TRC_ALT((TB, "SetCurrentMode"));
if (pSdIoctl->InputBufferLength < sizeof(VIDEO_MODE))
{
TRC_ERR((TB,
"SetCurrentMode buffer too small: got/expected %d/%d",
pSdIoctl->InputBufferLength, sizeof(VIDEO_MODE) ));
status = STATUS_BUFFER_TOO_SMALL;
}
else
{
TRC_ALT((TB, "Set current mode to %d",
((PVIDEO_MODE)(pSdIoctl->InputBuffer))->RequestedMode));
}
}
break;
case IOCTL_VIDEO_SET_COLOR_REGISTERS:
{
TRC_NRM((TB, "SetColorRegisters"));
}
break;
case IOCTL_VIDEO_RESET_DEVICE:
{
TRC_NRM((TB, "ResetDevice"));
}
break;
/****************************************************************************/
/****************************************************************************/
/* IOCtls that require translation for MCS */
/****************************************************************************/
/****************************************************************************/
/********************************************************************/
/* Process Query Bindings for local and MCS virtual channels */
/********************************************************************/
case IOCTL_ICA_VIRTUAL_QUERY_BINDINGS :
{
PSD_VCBIND pVBind;
/****************************************************************/
/* This IOCtl is issued twice */
/****************************************************************/
if (!pTSWd->bVirtualChannelBound)
{
/************************************************************/
/* First time, return internal channels */
/************************************************************/
pVBind = (PSD_VCBIND) pSdIoctl->OutputBuffer;
/************************************************************/
/* Let MCS define channel(s) */
/************************************************************/
MCSIcaVirtualQueryBindings(pTSWd->hDomainKernel,
&pVBind,
(unsigned int *)&pSdIoctl->
BytesReturned);
// Add RDPDD->RDPWD channel.
RtlCopyMemory(pVBind->VirtualName,
VIRTUAL_THINWIRE,
sizeof(VIRTUAL_THINWIRE));
pVBind->VirtualClass = WD_THINWIRE_CHANNEL;
pSdIoctl->BytesReturned += sizeof(SD_VCBIND);
pTSWd->bVirtualChannelBound = TRUE;
TRC_NRM((TB, "%d Virtual Channels (first time)",
pSdIoctl->BytesReturned/sizeof(SD_VCBIND)));
}
else
{
/************************************************************/
/* Second time, return virtual channels */
/************************************************************/
pVBind = (PSD_VCBIND)pSdIoctl->OutputBuffer;
status = NM_VirtualQueryBindings(pTSWd->pNMInfo,
pVBind,
pSdIoctl->OutputBufferLength,
&(pSdIoctl->BytesReturned));
TRC_NRM((TB, "%d Virtual Channels (second time)",
pSdIoctl->BytesReturned/sizeof(SD_VCBIND)));
}
}
break;
/********************************************************************/
/* T.120 request from user mode - pass it on */
/********************************************************************/
case IOCTL_T120_REQUEST:
{
status = MCSIcaT120Request(pTSWd->hDomainKernel, pSdIoctl);
}
break;
#ifdef USE_LICENSE
/****************************************************************************/
/****************************************************************************/
/* Licensing IOCtls */
/****************************************************************************/
/****************************************************************************/
/********************************************************************/
/* Query the client licensing capabilities
/********************************************************************/
case IOCTL_ICA_STACK_QUERY_LICENSE_CAPABILITIES:
{
PLICENSE_CAPABILITIES pLicenseCap;
if( pSdIoctl->OutputBufferLength < sizeof( LICENSE_CAPABILITIES ) )
{
TRC_ERR( ( TB,
"QueryLicenseCapabilities buffer too small: got/expected %d/%d",
pSdIoctl->OutputBufferLength, sizeof( LICENSE_CAPABILITIES ) ) );
status = STATUS_BUFFER_TOO_SMALL;
}
else
{
//
// set the client licensing capability. Here we temporarily hard-code
// the client to use the RSA key exchange algorithm and the licensing
// protocol version.
//
pLicenseCap = ( PLICENSE_CAPABILITIES )( pSdIoctl->OutputBuffer );
pLicenseCap->KeyExchangeAlg = KEY_EXCHANGE_ALG_RSA;
if( RNS_TERMSRV_40_UD_VERSION >= pTSWd->version )
{
//
// this is a hydra 4.0 client, use the corresponding licensing
// protocol.
//
pLicenseCap->ProtocolVer = LICENSE_HYDRA_40_PROTOCOL_VERSION;
pLicenseCap->fAuthenticateServer = TRUE;
}
else
{
//
// Use the latest licensing protocol for later clients
//
pLicenseCap->ProtocolVer = LICENSE_HIGHEST_PROTOCOL_VERSION;
//
// if encryption is enabled, then the server has already been
// authenticated in the earlier key exchange protocol and the
// licensing protocol does not have to authenticate the server
// again.
//
pLicenseCap->fAuthenticateServer = ( SM_IsSecurityExchangeCompleted(
pTSWd->pSmInfo,
&pLicenseCap->CertType ) ?
FALSE : TRUE );
}
TRC_NRM( ( TB, "Key Exchange Alg = %d", pLicenseCap->KeyExchangeAlg ) );
TRC_NRM( ( TB, "License Protocol Version = %x", pLicenseCap->ProtocolVer ) );
//
// copy the client name
//
if( pLicenseCap->pbClientName )
{
memcpy( pLicenseCap->pbClientName,
pTSWd->clientName,
( ( pLicenseCap->cbClientName < sizeof( pTSWd->clientName ) ) ?
pLicenseCap->cbClientName : sizeof( pTSWd->clientName ) ) );
}
pSdIoctl->BytesReturned = sizeof( LICENSE_CAPABILITIES );
}
}
break;
/********************************************************************/
/* Send and receive licensing protocol data to and from client.
/********************************************************************/
case IOCTL_ICA_STACK_REQUEST_CLIENT_LICENSE:
{
PLicense_Handle pLicenseHandle;
BOOL rc = FALSE;
BOOL encrypingLicToCli;
NTSTATUS waitStatus;
PBYTE pOutBuffer;
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)(pTSWd->pSmInfo);
PRNS_SECURITY_HEADER pLicenseHeader;
pLicenseHandle = ( PLicense_Handle )pTSWd->pSLicenseHandle;
//
// validate input parameters
//
ASSERT( NULL != pLicenseHandle );
ASSERT( NULL != pSdIoctl->InputBuffer );
ASSERT( 0 < pSdIoctl->InputBufferLength );
if( ( NULL == pLicenseHandle ) ||
( NULL == pSdIoctl->InputBuffer ) ||
( 0 >= pSdIoctl->InputBufferLength ) )
{
TRC_ERR( ( TB, "invalid Licensing IOCTL parameters" ) );
status = STATUS_INVALID_PARAMETER;
break;
}
if( ( pSdIoctl->OutputBuffer ) && ( pSdIoctl->OutputBufferLength > 0 ) )
{
//
// set the output buffer pointer so that we can receive data
// when the client response
//
pLicenseHandle->pDataBuf = ( PBYTE )pSdIoctl->OutputBuffer;
pLicenseHandle->cbDataBuf = pSdIoctl->OutputBufferLength;
}
else
{
pLicenseHandle->pDataBuf = NULL;
pLicenseHandle->cbDataBuf = 0;
}
//
// We will encrypt the S->C licensing packet if encryption is
// on AND if the client told us they can decrypt this particular
// packet.
// If encryptDisplayData is not set (low encryption), we don't
// encrypt the S->C licensing packet
//
encrypingLicToCli = (pRealSMHandle->encrypting &&
pRealSMHandle->encryptingLicToClient &&
pRealSMHandle->encryptDisplayData);
if (!encrypingLicToCli)
{
//
// Allocate an NM buffer for sending the data. we are allocating an extra
// DWORD to hack around the encryption problem.
// fWait is TRUE means that we will always wait for a buffer to be avail
status = NM_AllocBuffer( pTSWd->pNMInfo,
( PPVOID )&pOutBuffer,
pSdIoctl->InputBufferLength +
sizeof( RNS_SECURITY_HEADER ),
TRUE );
if( STATUS_SUCCESS != status || pTSWd->hDomainKernel == NULL)
{
TRC_ERR( ( TB, "Failed to allocate NM buffer" ) );
if (STATUS_SUCCESS == status) {
NM_FreeBuffer(pTSWd->pNMInfo, pOutBuffer);
status = STATUS_NET_WRITE_FAULT;
}
else {
// Follow old code path.
status = STATUS_NO_MEMORY;
}
break;
}
//
// initialize the license data header
//
pLicenseHeader = ( PRNS_SECURITY_HEADER )pOutBuffer;
//
// Indicate this is a licensing packet and then cheat and sneak
// in the flag that indicates the client should encrypt all
// licensing data sent to the server (early capabilities)
//
pLicenseHeader->flags = RNS_SEC_LICENSE_PKT |
RDP_SEC_LICENSE_ENCRYPT_CS;
pLicenseHeader->flagsHi = ( WORD )pSdIoctl->InputBufferLength;
//
// copy the data over
//
ASSERT( NULL != pOutBuffer );
memcpy( pOutBuffer + sizeof( RNS_SECURITY_HEADER ),
pSdIoctl->InputBuffer,
pSdIoctl->InputBufferLength );
}
else
{
if (STATUS_SUCCESS == SM_AllocBuffer(pTSWd->pSmInfo, (PPVOID) &pOutBuffer, pSdIoctl->InputBufferLength, TRUE, FALSE))
{
memcpy(pOutBuffer, (PBYTE)pSdIoctl->InputBuffer, pSdIoctl->InputBufferLength);
}
else {
TRC_ERR((TB, "FAILED to alloc license data buffer"));
status = STATUS_NO_MEMORY;
break;
}
}
//
// clear the incoming data event
//
KeClearEvent( pLicenseHandle->pDataEvent );
//
// send the data in the input buffer
//
if (encrypingLicToCli)
{
rc = SM_SendData(pTSWd->pSmInfo, pOutBuffer, pSdIoctl->InputBufferLength,
TS_HIGHPRIORITY, 0, FALSE, RNS_SEC_LICENSE_PKT | RDP_SEC_LICENSE_ENCRYPT_CS | RNS_SEC_ENCRYPT, FALSE);
}
else
{
rc = NM_SendData(pTSWd->pNMInfo, (BYTE *)pOutBuffer,
pSdIoctl->InputBufferLength + sizeof(RNS_SECURITY_HEADER),
TS_HIGHPRIORITY, 0, FALSE);
}
if (!rc)
{
TRC_ERR((TB, "Failed to send licensing data"));
status = STATUS_NET_WRITE_FAULT;
break;
}
if (pLicenseHandle->pDataBuf)
{
//
// caller supplied a return buffer, wait for the client response
//
waitStatus = WDW_WaitForConnectionEvent(pTSWd,
pLicenseHandle->pDataEvent, 60000L);
if (STATUS_TIMEOUT == waitStatus)
{
TRC_ERR( ( TB, "Timeout waiting for client licensing response" ) );
pSdIoctl->BytesReturned = 0;
status = STATUS_IO_TIMEOUT;
}
else
{
//
// got the client response, check that the data is received
// correctly
//
if( !NT_SUCCESS( pLicenseHandle->Status ) )
{
status = pLicenseHandle->Status;
//
// The data was not copied correctly. If the buffer provided is
// too small, let the caller know the right size of the
// buffer to provide.
//
if( STATUS_BUFFER_TOO_SMALL == status )
{
TRC_ERR( ( TB,
"IOCTL_ICA_STACK_REQUEST_CLIENT_LICENSE buffer too small: got/expected %d/%d",
pSdIoctl->InputBufferLength, pLicenseHandle->cbCacheBuf ) );
pSdIoctl->BytesReturned = pLicenseHandle->cbCacheBuf;
}
else
{
pSdIoctl->BytesReturned = 0;
}
}
else
{
pSdIoctl->BytesReturned = pLicenseHandle->cbDataBuf;
}
}
if (status != STATUS_SUCCESS)
{
// Make sure we don't try to write to pointer when
// client data comes in
pLicenseHandle->pDataBuf = NULL;
pLicenseHandle->cbDataBuf = 0;
}
}
else
{
//
// caller did not supply a return buffer, simply return
//
pSdIoctl->BytesReturned = 0;
}
}
break;
/********************************************************************/
/* Send licensing protocol data to client without waiting for reply.
/********************************************************************/
case IOCTL_ICA_STACK_SEND_CLIENT_LICENSE:
{
PLicense_Handle pLicenseHandle;
BOOL rc = FALSE;
BOOL encrypingLicToCli;
PBYTE pOutBuffer;
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)(pTSWd->pSmInfo);
PRNS_SECURITY_HEADER pLicenseHeader;
pLicenseHandle = ( PLicense_Handle )pTSWd->pSLicenseHandle;
//
// validate input parameters
//
ASSERT( NULL != pLicenseHandle );
ASSERT( NULL != pSdIoctl->InputBuffer );
ASSERT( 0 < pSdIoctl->InputBufferLength );
if( ( NULL == pLicenseHandle ) ||
( NULL == pSdIoctl->InputBuffer ) ||
( 0 >= pSdIoctl->InputBufferLength ) )
{
TRC_ERR( ( TB, "invalid Licensing IOCTL parameters" ) );
status = STATUS_INVALID_PARAMETER;
break;
}
//
// We will encrypt the S->C licensing packet if encryption is
// on AND if the client told us they can decrypt this particular
// packet.
// If encryptDisplayData is not set (low encryption), we don't
// encrypt the S->C licensing packet
//
encrypingLicToCli = (pRealSMHandle->encrypting &&
pRealSMHandle->encryptingLicToClient &&
pRealSMHandle->encryptDisplayData);
if (!encrypingLicToCli)
{
//
// allocate NM buffer for sending
// fWait is TRUE means that we will always wait for a buffer to be avail
status = NM_AllocBuffer( pTSWd->pNMInfo,
( PPVOID )&pOutBuffer,
pSdIoctl->InputBufferLength + sizeof( RNS_SECURITY_HEADER ),
TRUE );
if( STATUS_SUCCESS != status || pTSWd->hDomainKernel == NULL)
{
TRC_ERR( ( TB, "Failed to allocate SM buffer" ) );
if (STATUS_SUCCESS == status) {
NM_FreeBuffer(pTSWd->pNMInfo, pOutBuffer);
status = STATUS_NET_WRITE_FAULT;
}
else {
// Follow old code path.
status = STATUS_NO_MEMORY;
}
break;
}
//
// initialize the license data header
//
pLicenseHeader = ( PRNS_SECURITY_HEADER )pOutBuffer;
//
// Indicate this is a licensing packet and then cheat and sneak
// in the flag that indicates the client should encrypt all
// licensing data sent to the server (early capabilities)
//
pLicenseHeader->flags = RNS_SEC_LICENSE_PKT |
RDP_SEC_LICENSE_ENCRYPT_CS;
pLicenseHeader->flagsHi = ( WORD )pSdIoctl->InputBufferLength;
//
// copy the data over
//
ASSERT( NULL != pOutBuffer );
memcpy( pOutBuffer + sizeof( RNS_SECURITY_HEADER ),
pSdIoctl->InputBuffer,
pSdIoctl->InputBufferLength );
}
else
{
if (STATUS_SUCCESS == SM_AllocBuffer(pTSWd->pSmInfo, (PPVOID) &pOutBuffer, pSdIoctl->InputBufferLength, TRUE, FALSE))
{
memcpy(pOutBuffer, (PBYTE)pSdIoctl->InputBuffer, pSdIoctl->InputBufferLength);
}
else {
TRC_ERR((TB, "FAILED to alloc license data buffer"));
status = STATUS_NO_MEMORY;
break;
}
}
//
// clear the incoming data event
//
KeClearEvent(pLicenseHandle->pDataEvent);
//
// send the data in the input buffer
//
if (encrypingLicToCli)
{
rc = SM_SendData(pTSWd->pSmInfo, pOutBuffer, pSdIoctl->InputBufferLength,
TS_HIGHPRIORITY, 0, FALSE, RNS_SEC_LICENSE_PKT | RDP_SEC_LICENSE_ENCRYPT_CS | RNS_SEC_ENCRYPT, FALSE);
}
else
{
rc = NM_SendData(pTSWd->pNMInfo, (BYTE *)pOutBuffer,
pSdIoctl->InputBufferLength + sizeof(RNS_SECURITY_HEADER),
TS_HIGHPRIORITY, 0, FALSE);
}
if (!rc)
{
TRC_ERR( ( TB, "Failed to send licensing data" ) );
status = STATUS_NET_WRITE_FAULT;
}
}
break;
/********************************************************************/
/* Indicate that the licensing protocol has completed.
/********************************************************************/
case IOCTL_ICA_STACK_LICENSE_PROTOCOL_COMPLETE:
{
PULONG pResult;
//
// validate input parameters
//
ASSERT( NULL != pSdIoctl->InputBuffer );
ASSERT( 0 < pSdIoctl->InputBufferLength );
if( ( NULL == pSdIoctl->InputBuffer ) ||
( 0 >= pSdIoctl->InputBufferLength ) )
{
TRC_ERR( ( TB, "invalid Licensing IOCTL parameters" ) );
status = STATUS_INVALID_PARAMETER;
break;
}
//
// Tell SM if the client license has been validated successfully
//
pResult = ( PULONG )( pSdIoctl->InputBuffer );
if( LICENSE_PROTOCOL_SUCCESS == ( *pResult ) )
{
SM_LicenseOK(pTSWd->pSmInfo);
}
}
break;
/********************************************************************/
/* Indicate to retrieve the licensing data that was previously
/* cached.
/********************************************************************/
case IOCTL_ICA_STACK_GET_LICENSE_DATA:
{
PLicense_Handle pLicenseHandle = ( PLicense_Handle )pTSWd->pSLicenseHandle;
//
// validate input parameters
//
if ((NULL == pSdIoctl->OutputBuffer) ||
(NULL == pLicenseHandle))
{
pSdIoctl->BytesReturned = 0;
status = STATUS_INVALID_PARAMETER;
break;
}
//
// check that there's actually cached data
//
if( NULL == pLicenseHandle->pCacheBuf )
{
pSdIoctl->BytesReturned = 0;
status = STATUS_NO_DATA_DETECTED;
break;
}
if( pSdIoctl->OutputBufferLength < pLicenseHandle->cbCacheBuf )
{
pSdIoctl->BytesReturned = 0;
status = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// copy the cached data and free the cached data buffer
//
memcpy(pSdIoctl->OutputBuffer,
pLicenseHandle->pCacheBuf,
pLicenseHandle->cbCacheBuf );
pSdIoctl->BytesReturned = pLicenseHandle->cbCacheBuf;
ExFreePool( pLicenseHandle->pCacheBuf );
pLicenseHandle->pCacheBuf = NULL;
}
break;
#endif // #ifdef USE_LICENSE
/********************************************************************/
/* shadow only IOCTLS */
/********************************************************************/
// Pass all relevent stack data from the client's primary stack to the
// target's shadow stack.
case IOCTL_ICA_STACK_QUERY_MODULE_DATA:
TRC_ALT((TB, "IOCTL_ICA_STACK_QUERY_MODULE_DATA(%p) - stack class %d",
pTSWd, pTSWd->StackClass));
if ((pTSWd->StackClass == Stack_Primary) ||
(pTSWd->StackClass == Stack_Console)) {
status = WDWGetModuleData(pTSWd, pSdIoctl);
}
break;
// Pass all relevant capabilities data from the client to the shadow
// target display driver.
case IOCTL_ICA_VIRTUAL_QUERY_MODULE_DATA:
PTSHARE_VIRTUAL_MODULE_DATA pVirtModuleData;
PTS_COMBINED_CAPABILITIES pCaps;
PTS_GENERAL_CAPABILITYSET pGenCapSet;
unsigned capsLength;
ShareClass * dcShare;
dcShare = (ShareClass *)(pTSWd->dcShare);
dcShare->SC_GetCombinedCapabilities(SC_REMOTE_PERSON_ID,
&capsLength, &pCaps);
if (pCaps != NULL) {
pGenCapSet = (PTS_GENERAL_CAPABILITYSET) WDW_GetCapSet(
pTSWd, TS_CAPSETTYPE_GENERAL, pCaps, capsLength);
if (pGenCapSet != NULL) {
// update the compression capability
if (pTSWd->bCompress) {
pGenCapSet->extraFlags |= TS_SHADOW_COMPRESSION_LEVEL;
pGenCapSet->generalCompressionLevel = (TSUINT16)pTSWd->pMPPCContext->ClientComprType;
}
}
if (pSdIoctl->OutputBufferLength >=
(capsLength + sizeof(TSHARE_VIRTUAL_MODULE_DATA) - 1)) {
pVirtModuleData = (PTSHARE_VIRTUAL_MODULE_DATA) pSdIoctl->OutputBuffer;
pVirtModuleData->capsLength = capsLength;
memcpy(&pVirtModuleData->combinedCapabilities,
pCaps, capsLength);
}
else {
status = STATUS_BUFFER_OVERFLOW;
}
}
else {
status = STATUS_NO_MEMORY;
}
pSdIoctl->BytesReturned = capsLength +
sizeof(TSHARE_VIRTUAL_MODULE_DATA) - 1;
TRC_ALT((TB, "IOCTL_ICA_VIRTUAL_QUERY_MODULE_DATA: rc=%lx, in=%ld, out=%ld",
status, pSdIoctl->OutputBufferLength, pSdIoctl->BytesReturned));
break;
case IOCTL_WDTS_DD_SHADOW_CONNECT:
{
if (pSdIoctl->InputBuffer &&
(((PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer)->pShm)) {
WDW_CHECK_SHM(
(((PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer)->pShm));
TRC_ALT((TB, "++TSHARE_DD_SHADOW_CONNECT(%p) - stack class %d",
pTSWd, pTSWd->StackClass));
status = WDWDDShadowConnect(pTSWd, pSdIoctl);
TRC_ALT((TB, "--TSHARE_DD_SHADOW_CONNECT(%p) - stack class %d",
pTSWd, pTSWd->StackClass));
WDW_CHECK_SHM(
(((PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer)->pShm));
}
else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
#ifdef DC_HICOLOR
// Maybe get the caps of the shadower
case IOCTL_WDTS_DD_QUERY_SHADOW_CAPS:
{
// only respond to this if we're a shadow stack
if (pTSWd->StackClass == Stack_Shadow)
{
PTS_COMBINED_CAPABILITIES pCaps;
PTSHARE_VIRTUAL_MODULE_DATA pVMData = NULL;
unsigned capsLength;
ShareClass * dcShare;
dcShare = (ShareClass *)(pTSWd->dcShare);
if (pSdIoctl->OutputBufferLength >= sizeof(unsigned))
{
pVMData = (PTSHARE_VIRTUAL_MODULE_DATA)pSdIoctl->OutputBuffer;
}
dcShare->SC_GetCombinedCapabilities(SC_REMOTE_PERSON_ID,
&capsLength, &pCaps);
if (pCaps != NULL)
{
if (pSdIoctl->OutputBufferLength >=
(capsLength + sizeof(unsigned)))
{
memcpy(&pVMData->combinedCapabilities,
pCaps, capsLength);
}
else
{
status = STATUS_BUFFER_OVERFLOW;
}
}
else
{
status = STATUS_NO_MEMORY;
}
pSdIoctl->BytesReturned = capsLength + sizeof(unsigned);
if (pVMData)
{
pVMData->capsLength = capsLength;
}
TRC_ALT((TB, "IOCTL_WDTS_DD_QUERY_SHADOW_CAPS:" \
" rc=%lx, in=%ld, out=%ld",
status, pSdIoctl->OutputBufferLength,
pSdIoctl->BytesReturned));
}
else
{
TRC_ALT((TB, "IOCTL_WDTS_DD_QUERY_SHADOW_CAPS: " \
"not shadow stack so ignoring"));
TRC_ALT((TB, " rc=%lx, in=%ld, out=%ld",
status, pSdIoctl->OutputBufferLength,
pSdIoctl->BytesReturned));
}
}
break;
case IOCTL_WDTS_DD_SHADOW_SYNCHRONIZE:
{
ShareClass * dcShare;
PTS_COMBINED_CAPABILITIES pCaps;
unsigned capsLen;
if (pSdIoctl->InputBuffer &&
(((PTSHARE_DD_SHADOWSYNC_IN)pSdIoctl->InputBuffer)->pShm)) {
WDW_CHECK_SHM(
(((PTSHARE_DD_SHADOWSYNC_IN)pSdIoctl->InputBuffer)->pShm));
// synchronize this stack, this is required so that OE2 will match up
// for both shadow client and target.
dcShare = (ShareClass *)(pTSWd->dcShare);
pCaps = ((PTSHARE_DD_SHADOWSYNC_IN)pSdIoctl->InputBuffer)->pShadowCaps;
capsLen = ((PTSHARE_DD_SHADOWSYNC_IN)pSdIoctl->InputBuffer)->capsLen;
dcShare->SC_ShadowSyncShares(pCaps, capsLen);
TRC_ALT((TB, "Synchronized share for stack [%ld]", pTSWd->StackClass));
WDW_CHECK_SHM(
(((PTSHARE_DD_SHADOWSYNC_IN)pSdIoctl->InputBuffer)->pShm));
}
else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
#else
case IOCTL_WDTS_DD_SHADOW_SYNCHRONIZE:
{
ShareClass * dcShare;
if (pSdIoctl->InputBuffer &&
(((PTSHARE_DD_SHADOWSYNC_IN)pSdIoctl->InputBuffer)->pShm)) {
WDW_CHECK_SHM(
(((PTSHARE_DD_SHADOWSYNC_IN)pSdIoctl->InputBuffer)->pShm));
// synchronize this stack, this is required so that OE2 will match up
// for both shadow client and target.
dcShare = (ShareClass *)(pTSWd->dcShare);
dcShare->SC_ShadowSyncShares();
TRC_ALT((TB, "Synchronized share for stack [%ld]", pTSWd->StackClass));
WDW_CHECK_SHM(
(((PTSHARE_DD_SHADOWSYNC_IN)pSdIoctl->InputBuffer)->pShm));
}
else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
#endif
case IOCTL_WDTS_DD_SHADOW_DISCONNECT:
{
if (pSdIoctl->InputBuffer &&
(((PTSHARE_DD_DISCONNECT_IN)pSdIoctl->InputBuffer)->pShm)) {
WDW_CHECK_SHM(
(((PTSHARE_DD_DISCONNECT_IN)pSdIoctl->InputBuffer)->pShm));
status = WDWDDShadowDisconnect(pTSWd, pSdIoctl);
WDW_CHECK_SHM(
(((PTSHARE_DD_DISCONNECT_IN)pSdIoctl->InputBuffer)->pShm));
}
else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
case IOCTL_ICA_STACK_REGISTER_HOTKEY :
{
PICA_STACK_HOTKEY pHotkey = (PICA_STACK_HOTKEY) pSdIoctl->InputBuffer;
if (pHotkey->HotkeyVk) {
pTSWd->shadowState = SHADOW_CLIENT;
pTSWd->HotkeyVk = pHotkey->HotkeyVk;
pTSWd->HotkeyModifiers = pHotkey->HotkeyModifiers;
TRC_ALT((TB, "IOCTL_ICA_STACK_REGISTER_HOTKEY - Enable Vk(%ld, %lx)",
pHotkey->HotkeyVk, pHotkey->HotkeyModifiers));
// Allocate and initialize a physical key state array
status = KeyboardSetKeyState(pTSWd, &pTSWd->pgafPhysKeyState);
if (NT_SUCCESS(status)) {
TRC_ALT((TB, "Allocated phys key state"));
}
else {
TRC_ALT((TB, "Failed to alloc phys key states: %lx", status));
}
// VCs don't work when shadowing. Tell VC subsystem to
// suspend now.
WDWVCMessage(pTSWd, CHANNEL_FLAG_SUSPEND);
}
else
{
pTSWd->shadowState = SHADOW_NONE;
pTSWd->HotkeyVk = 0;
pTSWd->HotkeyModifiers = 0;
TRC_ALT((TB, "IOCTL_ICA_STACK_REGISTER_HOTKEY - Disable"));
if (pTSWd->pShadowInfo != NULL) {
TRC_ALT((TB, "Primary client stack freeing reassembly info [%p]",
pTSWd->pShadowInfo));
COM_Free(pTSWd->pShadowInfo);
pTSWd->pShadowInfo = NULL;
}
// VCs don't work when shadowing. Tell VC subsystem to
// resume now.
WDWVCMessage(pTSWd, CHANNEL_FLAG_RESUME);
}
}
break;
case IOCTL_WDTS_DD_GET_BITMAP_KEYDATABASE:
{
ShareClass *dcShare;
PTSHARE_DD_BITMAP_KEYDATABASE_OUT pKDBOut =
(PTSHARE_DD_BITMAP_KEYDATABASE_OUT) pSdIoctl->OutputBuffer;
dcShare = (ShareClass *)(pTSWd->dcShare);
TRC_NRM((TB, "DD tries to get keydatabase\n"));
if (dcShare != NULL) {
// We have a valid share class, get the key database
dcShare->SBC_GetBitmapKeyDatabase(&pKDBOut->bitmapKeyDatabaseSize,
&pKDBOut->bitmapKeyDatabase);
}
}
break;
#ifdef DC_DEBUG
case IOCTL_WDTS_DD_ICABREAKONDEBUGGER:
{
IcaBreakOnDebugger();
}
break;
#endif
/********************************************************************/
// Send KeepAlive PDU IOCTL
/********************************************************************/
case IOCTL_ICA_STACK_SEND_KEEPALIVE_PDU:
{
ShareClass *dcShare;
dcShare = (ShareClass *)(pTSWd->dcShare);
TRC_NRM((TB, "TermDD requests to send a keepalive pkt to client\n"));
if (dcShare != NULL) {
// We have a valid share class, send a keepalive pdu to client
dcShare->SC_KeepAlive();
}
}
break;
/********************************************************************/
// Load balancing IOCTLs.
/********************************************************************/
case IOCTL_TS_STACK_QUERY_LOAD_BALANCE_INFO:
{
TS_LOAD_BALANCE_INFO *pLBInfo =
(TS_LOAD_BALANCE_INFO *)pSdIoctl->OutputBuffer;
TRC_ASSERT((pSdIoctl->OutputBufferLength >=
sizeof(TS_LOAD_BALANCE_INFO)),
(TB,"Invalid output buf size %u for STACK_QUERY_LBINFO",
pSdIoctl->OutputBufferLength));
// We need to fill in the IOCTL info from the gathered client
// info packet and the initial capabilities.
pLBInfo->bClientSupportsRedirection =
pTSWd->bClientSupportsRedirection;
pLBInfo->bRequestedSessionIDFieldValid =
pTSWd->bRequestedSessionIDFieldValid;
pLBInfo->RequestedSessionID = pTSWd->RequestedSessionID;
pLBInfo->bUseSmartcardLogon = pTSWd->bUseSmartcardLogon;
pLBInfo->ProtocolType = PROTOCOL_RDP;
pLBInfo->bClientRequireServerAddr =
pTSWd->ClientRedirectionVersion > TS_CLUSTER_REDIRECTION_VERSION1 ? 0 : 1;
pLBInfo->ClientRedirectionVersion = pTSWd->ClientRedirectionVersion;
wcsncpy(pLBInfo->UserName, (WCHAR *)pTSWd->pInfoPkt->UserName,
sizeof(pLBInfo->UserName) / sizeof(WCHAR) - 1);
pLBInfo->UserName[sizeof(pLBInfo->UserName) / sizeof(WCHAR) - 1] =
L'\0';
wcsncpy(pLBInfo->Domain, (WCHAR *)pTSWd->pInfoPkt->Domain,
sizeof(pLBInfo->Domain) / sizeof(WCHAR) - 1);
pLBInfo->Domain[sizeof(pLBInfo->Domain) / sizeof(WCHAR) - 1] =
L'\0';
wcsncpy(pLBInfo->InitialProgram,
(WCHAR *)pTSWd->pInfoPkt->AlternateShell,
sizeof(pLBInfo->InitialProgram) / sizeof(WCHAR) - 1);
pLBInfo->InitialProgram[sizeof(pLBInfo->InitialProgram) /
sizeof(WCHAR) - 1] = L'\0';
break;
}
case IOCTL_TS_STACK_SEND_CLIENT_REDIRECTION:
{
BOOL rc;
TS_CLIENT_REDIRECTION_INFO *pRedirInfo =
(TS_CLIENT_REDIRECTION_INFO *)pSdIoctl->InputBuffer;
TRC_ASSERT((pSdIoctl->InputBufferLength >=
sizeof(TS_CLIENT_REDIRECTION_INFO)),
(TB,"Invalid input buf size %u for STACK_CLIENT_REDIR",
pSdIoctl->InputBufferLength));
if (pTSWd->ClientRedirectionVersion == TS_CLUSTER_REDIRECTION_VERSION1) {
RDP_SERVER_REDIRECTION_PACKET *pPkt;
PBYTE ServerName;
unsigned PktSize;
unsigned ServerNameLen;
// Get the server name length in bytes, including null.
ServerNameLen = *((ULONG UNALIGNED*)(pRedirInfo + 1));
ServerName = (PBYTE)(pRedirInfo + 1) + sizeof(ULONG);
// Calculate the PDU size.
PktSize = sizeof(RDP_SERVER_REDIRECTION_PACKET) + ServerNameLen -
sizeof(WCHAR);
// The client username/domain info resulted in an off-machine
// session to be redirected-to. We receive this IOCTL before
// the licensing protocll occurs, hence we need to send a
// non-data packet. If the client indicated support for
// redirection, it must know how to parse this type of packet.
status = NM_AllocBuffer(pTSWd->pNMInfo, (PPVOID)&pPkt,
PktSize, TRUE);
if ( STATUS_SUCCESS == status && pTSWd->hDomainKernel != NULL) {
// Fill in the packet fields.
pPkt->Flags = RDP_SEC_REDIRECTION_PKT;
pPkt->Length = (UINT16)PktSize;
pPkt->SessionID = pRedirInfo->SessionID;
memcpy(pPkt->ServerAddress, ServerName, ServerNameLen);
TRC_DBG((TB, "Client Redirection PDU V1, ServerName: %S, ServerNameLen: %d",
ServerName, ServerNameLen));
rc = NM_SendData(pTSWd->pNMInfo, (BYTE *)pPkt, PktSize,
TS_HIGHPRIORITY, 0, FALSE);
if (rc) {
TRC_ALT((TB, "Sent TS_SERVER_REDIRECT_PDU: %u", PktSize));
status = STATUS_SUCCESS;
}
else {
TRC_ERR((TB,"Failed to send redir PDU"));
status = STATUS_UNSUCCESSFUL;
}
}
else {
TRC_ERR((TB, "Failed to alloc %d bytes for redir PDU",
PktSize));
if (STATUS_SUCCESS == status) {
NM_FreeBuffer(pTSWd->pNMInfo, pPkt);
}
// prevent regression, keep original return code.
status = STATUS_UNSUCCESSFUL;
}
}
else if (pTSWd->ClientRedirectionVersion == TS_CLUSTER_REDIRECTION_VERSION2) {
RDP_SERVER_REDIRECTION_PACKET_V2 *pPkt;
unsigned PktSize, DataLen;
// Calculate the PDU size
DataLen = pSdIoctl->InputBufferLength - sizeof(TS_CLIENT_REDIRECTION_INFO);
PktSize = sizeof(RDP_SERVER_REDIRECTION_PACKET_V2) + DataLen;
// The client username/domain info resulted in an off-machine
// session to be redirected-to. We receive this IOCTL before
// the licensing protocll occurs, hence we need to send a
// non-data packet. If the client indicated support for
// redirection, it must know how to parse this type of packet.
status = NM_AllocBuffer(pTSWd->pNMInfo, (PPVOID)&pPkt,
PktSize, TRUE);
if ( STATUS_SUCCESS == status && pTSWd->hDomainKernel != NULL) {
// Fill in the packet fields.
pPkt->Flags = RDP_SEC_REDIRECTION_PKT2;
pPkt->Length = (UINT16)PktSize;
pPkt->SessionID = pRedirInfo->SessionID;
pPkt->RedirFlags = pRedirInfo->Flags;
memcpy(pPkt + 1, pRedirInfo + 1, DataLen);
TRC_DBG((TB, "Client Redirection PDU V2"));
rc = NM_SendData(pTSWd->pNMInfo, (BYTE *)pPkt, PktSize,
TS_HIGHPRIORITY, 0, FALSE);
if (rc) {
TRC_ALT((TB, "Sent TS_SERVER_REDIRECT_PDU: %u", PktSize));
status = STATUS_SUCCESS;
}
else {
TRC_ERR((TB,"Failed to send redir PDU"));
status = STATUS_UNSUCCESSFUL;
}
}
else {
TRC_ERR((TB, "Failed to alloc %d bytes for redir PDU",
PktSize));
if (STATUS_SUCCESS == status) {
NM_FreeBuffer(pTSWd->pNMInfo, pPkt);
}
// prevent regression, keep original return code.
status = STATUS_UNSUCCESSFUL;
}
}
else {
RDP_SERVER_REDIRECTION_PACKET_V3 *pPkt;
unsigned PktSize, DataLen;
// Calculate the PDU size
DataLen = pSdIoctl->InputBufferLength - sizeof(TS_CLIENT_REDIRECTION_INFO);
PktSize = sizeof(RDP_SERVER_REDIRECTION_PACKET_V3) + DataLen;
status = SM_AllocBuffer(pTSWd->pSmInfo, (PPVOID)&pPkt,
PktSize, TRUE, TRUE);
if ( STATUS_SUCCESS == status ) {
// Fill in the packet fields.
pPkt->Flags = RDP_SEC_REDIRECTION_PKT3;
pPkt->Length = (UINT16)PktSize;
pPkt->SessionID = pRedirInfo->SessionID;
pPkt->RedirFlags = pRedirInfo->Flags;
if (pTSWd->fDontDisplayLastUserName) {
pPkt->RedirFlags |= LB_DONTSTOREUSERNAME;
}
memcpy(pPkt + 1, pRedirInfo + 1, DataLen);
TRC_DBG((TB, "Client Redirection PDU V3"));
rc = SM_SendData(pTSWd->pSmInfo, (BYTE *)pPkt, PktSize,
TS_HIGHPRIORITY, 0, FALSE, RDP_SEC_REDIRECTION_PKT3, TRUE);
if (rc) {
TRC_NRM((TB, "Sent TS_SERVER_REDIRECT_PDU: %u", PktSize));
status = STATUS_SUCCESS;
}
else {
TRC_ERR((TB,"Failed to send redir PDU"));
status = STATUS_UNSUCCESSFUL;
}
}
else {
TRC_ERR((TB, "Failed to alloc %d bytes for redir PDU",
PktSize));
// prevent regression, keep original return code.
status = STATUS_UNSUCCESSFUL;
}
}
break;
}
/****************************************************************************/
/****************************************************************************/
/* Finally the IOCtls that we pass on to the rest of the stack without */
/* getting in the way. */
/****************************************************************************/
/****************************************************************************/
/********************************************************************/
/* This IOCtl indicates the connection is down. Tell MCS before */
/* forwarding the IOCtl */
/********************************************************************/
case IOCTL_ICA_STACK_CANCEL_IO :
{
MCSIcaStackCancelIo(pTSWd->hDomainKernel);
TRC_NRM((TB, "CancelIO - set WD dead"));
// Make sure that Domain.StatusDead is consistent with TSWd.dead
pTSWd->dead = TRUE;
((PDomain)(pTSWd->hDomainKernel))->StatusDead = TRUE;
}
/********************************************************************/
/* NB NOTE NO BREAK here - we drop through deliberately. */
/********************************************************************/
/********************************************************************/
/* modem callback and some others we're not interested in but lower */
/* layers might be */
/********************************************************************/
case IOCTL_ICA_STACK_CALLBACK_INITIATE :
case IOCTL_ICA_STACK_CALLBACK_COMPLETE :
case IOCTL_ICA_STACK_CREATE_ENDPOINT :
case IOCTL_ICA_STACK_OPEN_ENDPOINT :
case IOCTL_ICA_STACK_CLOSE_ENDPOINT :
case IOCTL_ICA_STACK_CONNECTION_WAIT :
case IOCTL_ICA_STACK_CONNECTION_REQUEST : // required for shadowing
case IOCTL_ICA_STACK_QUERY_LOCALADDRESS :
{
status =
IcaCallNextDriver( pTSWd->pContext, SD$IOCTL, pSdIoctl );
TRC_DBG((TB,
"Chaining on IOCtl %#x (function %d): status %#x",
pSdIoctl->IoControlCode,
WDW_IOCTL_FUNCTION(pSdIoctl->IoControlCode),
status));
}
break;
// Returning bad status for this makes GRE ignore it.
case IOCTL_VIDEO_ENUM_MONITOR_PDO:
status = STATUS_DEVICE_NOT_READY;
break;
default:
{
TRC_ALT((TB, "UNKNOWN WdIoctl %#x (function %d): status %#x",
pSdIoctl->IoControlCode,
WDW_IOCTL_FUNCTION(pSdIoctl->IoControlCode),
status));
status =
IcaCallNextDriver( pTSWd->pContext, SD$IOCTL, pSdIoctl );
break;
}
}
DC_END_FN();
DC_EXIT_POINT:
return status;
}
/****************************************************************************/
/* Name: WD_RawWrite */
/* */
/* Purpose: Handle I/O writes to and from the client of a shadow operation*/
/* */
/* Params: IN pTSWd - Points to wd data structure */
/* INOUT pSdRawWrite - Points to a SD_RAWWRITE structure */
/* */
/* Operation: Forward the data to the client of this stack. */
/****************************************************************************/
NTSTATUS WD_RawWrite(PTSHARE_WD pTSWd, PSD_RAWWRITE pSdRawWrite)
{
PUCHAR pInBuffer;
PBYTE pOutBuffer;
ULONG newBytes;
BOOL bSuccess = TRUE;
NTSTATUS status;
DC_BEGIN_FN("WD_RawWrite");
pInBuffer = pSdRawWrite->pBuffer;
newBytes = pSdRawWrite->ByteCount;
status = SM_AllocBuffer(pTSWd->pSmInfo, (PPVOID) &pOutBuffer, newBytes, TRUE, FALSE);
if ( STATUS_SUCCESS == status ) {
memcpy(pOutBuffer, pInBuffer, newBytes);
bSuccess = SM_SendData(pTSWd->pSmInfo, pOutBuffer, newBytes,
PROT_PRIO_MISC, 0, FALSE, RNS_SEC_ENCRYPT, FALSE);
if (bSuccess) {
TRC_NRM((TB, "Sent shadow data to %s: %ld",
(pTSWd->StackClass == Stack_Primary) ? "client" : "target",
newBytes));
status=STATUS_SUCCESS;
}
else {
TRC_ERR((TB, "FAILED to Send shadow data to %s: %ld",
(pTSWd->StackClass == Stack_Primary) ? "client" : "target",
newBytes));
status = STATUS_UNEXPECTED_IO_ERROR;
}
}
else {
TRC_ERR((TB, "FAILED to alloc shadow buffer for %s: %ld",
(pTSWd->StackClass == Stack_Primary) ? "client" : "target",
newBytes));
// prevent regression, keep original return code.
status = STATUS_NO_MEMORY;
}
DC_END_FN();
return status;
}
/****************************************************************************/
/* Name: WDWNewShareClass */
/* */
/* Purpose: Create a new ShareClass object */
/****************************************************************************/
NTSTATUS WDWNewShareClass(PTSHARE_WD pTSWd)
{
NTSTATUS status = STATUS_SUCCESS;
ShareClass *pSC;
DC_BEGIN_FN("WDWNewShareClass");
#ifdef DC_HICOLOR
pSC = new ShareClass(pTSWd, pTSWd->desktopHeight, pTSWd->desktopWidth,
pTSWd->desktopBpp, pTSWd->pSmInfo);
#else
pSC = new ShareClass(pTSWd, pTSWd->desktopHeight, pTSWd->desktopWidth,
8, pTSWd->pSmInfo);
#endif
if (pSC != NULL) {
TRC_NRM((TB, "Created Share Class"));
pTSWd->dcShare = (PVOID)pSC;
}
else {
TRC_ERR((TB, "Failed to create Share Class"));
status = STATUS_NO_MEMORY;
}
DC_END_FN();
return status;
} /* WDWNewShareClass */
/****************************************************************************/
/* Name: WDWDeleteShareClass */
/* */
/* Purpose: Delete a Share Class object */
/****************************************************************************/
void WDWDeleteShareClass(PTSHARE_WD pTSWd)
{
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
DC_BEGIN_FN("WDWDeleteShareClass");
TRC_ASSERT((pSC != NULL), (TB, "NULL Share Class"));
TRC_NRM((TB, "Delete Share Class"));
delete pSC;
pTSWd->dcShare = NULL;
DC_END_FN();
} /* WDWDeleteShareClass */
/****************************************************************************/
/* Name: WDWTermShareClass */
/* */
/* Purpose: Terminate the Share Class */
/****************************************************************************/
void WDWTermShareClass(PTSHARE_WD pTSWd)
{
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
DC_BEGIN_FN("WDWTermShareClass");
TRC_ASSERT((pSC != NULL), (TB, "NULL Share Class"));
if (pTSWd->shareClassInit) {
pSC->DCS_Term();
TRC_NRM((TB, "Share Class terminated"));
pTSWd->shareClassInit = FALSE;
}
else {
TRC_ALT((TB, "Can't terminate uninitialized Share Core"));
}
DC_END_FN();
} /* WDWTermShareClass */
/****************************************************************************/
/* Name: WDWDDConnect */
/* */
/* Purpose: Process an IOCTL_WDTS_DD_CONNECT or */
/* IOCTL_WDTS_DD_SHADOW_CONNECT from the client. */
/* */
/* Params: IN pTSWd - pointer to WD struct */
/* INOUT PSD_IOCTL - pointer to received IOCtl */
/* IN reconnect - TRUE - this is a reconnect */
/* FALSE - this is a connect */
/* */
/* Operation: Save the frame buffer pointer */
/* Initialize the share core (will start to bring the share up) */
/* Return the required pointers to the DD. */
/****************************************************************************/
NTSTATUS WDWDDConnect(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl, BOOL reconnect)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
NTSTATUS waitStatus;
BOOL rc;
PTS_BITMAP_CAPABILITYSET pBitmapCaps;
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
PTSHARE_DD_CONNECT_IN pIn = (PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer;
PTSHARE_DD_CONNECT_OUT pOut =
(PTSHARE_DD_CONNECT_OUT)pSdIoctl->OutputBuffer;
DC_BEGIN_FN("WDWDDConnect");
TRC_ASSERT((pSC != NULL), (TB, "NULL Share Class"));
// Check we're connected OK.
if (!pTSWd->connected) {
TRC_ERR((TB, "Not connected"));
status = STATUS_CONNECTION_DISCONNECTED;
DC_QUIT;
}
// Check we've been given a sensible IOCtl.
if ((pIn == NULL) ||
(pOut == NULL) ||
(pSdIoctl->InputBufferLength < sizeof(TSHARE_DD_CONNECT_IN)) ||
(pSdIoctl->OutputBufferLength < sizeof(TSHARE_DD_CONNECT_OUT)))
{
status = STATUS_BUFFER_TOO_SMALL;
TRC_ERR((TB, "A buffer not present or big enough, %p, %lu; %p, %lu",
pIn, pSdIoctl->InputBufferLength,
pOut, pSdIoctl->OutputBufferLength));
DC_QUIT;
}
// Check that the DD sizeof(SHM_SHARED_MEMORY) matches our expectations.
// If not, we have mismatched binaries.
if (pIn->DDShmSize != sizeof(SHM_SHARED_MEMORY)) {
DbgPrint("****** RDPWD: Mismatched DD/WD - DD Shm size=%u, WD=%u\n",
pIn->DDShmSize, sizeof(SHM_SHARED_MEMORY));
return STATUS_INVALID_PARAMETER;
}
// Set returned buffer length.
pSdIoctl->BytesReturned = sizeof(TSHARE_DD_CONNECT_OUT);
// Increment the loadcount
pTSWd->shareId = InterlockedIncrement(&WD_ShareId);
((PSHM_SHARED_MEMORY) (pIn->pShm))->shareId = pTSWd->shareId;
// Now get the share core initialized or reconnected.
if (reconnect) {
// Restore the timer info.
TRC_NRM((TB, "Reconnect Share Core"));
pTSWd->ritTimer = pIn->pKickTimer;
WDW_StartRITTimer(pTSWd, pTSWd->interactiveDelay);
}
else {
// Check for re-initialization.
// This is now legal with console disconnect.
// if (pTSWd->shareClassInit)
// {
//
// if (pTSWd->StackClass != Stack_Console)
// {
// TRC_ERR((TB, "Re-initialization - fail it"));
// status = STATUS_UNSUCCESSFUL;
// DC_QUIT;
// }
// else
// {
// TRC_ALT((TB, "Re-initialize console stack"));
// }
// }
//Make sure the sbcKeyDatabase is freed before initialization
if (pTSWd->shareClassInit)
{
pSC->SBC_FreeBitmapKeyDatabase();
}
// Initialize the Share Core.
TRC_NRM((TB, "Initialize Share Core"));
pSC->m_pShm = (SHM_SHARED_MEMORY *)pIn->pShm;
rc = pSC->DCS_Init(pTSWd, pTSWd->pSmInfo);
pSC->m_pShm = NULL;
if (rc) {
// Initialized OK
TRC_NRM((TB, "Share Class initialized, rc %d", rc));
pTSWd->shareClassInit = TRUE;
}
else {
TRC_ERR((TB, "Failed to initialize Share Class"));
status = STATUS_UNSUCCESSFUL;
DC_QUIT;
}
}
// If this is the primary stack, tell the display driver the desktop
// width/height we need to use.
if ((pTSWd->StackClass == Stack_Primary) ||
(pTSWd->StackClass == Stack_Console)) {
pOut->desktopHeight = pTSWd->desktopHeight;
pOut->desktopWidth = pTSWd->desktopWidth;
// Share's on its way up, so give the key values back to the DD.
pOut->pTSWd = (PVOID)pTSWd;
pOut->pProtocolStatus = pTSWd->pProtocolStatus;
TRC_ERR((TB, "Stored pTSWD %p, protocol status %p",
pTSWd, pTSWd->pProtocolStatus));
}
else {
// For shadow connects, the DD tells the shadow WD the width/height
// of the shadow target's desktop such that input from the shadow client
// can be scaled appropriately.
/********************************************************************/
/* See if the shadowing client supports dynamic resizing. First we */
/* need to extract the bitmap caps from the connect data */
/********************************************************************/
pBitmapCaps = (PTS_BITMAP_CAPABILITYSET) WDW_GetCapSet(
pTSWd,
TS_CAPSETTYPE_BITMAP,
&pIn->pVirtModuleData->combinedCapabilities,
pIn->pVirtModuleData->capsLength);
/********************************************************************/
/* If we found the bitmap caps, and the client does support dynamic */
/* resizing, then just go ahead and assign the size. */
/********************************************************************/
if (pBitmapCaps &&
(pBitmapCaps->desktopResizeFlag == TS_CAPSFLAG_SUPPORTED))
{
TRC_ALT((TB, "Client supports dynamic resizing"));
pTSWd->desktopHeight = pIn->desktopHeight;
pTSWd->desktopWidth = pIn->desktopWidth;
pSC->m_desktopHeight = pIn->desktopHeight;
pSC->m_desktopWidth = pIn->desktopWidth;
}
/********************************************************************/
/* If the client does NOT support dynamic resizing, then make sure */
/* that the shadower client is at least as big as the shadow target */
/* client - or the shadower client will trap */
/********************************************************************/
else if ((pTSWd->desktopHeight >= pIn->desktopHeight) &&
(pTSWd->desktopWidth >= pIn->desktopWidth)) {
pTSWd->desktopHeight = pIn->desktopHeight;
pTSWd->desktopWidth = pIn->desktopWidth;
pSC->m_desktopHeight = pIn->desktopHeight;
pSC->m_desktopWidth = pIn->desktopWidth;
}
else {
TRC_ERR((TB, "Rejecting attempt to shadow a higher res client"));
status = STATUS_UNSUCCESSFUL;
DC_QUIT;
}
#ifdef DC_HICOLOR
/********************************************************************/
/* Can the shadower cope with the target BPP?
/********************************************************************/
TRC_ALT((TB, "Shadower WD: %d bpp", pTSWd->desktopBpp ));
TRC_ALT((TB, "Target WD: %d bpp", pIn->desktopBpp ));
if (pTSWd->desktopBpp == pIn->desktopBpp) {
TRC_ALT((TB, "Color depths match - ok"));
pSC->m_desktopBpp = pIn->desktopBpp;
}
else {
TRC_ALT((TB, "Color depth mismatch"));
/****************************************************************/
/* Test the shadower's supported color depths */
/****************************************************************/
status = STATUS_SUCCESS;
switch (pIn->desktopBpp)
{
case 24:
{
if (pTSWd->supportedBpps & RNS_UD_24BPP_SUPPORT)
{
TRC_DBG((TB, "24bpp supported"));
break;
}
status = STATUS_UNSUCCESSFUL;
}
break;
case 16:
{
if (pTSWd->supportedBpps & RNS_UD_16BPP_SUPPORT)
{
TRC_DBG((TB, "16bpp supported"));
break;
}
status = STATUS_UNSUCCESSFUL;
}
break;
case 15:
{
if (pTSWd->supportedBpps & RNS_UD_15BPP_SUPPORT)
{
TRC_DBG((TB, "15bpp supported"));
break;
}
status = STATUS_UNSUCCESSFUL;
}
break;
case 8:
case 4:
{
TRC_DBG((TB, "8/4 bpp supported"));
}
break;
default:
{
TRC_ASSERT((FALSE), (TB, "Attempt to shadow unknown" \
" target color depth %d", pIn->desktopBpp));
}
break;
}
/****************************************************************/
/* Did they support it? */
/****************************************************************/
if (status == STATUS_UNSUCCESSFUL)
{
TRC_ERR((TB, "Rejecting shadow: unsupported color depth"));
DC_QUIT;
}
else
{
TRC_ALT((TB, "but client claims to cope..."));
pTSWd->desktopBpp = pIn->desktopBpp;
pSC->m_desktopBpp = pIn->desktopBpp;
}
}
#endif
}
/************************************************************************/
/* Share Core is no longer dead */
/************************************************************************/
// Make sure that Domain.StatusDead is consistent with TSWd.dead
pTSWd->dead = FALSE;
((PDomain)(pTSWd->hDomainKernel))->StatusDead = FALSE;
SM_Dead(pTSWd->pSmInfo, FALSE);
/************************************************************************/
/* Clear the create event before creating the Share */
/************************************************************************/
KeClearEvent(pTSWd->pCreateEvent);
/************************************************************************/
/* Now create a Share */
/************************************************************************/
#ifdef DC_HICOLOR
TRC_ALT((TB, "Creating share at %d bpp", pTSWd->desktopBpp ));
#endif
rc = pSC->SC_CreateShare();
if (rc) {
// Initialized OK - save the Shared Memory pointer.
TRC_NRM((TB, "Share create started"));
}
else {
TRC_ERR((TB, "Failed to create Share"));
status = STATUS_CONNECTION_DISCONNECTED;
DC_QUIT;
}
/************************************************************************/
/* Wait for Share creation to complete before returning to TShareDD */
/************************************************************************/
TRC_NRM((TB, "Wait for Share Core to create the Share"));
waitStatus = WDW_WaitForConnectionEvent(pTSWd,
pTSWd->pCreateEvent,
60000L);
/************************************************************************/
/* It is possible that the WD has been closed while we were waiting for */
/* the Share creation to complete. If this is the case, the Share */
/* class will have been deleted, so we can't continue. Return a */
/* failure to TShareDD. */
/************************************************************************/
if (pTSWd->dcShare == NULL)
{
TRC_ERR((TB, "Share Class ended while waiting for Share creation"));
status = STATUS_CONNECTION_DISCONNECTED;
DC_QUIT;
}
if (waitStatus == STATUS_TIMEOUT)
{
/********************************************************************/
/* The wait timed out - probably because the connection was */
/* disconnected before the Share was created. Tidy up the Share. */
/********************************************************************/
TRC_ERR((TB, "Timeout waiting for Share creation"));
pSC->m_pShm = (SHM_SHARED_MEMORY *)pIn->pShm;
pSC->SC_EndShare(FALSE);
pSC->m_pShm = NULL;
TRC_NRM((TB, "Share ended"));
status = STATUS_CONNECTION_DISCONNECTED;
// Can no longer accept input from RDPDD or PDMCS.
if (pTSWd->shadowState != SHADOW_CLIENT) {
// Make sure that Domain.StatusDead is consistent with TSWd.dead
pTSWd->dead = TRUE;
((PDomain)(pTSWd->hDomainKernel))->StatusDead = TRUE;
SM_Dead(pTSWd->pSmInfo, TRUE);
}
else {
// The client shadow stack is disconnected from its display driver
// during a shadow, but must still be able to send/receive data
// to/from the target shadow stack and shadow client.
TRC_ALT((TB, "In shadow: leaving SM active"));
}
DC_QUIT;
}
/************************************************************************/
/* Check whether the Share was created OK. If not, quit now. */
/************************************************************************/
if (!pTSWd->shareCreated)
{
TRC_ERR((TB, "Share creation failed"));
status = STATUS_UNSUCCESSFUL;
DC_QUIT;
}
// We have successfully received the initial share creation PDUs.
// Update the received info for the DD to use.
pSC->SBC_GetBitmapKeyDatabase(&pOut->bitmapKeyDatabaseSize,
&pOut->bitmapKeyDatabase);
// For shadow connects, we need to add in the remote party to negotiate
// capabilities correctly.
if ((pSdIoctl->IoControlCode == IOCTL_WDTS_DD_SHADOW_CONNECT) &&
((pTSWd->StackClass == Stack_Primary) ||
(pTSWd->StackClass == Stack_Console))) {
TRC_ALT((TB, "Negotiating shadow capabilities"));
status = pSC->SC_AddPartyToShare(
SC_SHADOW_PERSON_ID,
&pIn->pVirtModuleData->combinedCapabilities,
pIn->pVirtModuleData->capsLength);
if (status != STATUS_SUCCESS) {
TRC_ERR((TB, "Failed to negotiate shadow capabilities: %lx", status));
DC_QUIT;
}
}
/************************************************************************/
/* By now, the capabilities have been exchanged with the Client. Call */
/* the core to update SHM. */
/************************************************************************/
if ((pTSWd->StackClass == Stack_Primary) ||
(pTSWd->StackClass == Stack_Console)) {
TRC_NRM((TB, "Update SHM"));
pSC->m_pShm = (SHM_SHARED_MEMORY *)pIn->pShm;
pSC->DCS_UpdateShm();
pSC->m_pShm = NULL;
#ifdef DC_DEBUG
// Make sure trace config is updated in SHM.
pTSWd->trcShmNeedsUpdate = TRUE;
TRC_MaybeCopyConfig(pTSWd, &(((SHM_SHARED_MEMORY *)(pIn->pShm))->trc));
#endif
}
// All worked OK.
TRC_NRM((TB, "Share created"));
status = STATUS_SUCCESS;
DC_EXIT_POINT:
// record the individual connection status of each stack.
if (pTSWd->StackClass == Stack_Primary)
pOut->primaryStatus = status;
else
pOut->secondaryStatus |= status;
DC_END_FN();
return (status);
} /* WDWDDConnect */
/****************************************************************************/
/* Name: WDWDDDisconnect */
/* */
/* Purpose: Handle the disconnect IOCtl from the DD */
/* */
/* Params: IN pTSWd - pointer to WD struct */
/* INOUT PSD_IOCTL - pointer to received IOCtl */
/* IN bForce - used by shadow to force sending of a */
/* deactivate all PDU. */
/****************************************************************************/
NTSTATUS WDWDDDisconnect(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl, BOOLEAN bForce)
{
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
PTSHARE_DD_DISCONNECT_IN pIn =
(PTSHARE_DD_DISCONNECT_IN)pSdIoctl->InputBuffer;
DC_BEGIN_FN("WDWDDDisconnect");
TRC_ASSERT((pTSWd->dcShare != NULL),
(TB,"Got a disconnect with no share obj!"));
// Remove all references to WinStation resources.
WDWStopRITTimer(pTSWd);
pTSWd->ritTimer = NULL;
// Dump the bitmap cache key database to system memory. If this disconnect
// is in preparation for a reconnect, the database will allow us to
// preserve the bitmap cache state.
//
// If this is a disconnect in preparation for a shadow, then we can't save
// off the keys. For the shadow target, bShadowDisconnect will be set by
// the DD in DrvShadowConnect() processing. The shadow state for the shadow
// client will be other than NONE since we would have seen hotkey enable
// requests prior to the disconnect.
pSC->m_pShm = (SHM_SHARED_MEMORY *)pIn->pShm;
if (pSC->m_pShm != NULL) {
pSC->SBC_DumpBitmapKeyDatabase(!pIn->bShadowDisconnect &&
(pTSWd->shadowState == SHADOW_NONE));
}
// First of all, end the Share.
pSC->SC_EndShare(bForce);
TRC_NRM((TB, "Share ended"));
// Can no longer accept input from RDPDD or PDMCS.
if (pTSWd->shadowState != SHADOW_CLIENT) {
// Make sure that Domain.StatusDead is consistent with TSWd.dead
pTSWd->dead = TRUE;
((PDomain)(pTSWd->hDomainKernel))->StatusDead = TRUE;
SM_Dead(pTSWd->pSmInfo, TRUE);
}
else {
// The client shadow stack is disconnected from its display driver
// during a shadow, but must still be able to send/receive data
// to/from the target shadow stack and shadow client.
TRC_ALT((TB, "In shadow: leaving SM active"));
}
// Tell Share Class to disconnect.
pSC->DCS_Disconnect();
TRC_NRM((TB, "Share Class disconnected"));
pSC->m_pShm = NULL;
DC_END_FN();
return STATUS_SUCCESS;
} /* WDWDDDisconnect */
/****************************************************************************/
/* Name: WDWDDShadowConnect */
/* */
/* Purpose: Process an IOCTL_WDTS_DD_SHADOW_CONNECT from the DD */
/* */
/* Params: IN pTSWd - pointer to WD struct */
/* INOUT PSD_IOCTL - pointer to received IOCtl */
/* */
/* Operation: Initialize either the primary stack or the shadow stack for */
/* a shadowing session. */
/****************************************************************************/
NTSTATUS WDWDDShadowConnect(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
{
NTSTATUS status = STATUS_SUCCESS;
PTSHARE_DD_CONNECT_IN pIn = (PTSHARE_DD_CONNECT_IN)pSdIoctl->InputBuffer;
PTSHARE_DD_CONNECT_OUT pOut = (PTSHARE_DD_CONNECT_OUT)pSdIoctl->OutputBuffer;
PSHM_SHARED_MEMORY pShm = (PSHM_SHARED_MEMORY) pIn->pShm;
DC_BEGIN_FN("WDWDDShadowConnect");
switch (pTSWd->StackClass) {
case Stack_Primary:
case Stack_Console:
// Reconnect the primary stack
status = WDWDDConnect(pTSWd, pSdIoctl, TRUE);
if (NT_SUCCESS(status)) {
TRC_ALT((TB, "Primary target stack reconnected!"));
}
else {
TRC_ERR((TB, "Primary target stack could not reconnect: %lx)", status));
DC_QUIT;
}
// Set up the shadow data buffer. The primary stack will copy output to
// this location so all other shadow stacks can just squirt it.
#ifdef DC_HICOLOR
pTSWd->pShadowInfo = (PSHADOW_INFO)COM_Malloc(2 * WD_MAX_SHADOW_BUFFER);
#else
pTSWd->pShadowInfo = (PSHADOW_INFO)COM_Malloc(WD_MAX_SHADOW_BUFFER);
#endif
// Stash the shadow buffer so the DD can pass it to all shadow stacks
// via the Shm.
if (pTSWd->pShadowInfo != NULL) {
pTSWd->shadowState = SHADOW_TARGET;
memset(pTSWd->pShadowInfo, 0, sizeof(SHADOW_INFO));
pShm->pShadowInfo = pTSWd->pShadowInfo;
#ifdef DC_HICOLOR
TRC_ALT((TB, "Primary stack allocated shadow info: %p[%ld]",
pTSWd->pShadowInfo, 2 * WD_MAX_SHADOW_BUFFER));
#else
TRC_ALT((TB, "Primary stack allocated shadow info: %p[%ld]",
pTSWd->pShadowInfo, WD_MAX_SHADOW_BUFFER));
#endif
}
// Primary stack is really OK in this scenario, however it is fatal
// for the shadow stack
else {
pTSWd->pShadowInfo = NULL;
pShm->pShadowInfo = NULL;
pOut->secondaryStatus = STATUS_NO_MEMORY;
TRC_ERR((TB, "Could not allocate shadow data buffer"));
DC_QUIT;
}
break;
// Drive the shadow stack thru the normal connection phase
case Stack_Shadow:
status = WDWDDConnect(pTSWd, pSdIoctl, FALSE);
if (NT_SUCCESS(status)) {
TRC_ALT((TB, "Shadow stack connected!"));
}
else {
TRC_ERR((TB, "Shadow stack could not connect: %lx", status));
}
break;
default:
TRC_ERR((TB, "Unknown stack class: %ld", pTSWd->StackClass));
status = STATUS_INVALID_PARAMETER;
break;
}
DC_EXIT_POINT:
DC_END_FN();
return (status);
}
/****************************************************************************/
/* Name: WDWDDShadowDisconnect */
/* */
/* Purpose: Process an IOCTL_WDTS_DD_SHADOW_DISCONNECT from the DD */
/* */
/* Params: IN pTSWd - pointer to WD struct */
/* INOUT PSD_IOCTL - pointer to received IOCtl */
/* */
/* Operation: Stop shadowing on the primary stack. */
/****************************************************************************/
NTSTATUS WDWDDShadowDisconnect(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
{
NTSTATUS status = STATUS_SUCCESS;
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
PTSHARE_DD_DISCONNECT_IN pIn =
(PTSHARE_DD_DISCONNECT_IN)pSdIoctl->InputBuffer;
DC_BEGIN_FN("WDWDDShadowDisconnect");
switch (pTSWd->StackClass) {
// Deallocate the shadow buffer
case Stack_Primary:
case Stack_Console:
pTSWd->shadowState = SHADOW_NONE;
if (pTSWd->pShadowInfo != NULL)
COM_Free(pTSWd->pShadowInfo);
pTSWd->pShadowInfo = NULL;
if (pTSWd->bCompress == TRUE) {
unsigned MPPCCompressionLevel;
// Negotiate down to our highest level of compression support
// if we receive a larger number.
MPPCCompressionLevel =
(pTSWd->pInfoPkt->flags & RNS_INFO_COMPR_TYPE_MASK) >>
RNS_INFO_COMPR_TYPE_SHIFT;
if (MPPCCompressionLevel > PACKET_COMPR_TYPE_MAX)
MPPCCompressionLevel = PACKET_COMPR_TYPE_MAX;
// the compression history will be flushed
pTSWd->bFlushed = PACKET_FLUSHED;
// the compression will restart over
initsendcontext(pTSWd->pMPPCContext, MPPCCompressionLevel);
}
pSC->SC_RemovePartyFromShare(SC_SHADOW_PERSON_ID);
TRC_ALT((TB, "Update SHM after party left share"));
pSC->m_pShm = (SHM_SHARED_MEMORY *)pIn->pShm;
// Bump up the share ID to invalidate any old GRE cache entries for
// glyphs or brushes. This is necessary when RDP caches are destroyed
// since GRE may keep around the brush or font structure in its cache
pTSWd->shareId = InterlockedIncrement(&WD_ShareId);
pSC->m_pShm->shareId = pTSWd->shareId;
pSC->SC_Update();
pSC->DCS_UpdateShm();
pSC->m_pShm = NULL;
TRC_ALT((TB, "TSHARE_DD_SHADOW_DISCONNECT: Primary target stack"));
break;
// By the time this ioctl arrives TermDD should have already stopped echoing
// calls to the shadow stack.
case Stack_Shadow:
TRC_ERR((TB, "Shadow stack received an unexpected disconnect!"));
break;
default:
TRC_ERR((TB, "Unexpected stack class: %ld", pTSWd->StackClass));
break;
}
DC_END_FN();
return status;
}
/****************************************************************************/
/* Name: WDWUserLoggedOn */
/* */
/* Purpose: Notify the core that a user has logged on */
/****************************************************************************/
void WDWUserLoggedOn(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
{
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
DC_BEGIN_FN("WDWUserLoggedOn");
TRC_ASSERT((pSC != NULL),
(TB, "NULL Share Class"));
TRC_ASSERT((pSdIoctl->InputBufferLength == sizeof(LOGONINFO)),
(TB, "Bad LogonInfo"));
pSC->DCS_UserLoggedOn((PLOGONINFO)pSdIoctl->InputBuffer);
DC_END_FN();
} /* WDWUserLoggedOn */
/****************************************************************************/
/* Name: WDWKeyboardSetIndicators */
/* */
/* Purpose: Notify the core of new keyboard indicators */
/****************************************************************************/
void WDWKeyboardSetIndicators(PTSHARE_WD pTSWd)
{
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
DC_BEGIN_FN("WDWUserLoggedOn");
TRC_ASSERT((pSC != NULL),
(TB, "NULL Share Class"));
pSC->DCS_WDWKeyboardSetIndicators();
DC_END_FN();
} /* WDWKeyboardSetIndicators */
/****************************************************************************/
/* Name: WDWKeyboardSetImeStatus */
/* */
/* Purpose: Notify the core of new ime status */
/****************************************************************************/
void WDWKeyboardSetImeStatus(PTSHARE_WD pTSWd)
{
ShareClass *dcShare = (ShareClass *)pTSWd->dcShare;
DC_BEGIN_FN("WDWKeyboardSetImeStatus");
TRC_ASSERT((dcShare != NULL),
(TB, "NULL Share Class"));
dcShare->DCS_WDWKeyboardSetImeStatus();
DC_END_FN();
} /* WDWKeyboardSetImeStatus */
/****************************************************************************/
/* Name: WDWSendBeep */
/* */
/* Purpose: Send a beep PDU to the client */
/* */
/* Params: IN pTSWd - pointer to WD struct */
/* INOUT PSD_IOCTL - pointer to received IOCtl */
/* */
/* Operation: Check validity of IOCtl & call through to UP. */
/****************************************************************************/
NTSTATUS WDWSendBeep(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
DC_BEGIN_FN("WDWSendBeep");
if (pSdIoctl->InputBufferLength == sizeof(BEEP_SET_PARAMETERS) &&
pSdIoctl->InputBuffer != NULL) {
/************************************************************************/
/* Call into the Share Class to allocate and send the beep PDU */
/************************************************************************/
if (pSC != NULL && pTSWd->shareClassInit) {
if (pSC->UP_SendBeep(
((PBEEP_SET_PARAMETERS)pSdIoctl->InputBuffer)->Duration,
((PBEEP_SET_PARAMETERS)pSdIoctl->InputBuffer)->Frequency))
status = STATUS_SUCCESS;
}
pSdIoctl->BytesReturned = 0;
}
else {
TRC_ASSERT((TRUE), (TB,"Got Beep Ioctl but input buffer too small"));
}
DC_END_FN();
return status;
} /* WDWSendBeep */
/****************************************************************************/
/* Name: WDWGetModuleData */
/* */
/* Purpose: Processes an IOCTL_ICA_STACK_QUERY_MODULE_DATA from Termsrv. */
/* */
/* Params: IN pTSWd - pointer to WD struct */
/* INOUT PSD_IOCTL - pointer to received IOCtl */
/* */
/* Operation: return all the relevant conference creation info */
/****************************************************************************/
NTSTATUS WDWGetModuleData(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
{
NTSTATUS status = STATUS_SUCCESS;
ShareClass *dcShare = (ShareClass *)pTSWd->dcShare;
PTSHARE_MODULE_DATA pModuleData = (PTSHARE_MODULE_DATA)
pSdIoctl->OutputBuffer;
PBYTE pData;
ULONG ulDataSize;
PRNS_UD_CS_CORE pCoreData;
PRNS_UD_CS_SEC pSecurityData;
DC_BEGIN_FN("WDWGetModuleData");
ulDataSize = sizeof(TSHARE_MODULE_DATA) - sizeof(RNS_UD_HEADER) +
sizeof(RNS_UD_CS_CORE) +
sizeof(RNS_UD_CS_SEC);
// Make sure the output buffer is big enough!
pSdIoctl->BytesReturned = ulDataSize;
if (pSdIoctl->OutputBufferLength < ulDataSize) {
status = STATUS_BUFFER_TOO_SMALL;
DC_QUIT;
}
pModuleData->ulLength = ulDataSize;
pModuleData->ulVersion = 2;
pModuleData->userDataLen = sizeof(RNS_UD_CS_CORE) + sizeof(RNS_UD_CS_SEC);
pData = (PBYTE) &pModuleData->userData;
// Client to server core data
pCoreData = (PRNS_UD_CS_CORE) pData;
pCoreData->header.type = RNS_UD_CS_CORE_ID;
pCoreData->header.length = sizeof(RNS_UD_CS_CORE);
pCoreData->version = RNS_UD_VERSION;
pCoreData->desktopWidth = (UINT16)pTSWd->desktopWidth;
pCoreData->desktopHeight = (UINT16)pTSWd->desktopHeight;
// Re-munge the color depth
switch (pTSWd->desktopBpp) {
case 8:
pCoreData->colorDepth = RNS_UD_COLOR_8BPP;
break;
case 4:
pCoreData->colorDepth = RNS_UD_COLOR_4BPP;
break;
#ifdef DC_HICOLOR
case 15:
pCoreData->colorDepth = RNS_UD_COLOR_16BPP_555;
break;
#endif
case 16:
pCoreData->colorDepth = RNS_UD_COLOR_16BPP_565;
break;
case 24:
pCoreData->colorDepth = RNS_UD_COLOR_24BPP;
break;
default:
status = STATUS_UNSUCCESSFUL;
DC_QUIT;
}
pCoreData->postBeta2ColorDepth = pCoreData->colorDepth;
#ifdef DC_HICOLOR
/************************************************************************/
/* Copy across the current color depth */
/************************************************************************/
pCoreData->highColorDepth = (TSUINT16)pTSWd->desktopBpp;
pCoreData->supportedColorDepths = (TSUINT16)pTSWd->supportedBpps;
#endif
// Other useful stuff from user data
pCoreData->version = pTSWd->version;
pCoreData->SASSequence = pTSWd->sas;
pCoreData->keyboardLayout = pTSWd->kbdLayout;
pCoreData->clientBuild = pTSWd->clientBuild;
memcpy(pCoreData->clientName, pTSWd->clientName, sizeof(pTSWd->clientName));
//Whistler post Beta2 - shadow loop fix
memcpy( pCoreData->clientDigProductId, pTSWd->clientDigProductId, sizeof( pTSWd->clientDigProductId ));
// FE data
pCoreData->keyboardType = pTSWd->keyboardType;
pCoreData->keyboardSubType = pTSWd->keyboardSubType;
pCoreData->keyboardFunctionKey = pTSWd->keyboardFunctionKey;
memcpy(pCoreData->imeFileName, pTSWd->imeFileName, sizeof(pTSWd->imeFileName));
// Win2000 Post Beta3 fields added
pCoreData->clientProductId = pTSWd->clientProductId;
pCoreData->serialNumber = pTSWd->serialNumber;
// client to server security data
pSecurityData = (PRNS_UD_CS_SEC) (pCoreData + 1);
pSecurityData->header.type = RNS_UD_CS_SEC_ID;
pSecurityData->header.length = sizeof(RNS_UD_CS_SEC);
SM_GetEncryptionMethods(pTSWd->pSmInfo, pSecurityData );
// UGH! Now copy this data in a redundant form so we won't break
// compatibility with TS5 B3.
memcpy(&pModuleData->clientCoreData, pCoreData, sizeof(RNS_UD_CS_CORE_V0));
memcpy(&pModuleData->clientSecurityData, pSecurityData, sizeof(RNS_UD_CS_SEC_V0));
MCSGetDefaultDomain(pTSWd->pContext,
&pModuleData->DomParams,
&pModuleData->MaxSendSize,
&pModuleData->MaxX224DataSize,
&pModuleData->X224SourcePort);
pModuleData->shareId = pTSWd->shareId;
DC_EXIT_POINT:
DC_END_FN();
return status;
} /* WDWGetModuleData */
/****************************************************************************/
/* Name: WDW_GetCapSet */
/* */
/* Purpose: Extract the specific capabilities from a combined */
/* capabilities set */
/* */
/* Returns: pointer to caps or NULL if not found */
/* */
/* Params: IN pTSWd - pointer to WD struct */
/* IN CapSetType - type of capability set */
/* IN pCombinedCaps - pointer to combined capabilites */
/* IN lengthCaps - length of supplied caps */
/* */
/* Operation: find the specific caps in supplied capability set */
/****************************************************************************/
PTS_CAPABILITYHEADER WDW_GetCapSet(
PTSHARE_WD pTSWd,
UINT32 CapSetType,
PTS_COMBINED_CAPABILITIES pCaps,
UINT32 capsLength)
{
PTS_CAPABILITYHEADER pCapsHeader = NULL;
UINT32 capsOffset;
DC_BEGIN_FN("WDW_GetCapSet");
/************************************************************************/
/* Set up the pointer to the first capability set, and check that there */
/* is at least one set of caps! */
/************************************************************************/
pCapsHeader = (PTS_CAPABILITYHEADER)pCaps->data;
capsOffset = sizeof(TS_COMBINED_CAPABILITIES) - 1;
if (capsOffset >= capsLength)
{
TRC_NRM((TB, "No Caps found"));
DC_QUIT;
}
/************************************************************************/
/* Now loop through all the caps, looking for the specified capabilities*/
/************************************************************************/
while (pCapsHeader->capabilitySetType != CapSetType)
{
/****************************************************************/
/* Add the length of this capability to the offset, to keep */
/* track of how much of the combined caps we have processed. */
/****************************************************************/
capsOffset += pCapsHeader->lengthCapability;
if (capsOffset >= capsLength)
{
TRC_NRM((TB, "Bitmap Caps not found"));
pCapsHeader = NULL;
break;
}
/****************************************************************/
/* Add the length of this capability to the header pointer, so */
/* it points to the next capability set. */
/****************************************************************/
pCapsHeader = (PTS_CAPABILITYHEADER)
(((PBYTE)pCapsHeader) + pCapsHeader->lengthCapability);
TRC_NRM((TB, "Next set: %u", pCapsHeader->capabilitySetType));
}
/************************************************************************/
/* pCapsHeader is either NULL or a pointer to the desired caps - which */
/* is what we want to return */
/************************************************************************/
DC_EXIT_POINT:
DC_END_FN();
return(pCapsHeader);
} /* WDW_GetCapSet */
/****************************************************************************/
/* Name: WDWGetDefaultCoreParams */
/* */
/* Purpose: Defaults the core params used by the shadow stacks */
/* */
/* Params: OUT pClientCoreData - WD core data */
/* */
/* Operation: Default the core params used by the shadow stacks */
/****************************************************************************/
NTSTATUS WDWGetDefaultCoreParams(PRNS_UD_CS_CORE pClientCoreData)
{
DC_BEGIN_FN("WDWGetDefaultCoreParams");
// Client to server core data
pClientCoreData->header.type = RNS_UD_CS_CORE_ID;
pClientCoreData->header.length = sizeof(RNS_UD_CS_CORE);
// Desktop parameters
pClientCoreData->desktopHeight = 640;
pClientCoreData->desktopWidth = 480;
pClientCoreData->colorDepth = RNS_UD_COLOR_8BPP;
pClientCoreData->postBeta2ColorDepth = RNS_UD_COLOR_8BPP;
#ifdef DC_HICOLOR
pClientCoreData->highColorDepth = 15;
pClientCoreData->supportedColorDepths = RNS_UD_24BPP_SUPPORT ||
RNS_UD_16BPP_SUPPORT ||
RNS_UD_15BPP_SUPPORT;
#endif
// Other useful stuff from user data
pClientCoreData->version = RNS_TERMSRV_40_UD_VERSION;
pClientCoreData->SASSequence = RNS_UD_SAS_NONE;
pClientCoreData->keyboardLayout = 0;
pClientCoreData->clientBuild = VER_PRODUCTBUILD;
memcpy(pClientCoreData->clientName, L"Passthru Stack", sizeof(L"Passthru Stack"));
//Whistler post Beta2 - shadow loop fix
pClientCoreData->clientDigProductId[0] = 0;
// FE data
pClientCoreData->keyboardType = 0;
pClientCoreData->keyboardSubType = 0;
pClientCoreData->keyboardFunctionKey = 0;
memset(pClientCoreData->imeFileName, 0, sizeof(pClientCoreData->imeFileName));
return STATUS_SUCCESS;
}
/****************************************************************************/
// Name: WDWSetConfigData
//
// Purpose: Sets the stack configuration/Policy settings from winstation
//
// Params: IN pConfigData
/****************************************************************************/
NTSTATUS WDWSetConfigData(PTSHARE_WD pTSWd, PICA_STACK_CONFIG_DATA pConfigData)
{
PSM_HANDLE_DATA pRealSMHandle = (PSM_HANDLE_DATA)pTSWd->pSmInfo;
DC_BEGIN_FN("WDWSetConfigData");
if (pConfigData->colorDepth == TS_24BPP_SUPPORT) {
pTSWd->maxServerBpp = 24;
}
else if (pConfigData->colorDepth == TS_16BPP_SUPPORT) {
pTSWd->maxServerBpp = 16;
}
else if (pConfigData->colorDepth == TS_15BPP_SUPPORT) {
pTSWd->maxServerBpp = 15;
}
else {
pTSWd->maxServerBpp = 8;
}
TRC_DBG((TB, "Max Color Depth support: %d", pTSWd->maxServerBpp));
pRealSMHandle->encryptionLevel = pConfigData->encryptionLevel;
pRealSMHandle->encryptAfterLogon =
(pConfigData->fDisableEncryption == 0) ? TRUE : FALSE;
TRC_DBG((TB, "Encryption after logon: %d", pRealSMHandle->encryptAfterLogon));
TRC_DBG((TB, "Encryption level: %d", pRealSMHandle->encryptionLevel));
pTSWd->fPolicyDisablesArc = pConfigData->fDisableAutoReconnect;
TRC_DBG((TB, "AutoReconnect disabled: %d", pTSWd->fPolicyDisablesArc));
DC_END_FN();
return STATUS_SUCCESS;
}
/****************************************************************************/
/* Name: WDWSetErrorInfo */
/* */
/* Purpose: Send error info to the client */
/****************************************************************************/
NTSTATUS WDWSetErrorInfo(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
{
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
DC_BEGIN_FN("WDWSetErrorInfo");
TRC_ASSERT((pSC != NULL),
(TB, "NULL Share Class"));
TRC_ASSERT((pSdIoctl->InputBufferLength == sizeof(TSUINT32)),
(TB, "Bad ErrorInfo"));
if(pSC)
{
if(pTSWd->bSupportErrorInfoPDU)
{
pSC->DCS_SendErrorInfo(*((PTSUINT32)pSdIoctl->InputBuffer));
}
else
{
TRC_NRM((TB,"SetErrorInfo called but client doesn't support error PDU"));
}
}
DC_END_FN();
return STATUS_SUCCESS;
} /* WDWSetErrorInfo */
/****************************************************************************/
/* Name: WDWSendArcStatus
/*
/* Purpose: Send autoreconnect status update to client
/****************************************************************************/
NTSTATUS WDWSendArcStatus(PTSHARE_WD pTSWd, PSD_IOCTL pSdIoctl)
{
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
DC_BEGIN_FN("WDWSendArcStatus");
TRC_ASSERT((pSC != NULL),
(TB, "NULL Share Class"));
TRC_ASSERT((pSdIoctl->InputBufferLength == sizeof(TSUINT32)),
(TB, "Bad ErrorInfo"));
if(pSC)
{
if(pSC->SC_IsAutoReconnectEnabled())
{
pSC->DCS_SendAutoReconnectStatus(*((PTSUINT32)pSdIoctl->InputBuffer));
}
else
{
TRC_NRM((TB,"SetErrorInfo called but client doesn't ARC error PDU"));
}
}
DC_END_FN();
return STATUS_SUCCESS;
} /* WDWSendArcStatus */
/****************************************************************************/
/* Name: WDW_LogAndDisconnect */
/* */
/* Purpose: Log an event and disconnect the Client */
/* */
/* Returns: none */
/* */
/* Params: pTSWd */
/* errDetailCode - error code to log */
/* pDetailData - additional data */
/* detailDataLen - length of additional data */
/* */
/****************************************************************************/
void RDPCALL WDW_LogAndDisconnect(
PTSHARE_WD pTSWd,
BOOL fSendErrorToClient,
unsigned errDetailCode,
PBYTE pDetailData,
unsigned detailDataLen)
{
DC_BEGIN_FN("WDW_LogAndDisconnect");
//Report the error code back to the client
ShareClass *pSC = (ShareClass *)pTSWd->dcShare;
if(pSC)
{
if(fSendErrorToClient && pTSWd->bSupportErrorInfoPDU)
{
pSC->DCS_SendErrorInfo( (errDetailCode + TS_ERRINFO_PROTOCOL_BASE));
}
else
{
if( fSendErrorToClient )
{
TRC_NRM((TB,"SetErrorInfo called but client doesn't support error PDU"));
}
else
{
TRC_NRM((TB,"SetErrorInfo called but asked not to send error code to client"));
}
}
}
if( !pTSWd->dead )
MCSProtocolErrorEvent(pTSWd->pContext, pTSWd->pProtocolStatus,
errDetailCode, pDetailData, detailDataLen);
DC_END_FN();
}
} /* extern "C" */