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.
 
 
 
 
 
 

1089 lines
48 KiB

/****************************************************************************/
/* ascint.c */
/* */
/* Share Controller Internal functions. */
/* */
/* Copyright(c) Microsoft, PictureTel 1992-1997 */
/* Copyright(c) Microsoft 1997-2000 */
/****************************************************************************/
#include <precomp.h>
#pragma hdrstop
#define TRC_FILE "ascint"
#include <as_conf.hpp>
#include <string.h>
#include <stdio.h>
extern "C"
{
#include <asmapi.h>
}
/****************************************************************************/
/* FUNCTION: SCPartyJoiningShare */
/* */
/* Called when a new party is joining the share. This is an internal */
/* function because it is the SC which calls all these functions. The */
/* processing done here relies on the capabilities - so it is in here as */
/* this is called after CPC_PartyJoiningShare. */
/* */
/* PARAMETERS: */
/* locPersonID - local person ID of remote person joining the share. */
/* oldShareSize - the number of the parties which were in the share (ie */
/* excludes the joining party). */
/* */
/* RETURNS: */
/* TRUE if the party can join the share. */
/* FALSE if the party can NOT join the share. */
/****************************************************************************/
BOOL RDPCALL SHCLASS SCPartyJoiningShare(LOCALPERSONID locPersonID,
unsigned oldShareSize)
{
DC_BEGIN_FN("SCPartyJoiningShare");
DC_IGNORE_PARAMETER(locPersonID);
if (oldShareSize != 0) {
SCParseGeneralCaps();
// Initialize Flow Control.
SCFlowInit();
}
DC_END_FN();
return TRUE;
}
/****************************************************************************/
/* FUNCTION: SCPartyLeftShare() */
/* */
/* Called when a party has left the share. */
/* */
/* PARAMETERS: */
/* locPersonID - local person ID of remote person leaving the */
/* share. */
/* newShareSize - the number of the parties now in the share (ie excludes */
/* the leaving party). */
/****************************************************************************/
void RDPCALL SHCLASS SCPartyLeftShare(LOCALPERSONID locPersonID,
unsigned newShareSize)
{
DC_BEGIN_FN("SCPartyLeftShare");
DC_IGNORE_PARAMETER(locPersonID);
if (newShareSize != 0)
SCParseGeneralCaps();
DC_END_FN();
}
/****************************************************************************/
// SCParseGeneralCaps
//
// Enumerates the general capabilities and sets up needed variables.
/****************************************************************************/
void RDPCALL SHCLASS SCParseGeneralCaps()
{
DC_BEGIN_FN("SCParseGeneralCaps");
// Set default local support for fast-path output. It must be shut down
// during a shadow to guarantee the non-fast-path format is used
// in the cross-server shadow pipe, even though that means a performance
// hit on the wire to each client. Note that checking for shadowState
// == SHADOW_NONE is not a sufficient check, there is a timing window
// where it is likely not be be set yet, so we also force it off in
// SC_AddPartyToShare().
if (m_pTSWd->shadowState == SHADOW_NONE) {
scUseFastPathOutput = TRUE;
}
else {
scUseFastPathOutput = FALSE;
TRC_ALT((TB,"Forcing fast-path output to off in shadow"));
}
CPC_EnumerateCapabilities(TS_CAPSETTYPE_GENERAL, NULL,
SCEnumGeneralCaps);
// Set the package header reservation size based on the final results of
// the fast-path output support.
if (scUseFastPathOutput) {
if (m_pTSWd->bCompress) {
TRC_ALT((TB,"Fast-path output enabled with compression"));
scUpdatePDUHeaderSpace = 4;
scCompressionUsedValue = TS_OUTPUT_FASTPATH_COMPRESSION_USED;
}
else {
TRC_ALT((TB,"Fast-path output enabled without compression"));
scUpdatePDUHeaderSpace = 3;
scCompressionUsedValue = 0;
}
}
else {
TRC_ALT((TB,"Fast-path output disabled"));
scUpdatePDUHeaderSpace = sizeof(TS_SHAREDATAHEADER);
}
SCUpdateVCCaps();
DC_END_FN();
}
/****************************************************************************/
/* FUNCTION: SCEnumGeneralCaps */
/* */
/* Used to determine the lowest version in the share. */
/* */
/* PARAMETERS: standard CPC callback parameters */
/****************************************************************************/
void RDPCALL SHCLASS SCEnumGeneralCaps(
LOCALPERSONID locPersonID,
UINT_PTR UserData,
PTS_CAPABILITYHEADER pCapabilities )
{
PTS_GENERAL_CAPABILITYSET pGeneralCaps =
(PTS_GENERAL_CAPABILITYSET)pCapabilities;
DC_BEGIN_FN("SCEnumGeneralCaps");
DC_IGNORE_PARAMETER(locPersonID);
DC_IGNORE_PARAMETER(UserData);
// Determine if we should support No BC header or not depending on the
// client support level and the current support level
scNoBitmapCompressionHdr = min(scNoBitmapCompressionHdr,
pGeneralCaps->extraFlags & TS_EXTRA_NO_BITMAP_COMPRESSION_HDR);
// Disable fast-path output if any client does not support it.
if (!(pGeneralCaps->extraFlags & TS_FASTPATH_OUTPUT_SUPPORTED))
scUseFastPathOutput = FALSE;
// Enable sending Long Credentials back to the client if it supports it
if (pGeneralCaps->extraFlags & TS_LONG_CREDENTIALS_SUPPORTED) {
scUseLongCredentials = TRUE;
} else {
scUseLongCredentials = FALSE;
}
// Determine if we should enable the arc cookie
if ((pGeneralCaps->extraFlags & TS_AUTORECONNECT_COOKIE_SUPPORTED) &&
(FALSE == m_pTSWd->fPolicyDisablesArc)) {
scUseAutoReconnect = TRUE;
}
else {
scUseAutoReconnect = FALSE;
}
// Determine if we support the more secure checksum style
if ((pGeneralCaps->extraFlags & TS_ENC_SECURE_CHECKSUM)) {
SM_SetSafeChecksumMethod(scPSMHandle, TRUE);
}
else {
SM_SetSafeChecksumMethod(scPSMHandle, FALSE);
}
DC_END_FN();
}
/****************************************************************************/
/* FUNCTION: SCCallPartyJoiningShare */
/* */
/* Calls other components' XX_PartyJoiningShare() functions. Should be */
/* called with scNumberInShare set to the old call size. */
/* */
/* PARAMETERS: */
/* locPersonID - of party joining the call. */
/* sizeOfCaps - sizeof the capabilities parameter pCaps. */
/* pCaps - pointer to capabilities for the party. */
/* pAccepted - pointer to array of BOOLs which is filled in with the */
/* result of the respective components function. */
/* oldShareSize - the number to pass to the PJS functions. */
/* */
/* RETURNS: */
/* TRUE - all components accepted the party; pAccepted will be filled with */
/* TRUE. */
/* FALSE - a component rejected the party. Any components which accepted */
/* the party will have their pAccepted entry set to TRUE; all other */
/* entries will be FALSE. */
/****************************************************************************/
BOOL RDPCALL SHCLASS SCCallPartyJoiningShare(
LOCALPERSONID locPersonID,
unsigned sizeOfCaps,
PVOID pCaps,
PBOOL pAccepted,
unsigned oldShareSize)
{
DC_BEGIN_FN("SCCallPartyJoiningShare");
/************************************************************************/
/* Set all of pAccepted to FALSE. */
/************************************************************************/
memset(pAccepted, 0, sizeof(BOOL) * SC_NUM_PARTY_JOINING_FCTS);
/************************************************************************/
/* Call the functions in the correct order, giving up if any reject the */
/* party. */
/************************************************************************/
#define CALL_PJS(NUM, CALL) \
TRC_NRM((TB, "Call PJS # %d", NUM)); \
if (0 == (pAccepted[NUM] = CALL)) \
{ \
TRC_NRM((TB, "%d PartyJoining failed", (unsigned)NUM)); \
return FALSE; \
}
TRC_NRM((TB, "{%d}Call PJS functions", locPersonID));
/************************************************************************/
// Notes on the order of PartyJoiningShare calls:
// 1. CPC must be called before everyone else (as everyone else needs
// capabilites for the new party).
// 2. UP must be called after SC because UP relies on the caps
// negotiation in SC.
/************************************************************************/
CALL_PJS(SC_CPC, CPC_PartyJoiningShare(locPersonID, oldShareSize,
sizeOfCaps, pCaps))
CALL_PJS(SC_SC, SCPartyJoiningShare(locPersonID, oldShareSize))
CALL_PJS(SC_IM, IM_PartyJoiningShare (locPersonID, oldShareSize))
CALL_PJS(SC_CA, CA_PartyJoiningShare (locPersonID, oldShareSize))
CALL_PJS(SC_CM, CM_PartyJoiningShare (locPersonID, oldShareSize))
CALL_PJS(SC_OE, OE_PartyJoiningShare (locPersonID, oldShareSize))
CALL_PJS(SC_SSI, SSI_PartyJoiningShare(locPersonID, oldShareSize))
CALL_PJS(SC_USR, USR_PartyJoiningShare(locPersonID, oldShareSize))
CALL_PJS(SC_UP, UP_PartyJoiningShare(locPersonID, oldShareSize))
CALL_PJS(SC_SBC, SBC_PartyJoiningShare(locPersonID, oldShareSize))
TRC_DATA_NRM("PJS status",
pAccepted,
sizeof(BOOL) * SC_NUM_PARTY_JOINING_FCTS);
DC_END_FN();
return TRUE;
}
/****************************************************************************/
/* FUNCTION: SCCallPartyLeftShare */
/* */
/* Calls other components' XX_PartyLeftShare() functions. should be called */
/* with scNumberInShare set to the new call size. */
/* */
/* PARAMETERS: */
/* locPersonID - of party who has left the call. */
/* pAccepted - pointer to array of BOOLs which is used to decide which */
/* components' functions to call. Any component with an entry set to */
/* TRUE will be called. */
/* newShareSize - the number to pass to the various PLS functions. */
/****************************************************************************/
void RDPCALL SHCLASS SCCallPartyLeftShare(LOCALPERSONID locPersonID,
PBOOL pAccepted,
unsigned newShareSize )
{
DC_BEGIN_FN("SCCallPartyLeftShare");
/************************************************************************/
/* Call any components which have their pAccepted entry to TRUE. */
/************************************************************************/
#define CALL_PLS(A, B) \
{ \
if (pAccepted[A]) \
{ \
TRC_NRM((TB, "Call PLS # %d", A)); \
B(locPersonID, newShareSize); \
} \
}
TRC_NRM((TB, "Call PLS functions"));
/************************************************************************/
/* Notes on order of PartyLeftShare calls */
/* */
/* 1. CPC must be called first (so everyone else gets capabilities */
/* which exclude the party which has left). */
/************************************************************************/
CALL_PLS(SC_CPC, CPC_PartyLeftShare)
CALL_PLS(SC_SC, SCPartyLeftShare)
CALL_PLS(SC_CA, CA_PartyLeftShare )
CALL_PLS(SC_IM, IM_PartyLeftShare )
CALL_PLS(SC_OE, OE_PartyLeftShare )
CALL_PLS(SC_SBC, SBC_PartyLeftShare)
CALL_PLS(SC_SSI, SSI_PartyLeftShare)
CALL_PLS(SC_USR, USR_PartyLeftShare)
CALL_PLS(SC_UP, UP_PartyLeftShare)
TRC_NRM((TB, "Done PLS functions"));
DC_END_FN();
}
/****************************************************************************/
/* Name: SCInitiateSync */
/* */
/* Purpose: Initiate synchronization */
/* */
/* Params: bShadowSync - set to true of this sync is being requested for */
/* a shadowing session. */
/* */
/* Operation: Broadcast a sync packet on all priorities */
/* Call other components to synchronize, unless this is a shadow */
/* sync in which case the DD will already have synchronized */
/* itself prior to initiating this action. */
/****************************************************************************/
void RDPCALL SHCLASS SCInitiateSync(BOOLEAN bShadowSync)
{
PTS_SYNCHRONIZE_PDU pPkt;
NTSTATUS status;
BOOL rc;
DC_BEGIN_FN("SCInitiateSync");
SC_CHECK_STATE(SCE_INITIATESYNC);
/************************************************************************/
// Allocate a Sync PDU
// fWait is TRUE means that we will always wait for a buffer to be avail
/************************************************************************/
status = SM_AllocBuffer(scPSMHandle,
(PPVOID)(&pPkt),
sizeof(TS_SYNCHRONIZE_PDU),
TRUE,
FALSE);
if ( STATUS_SUCCESS == status ) {
/********************************************************************/
// Build the Sync PDU
/********************************************************************/
pPkt->shareDataHeader.shareControlHeader.totalLength =
sizeof(TS_SYNCHRONIZE_PDU);
pPkt->shareDataHeader.pduType2 = TS_PDUTYPE2_SYNCHRONIZE;
pPkt->messageType = TS_SYNCMSGTYPE_SYNC;
/********************************************************************/
// Send the Sync PDU (Broadcast, all parties, all priorities)
/********************************************************************/
rc = SC_SendData((PTS_SHAREDATAHEADER)pPkt,
sizeof(TS_SYNCHRONIZE_PDU),
sizeof(TS_SYNCHRONIZE_PDU),
0, 0);
if (rc) {
TRC_NRM((TB, "Sent Sync OK"));
/****************************************************************/
// Call all the XX_SyncNow() functions.
/****************************************************************/
CA_SyncNow();
PM_SyncNow(); // added for shadowing
UP_SyncNow(bShadowSync);
}
else {
TRC_ERR((TB, "Failed to send Sync PDU"));
}
}
else {
TRC_ERR((TB, "Failed to alloc syncPDU"));
}
DC_EXIT_POINT:
DC_END_FN();
} /* SCInitiateSync */
/****************************************************************************/
/* Name: SCConfirmActive */
/* */
/* Purpose: Handle incoming ConfirmActivePDU */
/* */
/* Params: netPersonID - ID of sender of ConfirmActivePDU */
/* pPkt - ConfirmActivePDU */
/****************************************************************************/
void RDPCALL SHCLASS SCConfirmActive(
PTS_CONFIRM_ACTIVE_PDU pPkt,
unsigned DataLength,
NETPERSONID netPersonID)
{
LOCALPERSONID localPersonID = 0;
unsigned localCapsSize;
PTS_COMBINED_CAPABILITIES pLocalCaps;
BOOL acceptedArray[SC_NUM_PARTY_JOINING_FCTS];
BOOL rc = FALSE;
BOOL callingPJS = FALSE;
BOOL kickWDW = FALSE;
unsigned errDetailCode = 0;
WCHAR detailData[25];
unsigned len, detailDataLen;
DC_BEGIN_FN("SCConfirmActive");
SC_CHECK_STATE(SCE_CONFIRM_ACTIVE);
// First check we have enogh data for this packet.
if (DataLength >= (sizeof(TS_CONFIRM_ACTIVE_PDU) - 1)) {
if (DataLength >= (sizeof(TS_CONFIRM_ACTIVE_PDU) - 1 +
pPkt->lengthSourceDescriptor +
pPkt->lengthCombinedCapabilities)) {
// Do some meaningful work here to predict the branches correctly.
goto PDUOK;
}
else {
TRC_ERR((TB,"Total PDU len %u too short for header and data len %u",
DataLength, pPkt->lengthSourceDescriptor +
pPkt->lengthCombinedCapabilities));
goto ShortPDU;
}
}
else {
TRC_ERR((TB,"Data length %u too short for ConfirmActivePDU header",
DataLength));
goto ShortPDU;
}
PDUOK:
kickWDW = FALSE;
/************************************************************************/
/* Check it's the right ConfirmActivePDU */
/************************************************************************/
if (pPkt->shareID != scShareID)
{
TRC_ERR((TB, "Wrong Share ID, expect %x, got %x",
scShareID, pPkt->shareID));
errDetailCode = Log_RDP_ConfirmActiveWrongShareID;
len = swprintf(detailData, L"%x %x", scShareID, pPkt->shareID);
detailDataLen = sizeof(*detailData) * len;
DC_QUIT;
}
if (pPkt->originatorID != scUserID)
{
TRC_ERR((TB, "Wrong originator ID, expect %d, got %hd",
scUserID, pPkt->originatorID));
errDetailCode = Log_RDP_ConfirmActiveWrongOriginator;
len = swprintf(detailData, L"%x %hx", scUserID, pPkt->originatorID);
detailDataLen = sizeof(*detailData) * len;
DC_QUIT;
}
/************************************************************************/
/* We will receive a ConfirmActivePDU on all priorities. If we get */
/* here and we're already in a Share, this must be a second or */
/* subsequent one. Simply ignore it. Set rc = TRUE so that we don't */
/* send a DeactivateOtherPDU below. */
/************************************************************************/
if (scState == SCS_IN_SHARE)
{
TRC_ALT((TB, "Superfluous ConfirmActivePDU received"));
rc = TRUE;
DC_QUIT;
}
/************************************************************************/
/* If we get here, this is the first ConfirmActivePDU, and it's from */
/* the right Client. Set a flag which will cause us to kick WDW back */
/* into life at the end of this function */
/************************************************************************/
kickWDW = TRUE;
/************************************************************************/
/* Reject this party if it will exceed the maximum number of parties */
/* allowed in a share. (Not required for RNS V1.0, but left in as it */
/* doesn't do any harm). */
/************************************************************************/
if (scNumberInShare == SC_DEF_MAX_PARTIES)
{
TRC_ERR((TB, "Reached max parties in share %d",
SC_DEF_MAX_PARTIES));
DC_QUIT;
}
/************************************************************************/
/* If this is the first remote party in the share, call the */
/* XX_PartyJoiningShare() functions for the local party first. */
/************************************************************************/
callingPJS = TRUE;
if (scNumberInShare == 0)
{
CPC_GetCombinedCapabilities(SC_LOCAL_PERSON_ID,
&localCapsSize,
&pLocalCaps);
if (!SCCallPartyJoiningShare(SC_LOCAL_PERSON_ID,
localCapsSize,
pLocalCaps,
acceptedArray,
0))
{
/****************************************************************/
/* Some component rejected the local party */
/****************************************************************/
TRC_ERR((TB, "The local party should never be rejected"));
DC_QUIT;
}
/********************************************************************/
/* There is now one party in the share (the local one). */
/********************************************************************/
scNumberInShare = 1;
TRC_NRM((TB, "Added local person"));
}
/************************************************************************/
/* Calculate a localPersonID for the remote party and store their */
/* details in the party array. */
/************************************************************************/
for ( localPersonID = 1;
localPersonID < SC_DEF_MAX_PARTIES;
localPersonID++ )
{
if (scPartyArray[localPersonID].netPersonID == 0)
{
/****************************************************************/
/* Found an empty slot. */
/****************************************************************/
TRC_NRM((TB, "Allocated local person ID %d", localPersonID));
break;
}
}
/************************************************************************/
/* Even though scNumberInShare is checked against SC_DEF_MAX_PARTIES */
/* above, the loop above might still not find an empty slot. */
/************************************************************************/
if (SC_DEF_MAX_PARTIES <= localPersonID)
{
TRC_ABORT((TB, "Couldn't find room to store local person"));
DC_QUIT;
}
/************************************************************************/
/* Store the new person's details */
/************************************************************************/
scPartyArray[localPersonID].netPersonID = netPersonID;
// we know that we have at least lengthSourceDescriptor bytes in the buffer
// we should copy not more than lengthSourceDescriptor or the destination
// buffer size.
strncpy(scPartyArray[localPersonID].name,
(char *)(&(pPkt->data[0])),
min(sizeof(scPartyArray[0].name)-sizeof(scPartyArray[0].name[0]),
pPkt->lengthSourceDescriptor));
// zero terminate to make sure we don't overflow on subsequent processing.
scPartyArray[localPersonID].name[sizeof(scPartyArray[0].name)/
sizeof(scPartyArray[0].name[0]) - 1] = 0;
memset(scPartyArray[localPersonID].sync,
0,
sizeof(scPartyArray[localPersonID].sync));
TRC_NRM((TB, "{%d} person name %s",
(unsigned)localPersonID, scPartyArray[localPersonID].name));
/************************************************************************/
/* Call the XX_PartyJoiningShare() functions for the remote party. */
/************************************************************************/
if (!SCCallPartyJoiningShare(localPersonID,
pPkt->lengthCombinedCapabilities,
(PVOID)(&(pPkt->data[pPkt->lengthSourceDescriptor])),
acceptedArray,
scNumberInShare))
{
/********************************************************************/
// Some component rejected the remote party. Force a disconnect
// and log an event.
/********************************************************************/
TRC_ERR((TB, "Remote party rejected"));
errDetailCode = Log_RDP_BadCapabilities;
detailDataLen = 0;
DC_QUIT;
}
/************************************************************************/
/* The remote party is now in the share. */
/************************************************************************/
callingPJS = FALSE;
rc = TRUE;
scNumberInShare++;
TRC_NRM((TB, "Number in share %d", (unsigned)scNumberInShare));
/************************************************************************/
/* Move onto the next state. */
/************************************************************************/
SC_SET_STATE(SCS_IN_SHARE);
/************************************************************************/
/* Synchronise only for primary stacks. Shadow stacks will be sync'd */
/* by the DD right before output starts. */
/************************************************************************/
SCInitiateSync(m_pTSWd->StackClass == Stack_Shadow);
DC_EXIT_POINT:
if (!rc)
{
/********************************************************************/
/* Something went wrong. Tidy up */
/********************************************************************/
TRC_NRM((TB, "Something went wrong - %d people in Share",
scNumberInShare));
/********************************************************************/
/* If we fail, tell WDW now, so it can clean up. If we succeed, FH */
/* tells WDW when font negotiation is complete. */
/********************************************************************/
if (kickWDW)
{
TRC_NRM((TB, "Kick WDW"));
WDW_ShareCreated(m_pTSWd, FALSE);
}
if (callingPJS)
{
TRC_NRM((TB, "Failed in PJS functions"));
/****************************************************************/
/* Notify components that remote party has left Share. Note */
/* that scNumberInShare is not updated if PJS functions fail. */
/****************************************************************/
if (scNumberInShare > 0)
{
/************************************************************/
/* We failed to add a remote party */
/************************************************************/
TRC_NRM((TB, "Failed to add remote party"));
SCCallPartyLeftShare(localPersonID,
acceptedArray,
scNumberInShare );
/************************************************************/
/* Set acceptedArray ready to call PJS for local person */
/************************************************************/
memset(acceptedArray,
TRUE,
sizeof(BOOL) * SC_NUM_PARTY_JOINING_FCTS );
}
if (scNumberInShare <= 1)
{
/************************************************************/
/* We failed to add one of */
/* - the local person (scNumberInShare == 0) */
/* - the first remote person (scNumberInShare == 1) */
/* Either way, we now need to remove the local person. */
/************************************************************/
TRC_NRM((TB, "Clean up local person"));
SCCallPartyLeftShare(SC_LOCAL_PERSON_ID,
acceptedArray, 0);
scNumberInShare = 0;
}
}
/********************************************************************/
/* Now we need to terminate the Client, via one of two means: */
/* - if it's a protocol error, simply disconnect the Client */
/* - if it's a resource error, try to end the Share. */
/********************************************************************/
if (errDetailCode != 0)
{
WDW_LogAndDisconnect(m_pTSWd, TRUE,
errDetailCode,
(BYTE *)detailData,
detailDataLen);
}
TRC_NRM((TB, "Reject the new person"));
SCDeactivateOther(netPersonID);
/********************************************************************/
/* Finally, free the local person ID, if one was allocated */
/********************************************************************/
if ((localPersonID != 0) && (localPersonID != SC_DEF_MAX_PARTIES))
{
TRC_NRM((TB, "Free local person ID"));
scPartyArray[localPersonID].netPersonID = 0;
}
}
DC_END_FN();
return;
// Error handling
ShortPDU:
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_ConfirmActivePDUTooShort,
(BYTE *)pPkt, DataLength);
DC_END_FN();
} /* SC_ConfirmActivePDU */
/****************************************************************************/
/* Name: SCDeactivateOther */
/* */
/* Purpose: Deactivate another person */
/* */
/* Params: netPersonID - ID of person to be deactivated */
/****************************************************************************/
void RDPCALL SHCLASS SCDeactivateOther(NETPERSONID netPersonID)
{
unsigned pktLen;
unsigned nameLen;
PTS_DEACTIVATE_OTHER_PDU pPkt;
NTSTATUS status;
BOOL rc;
DC_BEGIN_FN("SCDeactivateOther");
/************************************************************************/
/* Allocate a buffer */
/************************************************************************/
pktLen = sizeof(TS_DEACTIVATE_OTHER_PDU) - 1;
nameLen = strlen(scPartyArray[0].name);
nameLen = (unsigned)DC_ROUND_UP_4(nameLen);
pktLen += nameLen;
// fWait is TRUE means that we will always wait for a buffer to be avail
status = SM_AllocBuffer(scPSMHandle, (PPVOID)(&pPkt), pktLen, TRUE, FALSE);
if ( STATUS_SUCCESS == status ) {
/********************************************************************/
// Fill in the packet fields.
/********************************************************************/
pPkt->shareControlHeader.totalLength = (UINT16)pktLen;
pPkt->shareControlHeader.pduType = TS_PDUTYPE_DEACTIVATEOTHERPDU |
TS_PROTOCOL_VERSION;
pPkt->shareControlHeader.pduSource = (UINT16)scUserID;
pPkt->shareID = scShareID;
pPkt->deactivateID = (UINT16)netPersonID;
memcpy(&(pPkt->sourceDescriptor[0]), scPartyArray[0].name, nameLen);
// Send it.
rc = SM_SendData(scPSMHandle, pPkt, pktLen, TS_HIGHPRIORITY, 0,
FALSE, RNS_SEC_ENCRYPT, FALSE);
if (!rc) {
TRC_ERR((TB, "Failed to send TS_DEACTIVATE_OTHER_PDU"));
}
}
else {
/********************************************************************/
/* Failed to allocate a buffer. This Bad News. Give up. */
/********************************************************************/
TRC_ERR((TB, "Failed to alloc %d bytes for TS_DEACTIVATE_OTHER_PDU",
pktLen));
}
DC_END_FN();
} /* SCDeactivateOther */
/****************************************************************************/
/* Name: SCEndShare */
/* */
/* Purpose: Clean up the local side of the share */
/* */
/* Operation: Call all PartyLeftShare functions for each party. */
/****************************************************************************/
void RDPCALL SHCLASS SCEndShare(void)
{
BOOL acceptedArray[SC_NUM_PARTY_JOINING_FCTS];
int i;
DC_BEGIN_FN("SCEndShare");
/************************************************************************/
/* If no-one has joined the Share yet, there's nothing to do */
/************************************************************************/
if (scNumberInShare == 0)
{
TRC_ALT((TB, "Ending Share before it was started"));
DC_QUIT;
}
/************************************************************************/
/* Call PLS for all remote people. */
/************************************************************************/
memset(acceptedArray, TRUE, sizeof(acceptedArray));
for (i = SC_DEF_MAX_PARTIES - 1; i > 0; i--)
{
if (scPartyArray[i].netPersonID != 0)
{
TRC_NRM((TB, "Party %d left Share", i));
scNumberInShare--;
SCCallPartyLeftShare(i, acceptedArray, scNumberInShare);
memset(&(scPartyArray[i]), 0, sizeof(*scPartyArray));
}
}
/************************************************************************/
/* Now call PLS functions for the local person. Don't clear */
/* scPartyArray for the local person, as the info is still valid. */
/************************************************************************/
scNumberInShare--;
TRC_ASSERT((scNumberInShare == 0),
(TB, "Still %d people in the Share", scNumberInShare));
TRC_NRM((TB, "Local party left Share"));
SCCallPartyLeftShare(0, acceptedArray, scNumberInShare);
DC_EXIT_POINT:
/************************************************************************/
/* Return to the inititalized state */
/************************************************************************/
SC_SET_STATE(SCS_INITED);
DC_END_FN();
} /* SCEndShare */
/****************************************************************************/
/* Name: SCSynchronizePDU */
/* */
/* Purpose: Handle incoming Synchronize PDUs */
/* */
/* Params: netPersonID - user ID of the sender */
/* pPkt - SynchronizePDU */
/****************************************************************************/
void RDPCALL SHCLASS SCSynchronizePDU(NETPERSONID netPersonID,
UINT32 priority,
PTS_SYNCHRONIZE_PDU pPkt)
{
LOCALPERSONID localID;
DC_BEGIN_FN("SCSynchronizePDU");
localID = SC_NetworkIDToLocalID(netPersonID);
TRC_NRM((TB, "SynchronizePDU person [%d] {%d}, priority %d",
netPersonID, localID, priority));
scPartyArray[localID].sync[priority] = TRUE;
DC_END_FN();
} /* SCSynchronizePDU */
/****************************************************************************/
/* Name: SCReceivedControlPacket */
/* */
/* Purpose: Handle incoming control packets */
/* */
/* Params: netPersonID - ID of the sender */
/* priority - priority on which the packet was sent */
/* pPkt - the packet */
/****************************************************************************/
void RDPCALL SHCLASS SCReceivedControlPacket(
NETPERSONID netPersonID,
UINT32 priority,
void *pPkt,
unsigned DataLength)
{
unsigned pduType;
LOCALPERSONID locPersonID;
BOOL pduOK = FALSE;
BOOL status;
DC_BEGIN_FN("SCReceivedControlPacket");
// We have enough data to read the flow control marker since the marker
// is overlaid over the SHARECONTROLHEADER.totalLength. We checked earlier
// for having enough data to read the share ctrl hdr.
/************************************************************************/
/* First, check for Flow Control packets */
/************************************************************************/
if (((PTS_FLOW_PDU)pPkt)->flowMarker != TS_FLOW_MARKER)
{
/********************************************************************/
/* Check for control packets */
/********************************************************************/
// SC_CHECK_STATE(SCE_CONTROLPACKET);
pduOK = TRUE;
pduType = ((PTS_SHARECONTROLHEADER)pPkt)->pduType & TS_MASK_PDUTYPE;
switch (pduType) {
case TS_PDUTYPE_CONFIRMACTIVEPDU:
TRC_ALT((TB, "%s Stack: ConfirmActivePDU",
m_pTSWd->StackClass == Stack_Primary ? "Primary" :
(m_pTSWd->StackClass == Stack_Passthru ? "Passthru" :
"Shadow")));
SCConfirmActive((PTS_CONFIRM_ACTIVE_PDU)pPkt, DataLength,
netPersonID);
break;
case TS_PDUTYPE_CLIENTRANDOMPDU:
TRC_ALT((TB, "ClientRandomPDU"));
status = SC_SaveClientRandom((PTS_CLIENT_RANDOM_PDU) pPkt, DataLength);
if (status != TRUE)
{
TRC_ERR((TB, "Error in SC_SaveClientRandom, data length = %u", DataLength));
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_InputPDUBadLength,
(BYTE *) pPkt,
DataLength);
}
break;
default:
{
/************************************************************/
/* At the moment, we don't expect or process any other */
/* control packets */
/************************************************************/
TRC_ERR((TB, "Unexpected packet type %d", pduType));
TRC_DATA_NRM("Packet", pPkt,
((PTS_SHARECONTROLHEADER)&pPkt)->totalLength);
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_UnknownPDUType,
(BYTE *) &pduType,
sizeof(pduType));
}
break;
}
}
else
{
/********************************************************************/
/* For the purposes of state checking, treat Flow Control packets */
/* as data packets. */
/********************************************************************/
SC_CHECK_STATE(SCE_DATAPACKET);
pduOK = TRUE;
// Make sure we have enough data to access the TS_FLOW_PDU fields.
if (DataLength >= sizeof(TS_FLOW_PDU)) {
pduType = ((PTS_FLOW_PDU)pPkt)->pduType;
locPersonID = SC_NetworkIDToLocalID(netPersonID);
}
else {
TRC_ERR((TB,"Data length %u too short for FlowPDU", DataLength));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_FlowPDUTooShort,
(BYTE *)pPkt, DataLength);
DC_QUIT;
}
switch (pduType)
{
case TS_PDUTYPE_FLOWTESTPDU:
{
TRC_NRM((TB, "[%d] {%d} Flow Test PDU on priority %d",
netPersonID, locPersonID, priority));
SCFlowTestPDU(locPersonID, (PTS_FLOW_PDU)pPkt, priority);
}
break;
default:
{
TRC_ERR((TB, "[%d] {%d} Unknown Flow PDU %d on priority %d",
netPersonID, locPersonID, pduType, priority));
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_UnknownFlowPDU,
(BYTE *) &pduType,
sizeof(pduType));
}
break;
}
}
DC_EXIT_POINT:
if (!pduOK)
{
/********************************************************************/
/* Out-of-sequence control PDU - log and disconnect */
/********************************************************************/
WCHAR detailData[(sizeof(pduType)*2) + (sizeof(scState)*2) + 2];
TRC_ERR((TB, "Out-of-sequence control PDU %hx, state %d",
pduType, scState));
swprintf(detailData, L"%hx %x", pduType, scState);
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_ControlPDUSequence,
(BYTE *)detailData,
sizeof(detailData));
}
DC_END_FN();
} /* SCReceivedControlPacket */
/****************************************************************************/
/* Name: SCFlowTestPDU */
/* */
/* Purpose: Handle incoming Flow Test PDUs */
/* */
/* Params: locPersonID - id of the sender */
/* pPkt - the Flow Test PDU */
/****************************************************************************/
void RDPCALL SHCLASS SCFlowTestPDU(
LOCALPERSONID locPersonID,
PTS_FLOW_PDU pPkt,
UINT32 priority)
{
PTS_FLOW_PDU pRsp;
NTSTATUS status;
BOOL rc;
DC_BEGIN_FN("SCFlowTestPDU");
// Build and send a flow response PDU.
// fWait is TRUE means that we will always wait for a buffer to be avail
status = SM_AllocBuffer(scPSMHandle, (PPVOID)(&pRsp), sizeof(*pRsp), TRUE, FALSE);
if ( STATUS_SUCCESS == status ) {
pRsp->flowMarker = TS_FLOW_MARKER;
pRsp->pduType = TS_PDUTYPE_FLOWRESPONSEPDU;
pRsp->flowIdentifier = pPkt->flowIdentifier;
pRsp->flowNumber = pPkt->flowNumber;
pRsp->pduSource = pPkt->pduSource;
rc = SM_SendData(scPSMHandle, pRsp, sizeof(*pRsp), priority,
scPartyArray[locPersonID].netPersonID, FALSE, RNS_SEC_ENCRYPT, FALSE);
if (!rc) {
TRC_ERR((TB, "Failed to send Flow Response PDU"));
}
}
else {
TRC_ERR((TB, "Failed to alloc Flow Response PDU"));
}
DC_END_FN();
} /* SCFlowTestPDU */
//
// SCUpdateVCCaps update VirtualChannel capabilities based on
// remote person's caps.
//
void RDPCALL SHCLASS SCUpdateVCCaps()
{
DC_BEGIN_FN("SCUpdateVCCaps");
PTS_VIRTUALCHANNEL_CAPABILITYSET pVcCaps = NULL;
//
//Determine if the client supports VC compression
//What we're determining here is that the client supports
//the server sending it compressed VC data. The capability in the
//other direction, i.e can the server send the client VC data
//is a capability the server exposes to the client and it may choose
//to then send compressed VC data to the server
//
pVcCaps = (PTS_VIRTUALCHANNEL_CAPABILITYSET)CPCGetCapabilities(
SC_REMOTE_PERSON_ID, TS_CAPSETTYPE_VIRTUALCHANNEL);
if(pVcCaps && (pVcCaps->vccaps1 & TS_VCCAPS_COMPRESSION_64K))
{
m_pTSWd->bClientSupportsVCCompression = TRUE;
TRC_NRM((TB, "Client supports VC compression"));
}
else
{
m_pTSWd->bClientSupportsVCCompression = FALSE;
TRC_NRM((TB, "Client doesn't support VC compression"));
}
DC_END_FN();
}