|
|
/****************************************************************************/ // adcsapi.cpp
//
// RDP top-level component API functions.
//
// Copyright (C) Microsoft Corp., PictureTel 1992-1997
// Copyright (C) 1997-2000 Microsoft Corporation
/****************************************************************************/
#include <precomp.h>
#pragma hdrstop
#define TRC_FILE "adcsapi"
#include <randlib.h>
#include <as_conf.hpp>
#include <asmapi.h>
/****************************************************************************/ /* API FUNCTION: DCS_Init */ /* */ /* Initializes DCS. */ /* */ /* PARAMETERS: */ /* pTSWd - TShare WD handle */ /* pSMHandle - SM handle */ /* */ /* RETURNS: */ /* TRUE if DCS successfully initialized, FALSE otherwise. */ /****************************************************************************/ BOOL RDPCALL SHCLASS DCS_Init(PTSHARE_WD pTSWd, PVOID pSMHandle) { BOOL rc = FALSE; unsigned retCode; TS_GENERAL_CAPABILITYSET GeneralCaps; long arcUpdateIntervalSeconds; UINT32 drawGdipSupportLevel; NTSTATUS Status;
DC_BEGIN_FN("DCS_Init");
TRC_ALT((TB, "Initializing Core!"));
#define DC_INIT_DATA
#include <adcsdata.c>
#undef DC_INIT_DATA
dcsInitialized = TRUE;
// Read the registry key for the draw gdiplus support control
COM_OpenRegistry(pTSWd, WINSTATION_INI_SECTION_NAME); Status = COMReadEntry(pTSWd, L"DrawGdiplusSupportLevel", (PVOID)&drawGdipSupportLevel, sizeof(INT32), REG_DWORD); if (Status != STATUS_SUCCESS) { /********************************************************************/ /* We failed to read the value - copy in the default */ /********************************************************************/ TRC_ERR((TB, "Failed to read int32. Using default.")); drawGdipSupportLevel = TS_DRAW_GDIPLUS_DEFAULT; } else { TRC_NRM((TB, "Read from registry, gdipSupportLevel is %d", drawGdipSupportLevel)); } COM_CloseRegistry(pTSWd);
/************************************************************************/ /* Open registry here. Apart from SM_Init, all registry reads should */ /* be done from this function or its children. We close the key at the */ /* end of this function. */ /************************************************************************/ COM_OpenRegistry(pTSWd, DCS_INI_SECTION_NAME);
/************************************************************************/ /* Initialize individual modules. */ /************************************************************************/ TRC_DBG((TB, "Initializing components..."));
// we can't do any registry reading on this csrss thread,
// it'll cause deadlock in the system
arcUpdateIntervalSeconds = DCS_ARC_UPDATE_INTERVAL_DFLT; //
// Units specified are in seconds, convert to 100ns count
//
dcsMinArcUpdateInterval.QuadPart = (LONGLONG)DCS_TIME_ONE_SECOND * (ULONGLONG)arcUpdateIntervalSeconds; TRC_NRM((TB,"Set ARC update interval to %d seconds", arcUpdateIntervalSeconds));
/************************************************************************/ // Share Controller - must go first
/************************************************************************/ if (SC_Init(pSMHandle)) { // Capabilities Coordinator. Must be before all components which
// register capabilities structures.
CPC_Init();
// Register the SC's capabilities. This is required because SC is
// initialized before CPC, so cannot register its capabilities in
// SC_Init().
SC_SetCapabilities(); } else { TRC_ERR((TB, "SC Initialization failed")); DC_QUIT; }
/************************************************************************/ /* Register the general capabilities structure. */ /************************************************************************/ GeneralCaps.capabilitySetType = TS_CAPSETTYPE_GENERAL; GeneralCaps.osMajorType = TS_OSMAJORTYPE_WINDOWS; GeneralCaps.osMinorType = TS_OSMINORTYPE_WINDOWS_NT; GeneralCaps.protocolVersion = TS_CAPS_PROTOCOLVERSION;
/************************************************************************/ /* Mark the old DOS 6 compression field as unsupported. */ /************************************************************************/ GeneralCaps.pad2octetsA = 0; GeneralCaps.generalCompressionTypes = 0;
// Server supports no BC header and fast-path output, returning long credentials
// and sending the autoreconnect cookie
// Also supports receiving safer encrypted data from the client (better salted
// checksum)
//
GeneralCaps.extraFlags = TS_EXTRA_NO_BITMAP_COMPRESSION_HDR | TS_FASTPATH_OUTPUT_SUPPORTED | TS_LONG_CREDENTIALS_SUPPORTED | TS_AUTORECONNECT_COOKIE_SUPPORTED | TS_ENC_SECURE_CHECKSUM;
/************************************************************************/ /* We don't support remote machines changing their capabilities during */ /* a call */ /************************************************************************/ GeneralCaps.updateCapabilityFlag = TS_CAPSFLAG_UNSUPPORTED;
/************************************************************************/ /* We don't support unshare requests from remote parties */ /************************************************************************/ GeneralCaps.remoteUnshareFlag = TS_CAPSFLAG_UNSUPPORTED;
/************************************************************************/ /* Now do the extension caps - these don't fit in the level 1 caps. */ /************************************************************************/ GeneralCaps.generalCompressionLevel = 0;
/************************************************************************/ /* We can receive a TS_REFRESH_RECT_PDU */ /************************************************************************/ GeneralCaps.refreshRectSupport = TS_CAPSFLAG_SUPPORTED;
/************************************************************************/ /* We can receive a TS_SUPPRESS_OUTPUT_PDU */ /************************************************************************/ GeneralCaps.suppressOutputSupport = TS_CAPSFLAG_SUPPORTED;
CPC_RegisterCapabilities((PTS_CAPABILITYHEADER)&GeneralCaps, sizeof(TS_GENERAL_CAPABILITYSET));
//
// Register virtual channel capabilities
//
TS_VIRTUALCHANNEL_CAPABILITYSET VcCaps; VcCaps.capabilitySetType = TS_CAPSETTYPE_VIRTUALCHANNEL; VcCaps.lengthCapability = sizeof(TS_VIRTUALCHANNEL_CAPABILITYSET); //Indicate support for 8K VC compression (from client->server)
//I.e server understands compressed channels
VcCaps.vccaps1 = TS_VCCAPS_COMPRESSION_8K; CPC_RegisterCapabilities((PTS_CAPABILITYHEADER)&VcCaps, sizeof(TS_VIRTUALCHANNEL_CAPABILITYSET));
TS_DRAW_GDIPLUS_CAPABILITYSET DrawGdipCaps; DrawGdipCaps.capabilitySetType = TS_CAPSETTYPE_DRAWGDIPLUS; DrawGdipCaps.lengthCapability = sizeof(TS_DRAW_GDIPLUS_CAPABILITYSET); DrawGdipCaps.drawGdiplusSupportLevel = drawGdipSupportLevel; DrawGdipCaps.drawGdiplusCacheLevel = TS_DRAW_GDIPLUS_CACHE_LEVEL_ONE; CPC_RegisterCapabilities((PTS_CAPABILITYHEADER)&DrawGdipCaps, sizeof(TS_DRAW_GDIPLUS_CAPABILITYSET));
USR_Init(); CA_Init(); PM_Init(); SBC_Init(); BC_Init(); CM_Init(); IM_Init(); SSI_Init(); SCH_Init();
TRC_NRM((TB, "** All successfully initialized **"));
rc = TRUE;
DC_EXIT_POINT: /************************************************************************/ /* Close the registry key that we opened earlier. */ /************************************************************************/ COM_CloseRegistry(pTSWd);
DC_END_FN(); return rc; }
/****************************************************************************/ /* API FUNCTION: DCS_Term */ /* */ /* Terminates DCS. */ /****************************************************************************/ void RDPCALL SHCLASS DCS_Term() { DC_BEGIN_FN("DCS_Term");
if (!dcsInitialized) { TRC_ERR((TB,"DCS_Term() called when we have not been initialized")); }
SBC_Term(); PM_Term(); CA_Term(); BC_Term(); CM_Term(); IM_Term(); SSI_Term(); SCH_Term(); CPC_Term(); USR_Term(); SC_Term();
dcsInitialized = FALSE; TRC_NRM((TB, "BYE!"));
DC_END_FN(); }
/****************************************************************************/ /* API FUNCTION: DCS_TimeToDoStuff */ /* */ /* This function is called to send updates etc in the correct order. */ /* */ /* PARAMETERS: IN - pOutputIn - input from TShareDD */ /* OUT - pSchCurrentMode - current Scheduler mode */ /* */ /* RETURNS: Millisecs to set the timer for (-1 means infinite). */ /****************************************************************************/ /* Scheduling is the responsibility of the WDW, DD and SCH components. */ /* These ensure that DCS_TimeToDoStuff() gets called. The Scheduler is in */ /* one of three states: asleep, normal or turbo. When it is asleep, this */ /* function is not called. When it is in normal mode, this function is */ /* called at least once, but the scheduler is a lazy guy, so will fall */ /* asleep again unless you keep prodding him. In turbo mode this function */ /* is called repeatedly and rapidly, but only for a relatively short time, */ /* after which the scheduler falls back into normal mode, and from there */ /* falls asleep. */ /* */ /* Hence when a component realises it has some processing to do later, */ /* which is called from DCS_TimeToDoStuff(), it calls */ /* SCH_ContinueScheduling(SCH_MODE_NORMAL) which guarantees that this */ /* function will be called at least one more time. If the component wants */ /* DCS_TimeToDoStuff() to be called again, it must make another call to */ /* SCH_ContinueScheduling(), which prods the Scheduler again. */ /* */ /* The objective is to only keep the scheduler awake when it is really */ /* necessary. */ /****************************************************************************/ NTSTATUS RDPCALL SHCLASS DCS_TimeToDoStuff(PTSHARE_DD_OUTPUT_IN pOutputIn, PUINT32 pSchCurrentMode, PINT32 pNextTimer) { INT32 timeToSet; ULARGE_INTEGER sysTime; UINT32 sysTimeLowPart; NTSTATUS status = STATUS_SUCCESS;
DC_BEGIN_FN("DCS_TimeToDoStuff");
#ifdef DC_DEBUG
/************************************************************************/ /* Update trace config in shared memory. */ /************************************************************************/ TRC_MaybeCopyConfig(m_pTSWd, &(m_pShm->trc)); #endif
// Determine if we should do anything based on:
// 1. SCH determining that this is the time to do something.
// 2. We are in a share.
if (SCH_ShouldWeDoStuff(pOutputIn->forceSend) && SC_InShare()) { PDU_PACKAGE_INFO pkgInfo = {0};
// We check for the need to send a cursor-moved packet, by comparing
// the current mouse position to the last known position at the last
// mouse packet, only a few times a second, to reduce the traffic for
// shadow clients.
KeQuerySystemTime((PLARGE_INTEGER)&sysTime); sysTimeLowPart = sysTime.LowPart; if ((sysTimeLowPart - dcsLastMiscTime) > DCS_MISC_PERIOD) { dcsLastMiscTime = sysTimeLowPart; IM_CheckUpdateCursor(&pkgInfo, sysTimeLowPart); }
//
// Check if the ARC cookie needs to be updated
//
if (scEnablePeriodicArcUpdate && scUseAutoReconnect && ((sysTime.QuadPart - dcsLastArcUpdateTime.QuadPart) > dcsMinArcUpdateInterval.QuadPart)) {
dcsLastArcUpdateTime = sysTime; DCS_UpdateAutoReconnectCookie();
}
// Try to send updates now.
TRC_DBG((TB, "Send updates"));
//
// *** Keep the code path but still return status code ***
//
status = UP_SendUpdates(pOutputIn->pFrameBuf, pOutputIn->frameBufWidth, &pkgInfo);
// Call the cursor manager to decide if a new cursor needs to be
// sent to the remote system.
CM_Periodic(&pkgInfo);
// Flush any remaining data in the package.
SC_FlushPackage(&pkgInfo); }
/************************************************************************/ /* Check whether we have any pending callbacks. */ /************************************************************************/ if (dcsCallbackTimerPending) DCS_UpdateShm();
/************************************************************************/ /* Find out the timer period to set */ /************************************************************************/ *pNextTimer = SCH_EndOfDoingStuff(pSchCurrentMode);
DC_END_FN(); return status; }
/****************************************************************************/ /* DCS_DiscardAllOutput */ /* */ /* This routine will discard accumulated orders, screen data, and any */ /* pending shadow data. It is currently only called when the WD is dead */ /* to prevent the DD from looping during shadow termination, or when a */ /* disconnect or terminate is occuring. */ /****************************************************************************/ void RDPCALL SHCLASS DCS_DiscardAllOutput() { RECTL sdaRect[BA_MAX_ACCUMULATED_RECTS]; unsigned cRects;
// Blow the order heap, screen data, and clear any shadow data.
OA_ResetOrderList(); BA_GetBounds(sdaRect, &cRects);
if (m_pTSWd->pShadowInfo != NULL) { m_pTSWd->pShadowInfo->messageSize = 0; #ifdef DC_HICOLOR
m_pTSWd->pShadowInfo->messageSizeEx = 0; #endif
} }
/****************************************************************************/ /* Name: DCS_ReceivedShurdownRequestPDU */ /* */ /* Purpose: Handles ShutdownRequestPDU. */ /* */ /* Params: personID: originator of the PDU */ /* pPDU: the PDU */ /* */ /* Operation: See embedded comments for each PDU type */ /* */ /* Note that since a ShutdownRequestPDU is not really directed at a */ /* particular component, DCS_ReceivedPacket is intended as a generic */ /* received packet handler, and it therefore takes a generic 2nd parameter */ /****************************************************************************/ void RDPCALL SHCLASS DCS_ReceivedShutdownRequestPDU( PTS_SHAREDATAHEADER pDataPDU, unsigned DataLength, NETPERSONID personID) { UINT32 packetSize; PTS_SHUTDOWN_DENIED_PDU pResponsePDU;
DC_BEGIN_FN("DCS_ReceivedPacket");
if (dcsUserLoggedOn) { TRC_NRM((TB, "User logged on - deny shutdown request")); packetSize = sizeof(TS_SHUTDOWN_DENIED_PDU);
if (STATUS_SUCCESS == SC_AllocBuffer((PPVOID)&pResponsePDU, packetSize)) { pResponsePDU->shareDataHeader.pduType2 = TS_PDUTYPE2_SHUTDOWN_DENIED;
// The way in which this packet is handled in a multi-party
// call is not yet clear. We could send a directed or
// broadcast reponse to the client(s). I've chosen
// broadcast.
SC_SendData((PTS_SHAREDATAHEADER)pResponsePDU, packetSize, packetSize, PROT_PRIO_MISC, 0); } else { TRC_ALT((TB,"Failed to allocate packet for " "TS_SHUTDOWN_DENIED_PDU")); } } else { TRC_NRM((TB, "User not logged on - disconnect")); WDW_Disconnect(m_pTSWd); }
DC_END_FN(); } /* DCS_ReceivedPacket */
/****************************************************************************
DCS_UpdateAutoReconnectCookie Updates the autoreconnection cookie and sends it to the client *****************************************************************************/ BOOL RDPCALL SHCLASS DCS_UpdateAutoReconnectCookie() { BOOL fRet = FALSE; ARC_SC_PRIVATE_PACKET arcSCPkt;
DC_BEGIN_FN("DCS_UpdateAutoReconnectCookie");
arcSCPkt.cbLen = sizeof(ARC_SC_PRIVATE_PACKET); arcSCPkt.LogonId = m_pTSWd->arcReconnectSessionID; arcSCPkt.Version = 1;
if (NewGenRandom(NULL, NULL, arcSCPkt.ArcRandomBits, sizeof(arcSCPkt.ArcRandomBits))) {
#ifdef ARC_INSTRUMENT_RDPWD
LPDWORD pdwArcRandom = (LPDWORD)arcSCPkt.ArcRandomBits; KdPrint(("ARC-RDPWD:Sending arc for SID:%d - random: 0x%x,0x%x,0x%x,0x%x\n", arcSCPkt.LogonId, pdwArcRandom[0],pdwArcRandom[1],pdwArcRandom[2],pdwArcRandom[3])); #endif
//
// Try to send the updated packet and if it succeeds
//
if (DCS_SendAutoReconnectCookie(&arcSCPkt)) {
//
// Update the locally stored ARC cookie even though
// all we know is that we attempted to send it
// i.e. if the client link drops before it recvs the
// cookie then it won't be able to ARC.
//
memcpy(m_pTSWd->arcCookie, arcSCPkt.ArcRandomBits, ARC_SC_SECURITY_TOKEN_LEN); m_pTSWd->arcTokenValid = TRUE;
#ifdef ARC_INSTRUMENT_RDPWD
KdPrint(("ARC-RDPWD:ACTUALLY SENT ARC for SID:%d\n", arcSCPkt.LogonId)); #endif
fRet = TRUE; } else { #ifdef ARC_INSTRUMENT_RDPWD
KdPrint(("ARC-RDPWD:Failed to send new ARC for SID:%d\n", arcSCPkt.LogonId)); #endif
} }
DC_END_FN(); return fRet; }
BOOL RDPCALL SHCLASS DCS_FlushAutoReconnectCookie() { memset(m_pTSWd->arcCookie, 0, ARC_SC_SECURITY_TOKEN_LEN); m_pTSWd->arcTokenValid = FALSE; return TRUE; }
/****************************************************************************
DCS_SendAutoReconnectCookie Sends a autoreconnect cookie tot the client *****************************************************************************/ BOOL RDPCALL SHCLASS DCS_SendAutoReconnectCookie( PARC_SC_PRIVATE_PACKET pArcSCPkt) { BOOL fRet = FALSE; PTS_SAVE_SESSION_INFO_PDU pInfoPDU = NULL; PTS_LOGON_INFO_EXTENDED pLogonInfoExPkt = NULL; UINT32 cbLogonInfoExLen = sizeof(TS_SAVE_SESSION_INFO_PDU) + sizeof(ARC_SC_PRIVATE_PACKET) + sizeof(TSUINT32); TSUINT32 cbAutoReconnectInfoLen = sizeof(ARC_SC_PRIVATE_PACKET); TSUINT32 cbWrittenLen = 0;
DC_BEGIN_FN("DCS_SendAutoReconnectCookie");
//
//Send down the autoreconnect cookie
//
if (scUseAutoReconnect) { if ( STATUS_SUCCESS == SC_AllocBuffer((PPVOID)&pInfoPDU, cbLogonInfoExLen)) {
// Zero out the structure and set basic header info.
memset(pInfoPDU, 0, cbLogonInfoExLen); pInfoPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_SAVE_SESSION_INFO; pInfoPDU->data.InfoType = TS_INFOTYPE_LOGON_EXTENDED_INFO;
// Now fill up the rest of the packet
pLogonInfoExPkt = &pInfoPDU->data.Info.LogonInfoEx; pLogonInfoExPkt->Length = sizeof(TS_LOGON_INFO_EXTENDED) + sizeof(ARC_SC_PRIVATE_PACKET) + sizeof(TSUINT32);
//
// For now the only info we pass down is
// the autoreconnect cookie
//
pLogonInfoExPkt->Flags = LOGON_EX_AUTORECONNECTCOOKIE;
//Copy in the fields
//Autoreconnect field length
PBYTE pBuf = (PBYTE)(pLogonInfoExPkt+1); memcpy(pBuf, &cbAutoReconnectInfoLen, sizeof(TSUINT32)); pBuf += sizeof(TSUINT32); cbWrittenLen += sizeof(TSUINT32); //Autoreconnect cookie
memcpy(pBuf, pArcSCPkt, cbAutoReconnectInfoLen); pBuf += cbAutoReconnectInfoLen; cbWrittenLen += cbAutoReconnectInfoLen;
TRC_ASSERT(cbWrittenLen + sizeof(TS_LOGON_INFO_EXTENDED) <= pLogonInfoExPkt->Length, (TB,"Wrote to much data to packet"));
fRet = SC_SendData((PTS_SHAREDATAHEADER)pInfoPDU, cbLogonInfoExLen, cbLogonInfoExLen, PROT_PRIO_UPDATES, 0); } else { TRC_ALT((TB, "Failed to alloc pkt for " "PTS_SAVE_SESSION_INFO_PDU")); } }
DC_END_FN(); return fRet; }
/****************************************************************************/ /* Name: DCS_UserLoggedOn */ /* */ /* Purpose: Notify that a user has logged on */ /****************************************************************************/ void RDPCALL SHCLASS DCS_UserLoggedOn(PLOGONINFO pLogonInfo) { PTS_SAVE_SESSION_INFO_PDU pInfoPDU;
DC_BEGIN_FN("DCS_UserLoggedOn");
// This can get called before we're initialised in the console remoting
// case. Since in that case the class data hasn't been initialized, we
// can't use dcsInitialized to check whether we're inited or not. We
//must use the non-class variable TSWd->shareClassInit.
if (m_pTSWd->shareClassInit) {
// Note that a user has successfully logged on
dcsUserLoggedOn = TRUE; m_pTSWd->sessionId = pLogonInfo->SessionId;
// If a different domain/username has been selected for a non-
// autologon session, then send the new values back to the client to
// be cached for future use
if (!(m_pTSWd->pInfoPkt->flags & RNS_INFO_AUTOLOGON) && (m_pTSWd->pInfoPkt->flags & RNS_INFO_LOGONNOTIFY || (wcscmp((const PWCHAR)(pLogonInfo->Domain), (const PWCHAR)(m_pTSWd->pInfoPkt->Domain)) || wcscmp((const PWCHAR)(pLogonInfo->UserName), (const PWCHAR)(m_pTSWd->pInfoPkt->UserName))))) { // Get a buffer.
// The buffer size and how it is going to be filled depends on the client's
// capability to accept Long Credentials on return. Pre-Whistler Clients dont
// support Long Credentials
if (scUseLongCredentials == FALSE) {
// Pre Whistler Client - has no capability for accepting long credentials
if ( STATUS_SUCCESS == SC_AllocBuffer((PPVOID)&pInfoPDU, sizeof(TS_SAVE_SESSION_INFO_PDU)) ) {
// Zero out the structure and set basic header info.
memset(pInfoPDU, 0, sizeof(TS_SAVE_SESSION_INFO_PDU)); pInfoPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_SAVE_SESSION_INFO; // Now fill up the rest of the packet
pInfoPDU->data.InfoType = TS_INFOTYPE_LOGON; // Fill in the Domain info.
pInfoPDU->data.Info.LogonInfo.cbDomain = (wcslen((const PWCHAR)(pLogonInfo->Domain)) + 1) * sizeof(WCHAR); memcpy(pInfoPDU->data.Info.LogonInfo.Domain, pLogonInfo->Domain, pInfoPDU->data.Info.LogonInfo.cbDomain); // Fill in the UserName info.
// In case the fDontDisplayLastUserName is set we should
// not send back the username for caching.
pInfoPDU->data.Info.LogonInfo.cbUserName = (m_pTSWd->fDontDisplayLastUserName) ? 0 : (wcslen((const PWCHAR)(pLogonInfo->UserName)) + 1) * sizeof(WCHAR);
memcpy(pInfoPDU->data.Info.LogonInfo.UserName, pLogonInfo->UserName, pInfoPDU->data.Info.LogonInfo.cbUserName);
// Fill in the Session Id info.
pInfoPDU->data.Info.LogonInfo.SessionId = pLogonInfo->SessionId;
// Send it
SC_SendData((PTS_SHAREDATAHEADER)pInfoPDU, sizeof(TS_SAVE_SESSION_INFO_PDU), sizeof(TS_SAVE_SESSION_INFO_PDU), PROT_PRIO_UPDATES, 0);
} else { TRC_ALT((TB, "Failed to alloc pkt for " "PTS_SAVE_SESSION_INFO_PDU")); }
} else { // Client CAN accept long Credentials
TSUINT32 DomainLen, UserNameLen, DataLen ;
DomainLen = (wcslen((const PWCHAR)(pLogonInfo->Domain)) + 1) * sizeof(WCHAR); // In case fDontDisplayLastUserName is set we won't send the user name
UserNameLen = (m_pTSWd->fDontDisplayLastUserName) ? 0 : (wcslen((const PWCHAR)(pLogonInfo->UserName)) + 1) * sizeof(WCHAR); // Compute the length of the data u r sending
DataLen = sizeof(TS_SAVE_SESSION_INFO_PDU) + DomainLen + UserNameLen ;
TRC_DBG((TB, "DCS_UserLoggedOn : DomainLength allocated = %ul", DomainLen)); TRC_DBG((TB, "DCS_UserLoggedOn : UserNameLength allocated = %ul", UserNameLen));
if ( STATUS_SUCCESS == SC_AllocBuffer((PPVOID)&pInfoPDU, DataLen) ) {
// Zero out the structure and set basic header info.
memset(pInfoPDU, 0, DataLen); pInfoPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_SAVE_SESSION_INFO; // Now fill up the rest of the packet
pInfoPDU->data.InfoType = TS_INFOTYPE_LOGON_LONG;
pInfoPDU->data.Info.LogonInfoVersionTwo.Version = SAVE_SESSION_PDU_VERSION_ONE ; pInfoPDU->data.Info.LogonInfoVersionTwo.Size = sizeof(TS_LOGON_INFO_VERSION_2) ;
// Fill in the Session Id info.
pInfoPDU->data.Info.LogonInfoVersionTwo.SessionId = pLogonInfo->SessionId; // Fill in the Domain info.
pInfoPDU->data.Info.LogonInfoVersionTwo.cbDomain = DomainLen ;
// Fill in the UserName info.
pInfoPDU->data.Info.LogonInfoVersionTwo.cbUserName = UserNameLen ;
memcpy((PBYTE)(pInfoPDU + 1), pLogonInfo->Domain, DomainLen); // Note that in case the fDontDisplayLastUserName is TRUE
// the UserNameLen is 0 so we won't copy anything.
memcpy((PBYTE)(pInfoPDU + 1) + DomainLen, pLogonInfo->UserName, UserNameLen);
// Send it
SC_SendData((PTS_SHAREDATAHEADER)pInfoPDU, DataLen, DataLen, PROT_PRIO_UPDATES, 0);
} else { TRC_ALT((TB, "Failed to alloc pkt for " "PTS_SAVE_SESSION_INFO_PDU")); }
} // Client can accept long credentials
} else { //Send back a plain logon notification (without session update
//information)
//because the ActiveX control needs to expose an
//OnLoginComplete event. Older clients (e.g 2195)
//will just ignore this PDU
if ( STATUS_SUCCESS == SC_AllocBuffer((PPVOID)&pInfoPDU, sizeof(TS_SAVE_SESSION_INFO_PDU)) ) {
// Zero out the structure and set basic header info.
memset(pInfoPDU, 0, sizeof(TS_SAVE_SESSION_INFO_PDU)); pInfoPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_SAVE_SESSION_INFO;
// Now fill up the rest of the packet
pInfoPDU->data.InfoType = TS_INFOTYPE_LOGON_PLAINNOTIFY;
// Nothing else is needed
// Send it
//
SC_SendData((PTS_SHAREDATAHEADER)pInfoPDU, sizeof(TS_SAVE_SESSION_INFO_PDU), sizeof(TS_SAVE_SESSION_INFO_PDU), PROT_PRIO_UPDATES, 0);
} else { TRC_ALT((TB, "Failed to alloc pkt for " "PTS_SAVE_SESSION_INFO_PDU")); } }
pInfoPDU = NULL; if (pLogonInfo->Flags & LI_USE_AUTORECONNECT) {
if (scUseAutoReconnect) {
//
//Send down the autoreconnect cookie
//
m_pTSWd->arcReconnectSessionID = pLogonInfo->SessionId; if (DCS_UpdateAutoReconnectCookie()) {
//
// Record the update time to prevent a double-update
// in DCS_TimeToDoStuff
//
KeQuerySystemTime((PLARGE_INTEGER)&dcsLastArcUpdateTime); scEnablePeriodicArcUpdate = TRUE; } } else { DCS_FlushAutoReconnectCookie(); scEnablePeriodicArcUpdate = FALSE; }
} } else { TRC_ALT((TB, "Called before init")); }
DC_END_FN(); } /* DCS_UserLoggedOn */
/****************************************************************************/ /* Name: DCS_WDWKeyboardSetIndicators */ /* */ /* Purpose: Notify that keyboard indicators have changed */ /****************************************************************************/ void RDPCALL SHCLASS DCS_WDWKeyboardSetIndicators(void) { PTS_SET_KEYBOARD_INDICATORS_PDU pKeyPDU;
DC_BEGIN_FN("DCS_WDWKeyboardSetIndicators");
if ((_RNS_MAJOR_VERSION(m_pTSWd->version) > 8) || (_RNS_MINOR_VERSION(m_pTSWd->version) >= 1)) { // Get a buffer.
if ( STATUS_SUCCESS == SC_AllocBuffer((PPVOID)&pKeyPDU, sizeof(TS_SET_KEYBOARD_INDICATORS_PDU)) ) { // Zero out the structure and set basic header info.
memset(pKeyPDU, 0, sizeof(TS_SET_KEYBOARD_INDICATORS_PDU));
pKeyPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_SET_KEYBOARD_INDICATORS;
pKeyPDU->UnitId = m_pTSWd->KeyboardIndicators.UnitId; pKeyPDU->LedFlags = m_pTSWd->KeyboardIndicators.LedFlags;
// Send it.
SC_SendData((PTS_SHAREDATAHEADER)pKeyPDU, sizeof(TS_SET_KEYBOARD_INDICATORS_PDU), sizeof(TS_SET_KEYBOARD_INDICATORS_PDU), PROT_PRIO_UPDATES, 0); } else { TRC_ALT((TB, "Failed to alloc pkt for PTS_SET_KEYBOARD_INDICATORS_PDU")); } }
DC_END_FN(); } /* DCS_WDWKeyboardSetIndicators */
/****************************************************************************/ /* Name: DCS_WDWKeyboardSetImeStatus */ /* */ /* Purpose: Notify that ime status have changed */ /****************************************************************************/ void RDPCALL SHCLASS DCS_WDWKeyboardSetImeStatus(void) { PTS_SET_KEYBOARD_IME_STATUS_PDU pImePDU;
DC_BEGIN_FN("DCS_WDWKeyboardSetImeStatus");
if ((_RNS_MAJOR_VERSION(m_pTSWd->version) > 8) || (_RNS_MINOR_VERSION(m_pTSWd->version) >= 2)) { // Get a buffer.
if ( STATUS_SUCCESS == SC_AllocBuffer((PPVOID)&pImePDU, sizeof(TS_SET_KEYBOARD_IME_STATUS_PDU)) ) { // Zero out the structure and set basic header info.
memset(pImePDU, 0, sizeof(TS_SET_KEYBOARD_IME_STATUS_PDU));
pImePDU->shareDataHeader.pduType2 = TS_PDUTYPE2_SET_KEYBOARD_IME_STATUS;
pImePDU->UnitId = m_pTSWd->KeyboardImeStatus.UnitId; pImePDU->ImeOpen = m_pTSWd->KeyboardImeStatus.ImeOpen; pImePDU->ImeConvMode = m_pTSWd->KeyboardImeStatus.ImeConvMode;
// Send it.
SC_SendData((PTS_SHAREDATAHEADER)pImePDU, sizeof(TS_SET_KEYBOARD_IME_STATUS_PDU), sizeof(TS_SET_KEYBOARD_IME_STATUS_PDU), PROT_PRIO_UPDATES, 0); } else { TRC_ERR((TB, "Failed to alloc pkt for PTS_SET_KEYBOARD_IME_STATUS_PDU")); } }
DC_END_FN(); } /* DCS_WDWKeyboardSetImeStatus */
/****************************************************************************/ /* Name: DCS_TriggerUpdateShmCallback */ /* */ /* Purpose: Triggers a callback to the XX_UpdateShm functions on the */ /* correct WinStation context. */ /****************************************************************************/ void RDPCALL SHCLASS DCS_TriggerUpdateShmCallback(void) { DC_BEGIN_FN("DCS_TriggerUpdateShmCallback");
if (!dcsUpdateShmPending) { TRC_NRM((TB, "Trigger timer for UpdateShm")); dcsUpdateShmPending = TRUE;
if (!dcsCallbackTimerPending) { WDW_StartRITTimer(m_pTSWd, 0); dcsCallbackTimerPending = TRUE; } }
DC_END_FN(); } /* DCS_TriggerUpdateShmCallback */
/****************************************************************************/ /* Name: DCS_TriggerCBDataReady */ /* */ /* Purpose: Triggers a call to the clipboard data ready function in the */ /* correct WinStation context. */ /****************************************************************************/ void RDPCALL SHCLASS DCS_TriggerCBDataReady(void) { DC_BEGIN_FN("DCS_TriggerCBDataReady");
TRC_NRM((TB, "Trigger timer for CBDataReady"));
if (!dcsCallbackTimerPending) WDW_StartRITTimer(m_pTSWd, 10); // @@@ try 10ms delay
DC_END_FN(); } /* DCS_TriggerCBDataReady */
/****************************************************************************/ /* Name: DCS_UpdateShm */ /* */ /* Purpose: Update SHM */ /* */ /* Operation: Guaranteed to be called in a context where m_pShm is valid. */ /****************************************************************************/ void RDPCALL SHCLASS DCS_UpdateShm(void) { DC_BEGIN_FN("DCS_UpdateShm");
TRC_NRM((TB, "Check for specific wake-up calls."));
if (dcsUpdateShmPending) { TRC_NRM((TB, "Call UpdateShm calls"));
// A Global flag indicating shm updates for all components
m_pShm->fShmUpdate = TRUE;
SSI_UpdateShm(); SBC_UpdateShm(); BA_UpdateShm(); OA_UpdateShm(); OE_UpdateShm(); CM_UpdateShm(); SCH_UpdateShm(); SC_UpdateShm();
dcsUpdateShmPending = FALSE; } dcsCallbackTimerPending = FALSE;
DC_END_FN(); } /* DCS_UpdateShm */
/****************************************************************************/ /* Name: DCS_SendErrorInfo */ /* */ /* Purpose: Sends last error information to the client so that it can */ /* Display meaningful error messages to users about disconnects */ /****************************************************************************/ void RDPCALL SHCLASS DCS_SendErrorInfo(TSUINT32 errInfo) { PTS_SET_ERROR_INFO_PDU pErrorPDU = NULL; PTS_SHAREDATAHEADER pHdr = NULL; DC_BEGIN_FN("DCS_SendErrorInfo");
TRC_ASSERT(m_pTSWd->bSupportErrorInfoPDU, (TB,"DCS_SendErrorInfo called but client doesn't" "support errorinfo PDU")); //Send a PDU to the client to indicate the last error state
//this is analogous to win32's SetLastError() the PDU doesn't
//trigger a disconnect. The normal code path to disconnect
//is unchanged so we don't worry about affecting compatability with
//older clients
if ( STATUS_SUCCESS == SM_AllocBuffer( m_pTSWd->pSmInfo, (PPVOID) &pErrorPDU, sizeof(TS_SET_ERROR_INFO_PDU), FALSE, //never wait for an error packet
FALSE) ) { // Zero out the structure and set basic header info.
memset(pErrorPDU, 0, sizeof(TS_SET_ERROR_INFO_PDU));
//
// First set the share data header info
//
pHdr = (PTS_SHAREDATAHEADER)pErrorPDU; pHdr->shareControlHeader.pduType = TS_PDUTYPE_DATAPDU | TS_PROTOCOL_VERSION; pHdr->shareControlHeader.pduSource = 0; //user id may not be
//available yet
pHdr->shareControlHeader.totalLength = sizeof(TS_SET_ERROR_INFO_PDU); pHdr->shareID = 0; pHdr->streamID = (BYTE)PROT_PRIO_UPDATES; pHdr->uncompressedLength = (UINT16)sizeof(TS_SET_ERROR_INFO_PDU); pHdr->generalCompressedType = 0; pHdr->generalCompressedLength = 0; m_pTSWd->pProtocolStatus->Output.CompressedBytes += sizeof(TS_SET_ERROR_INFO_PDU);
//
// Error pdu specific info
//
pErrorPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_SET_ERROR_INFO_PDU; pErrorPDU->errorInfo = errInfo;
TRC_NRM((TB,"Sending ErrorInfo PDU for err:%d", errInfo)); // Send it
if(!SM_SendData( m_pTSWd->pSmInfo, pErrorPDU, sizeof(TS_SET_ERROR_INFO_PDU), 0, 0, FALSE, RNS_SEC_ENCRYPT, FALSE)) { TRC_ERR((TB, "Failed to SM_SendData for " "TS_SET_ERROR_INFO_PDU")); } } else { TRC_ALT((TB, "Failed to alloc pkt for " "TS_SET_ERROR_INFO_PDU")); }
DC_END_FN(); }
/****************************************************************************/ /* Name: DCS_SendAutoReconnectStatus
/*
/* Purpose: Sends autoreconnect status info to the client
/* (e.g. that autoreconnect failed so the client should go back to
/* displaying output so the user can enter cred at winlogon)
/*
/* Params:
/*
/*
/****************************************************************************/ void RDPCALL SHCLASS DCS_SendAutoReconnectStatus(TSUINT32 arcStatus) { PTS_AUTORECONNECT_STATUS_PDU pArcStatus = NULL; PTS_SHAREDATAHEADER pHdr = NULL; DC_BEGIN_FN("DCS_SendErrorInfo");
TRC_ASSERT(scUseAutoReconnect, (TB,"DCS_SendAutoReconnectStatus called but client doesn't" "support autoreconnect status PDU"));
if ( STATUS_SUCCESS == SM_AllocBuffer( m_pTSWd->pSmInfo, (PPVOID) &pArcStatus, sizeof(TS_AUTORECONNECT_STATUS_PDU), FALSE, //never wait for an error packet
FALSE) ) { // Zero out the structure and set basic header info.
memset(pArcStatus, 0, sizeof(TS_AUTORECONNECT_STATUS_PDU));
//
// First set the share data header info
//
pHdr = (PTS_SHAREDATAHEADER)pArcStatus; pHdr->shareControlHeader.pduType = TS_PDUTYPE_DATAPDU | TS_PROTOCOL_VERSION; pHdr->shareControlHeader.pduSource = 0; //user id may not be
//available yet
pHdr->shareControlHeader.totalLength = sizeof(TS_AUTORECONNECT_STATUS_PDU); pHdr->shareID = scShareID; pHdr->streamID = (BYTE)PROT_PRIO_UPDATES; pHdr->uncompressedLength = (UINT16)sizeof(TS_AUTORECONNECT_STATUS_PDU); pHdr->generalCompressedType = 0; pHdr->generalCompressedLength = 0; m_pTSWd->pProtocolStatus->Output.CompressedBytes += sizeof(TS_AUTORECONNECT_STATUS_PDU);
//
// Error pdu specific info
//
pArcStatus->shareDataHeader.pduType2 = TS_PDUTYPE2_ARC_STATUS_PDU; pArcStatus->arcStatus = arcStatus;
TRC_NRM((TB,"Sending ArcStatus PDU for status:%d", arcStatus)); // Send it
if(!SM_SendData( m_pTSWd->pSmInfo, pArcStatus, sizeof(TS_AUTORECONNECT_STATUS_PDU), 0, 0, FALSE, RNS_SEC_ENCRYPT, FALSE)) { TRC_ERR((TB, "Failed to SM_SendData for " "TS_AUTORECONNECT_STATUS_PDU")); } } else { TRC_ALT((TB, "Failed to alloc pkt for " "TS_AUTORECONNECT_STATUS_PDU")); }
DC_END_FN(); }
|