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.
1412 lines
34 KiB
1412 lines
34 KiB
/*++
|
|
|
|
Copyright (c) 1998-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
proc.cpp
|
|
|
|
Abstract:
|
|
|
|
This module contains shared code and protocol parsing functionality
|
|
for the port redirector dll in win32/wince environments.
|
|
|
|
Don't like the way server message clean up is handled.
|
|
There should be an object that wraps its way around a request packet
|
|
to automatically clean up. The current mechanism is prone to memory
|
|
leaks and dangling pointers. I would REALLY like to clean this up
|
|
because it WILL cause problems when we try to implement future
|
|
devices, but need to get approval from Madan, first.
|
|
|
|
See the old client's ProcObj::UpdateDriverName function for
|
|
how to handle making sure that if the driver name changes for cached
|
|
information, we whack the cached information.
|
|
|
|
Author:
|
|
|
|
madan appiah (madana) 16-Sep-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precom.h>
|
|
|
|
#define TRC_FILE "proc"
|
|
|
|
#include <winsock.h>
|
|
|
|
//
|
|
// Include the platform-specific classes.
|
|
//
|
|
#include "w32draut.h"
|
|
#include "w32drman.h"
|
|
#include "w32drlpt.h"
|
|
#include "w32drcom.h"
|
|
#include "w32proc.h"
|
|
#include "w32drdev.h"
|
|
#include "w32drive.h"
|
|
#if ((!defined(OS_WINCE)) || (!defined(WINCE_SDKBUILD)))
|
|
#include "w32scard.h"
|
|
#endif
|
|
|
|
#include "drconfig.h"
|
|
#include "drdbg.h"
|
|
|
|
#ifdef OS_WINCE
|
|
#include "filemgr.h"
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// ProcObj Data Members
|
|
//
|
|
|
|
//
|
|
// Device Enumeration Function Pointer List
|
|
//
|
|
// A function should be added for each class of device being
|
|
// redirected. There should be a separate instance of this
|
|
// array for each client platform.
|
|
//
|
|
RDPDeviceEnum ProcObj::_DeviceEnumFunctions[] =
|
|
{
|
|
#ifndef OS_WINCE
|
|
W32DrAutoPrn::Enumerate,
|
|
#endif
|
|
W32DrManualPrn::Enumerate,
|
|
W32DrCOM::Enumerate,
|
|
W32DrLPT::Enumerate,
|
|
W32Drive::Enumerate,
|
|
#if ((!defined(OS_WINCE)) || (!defined(WINCE_SDKBUILD)))
|
|
W32SCard::Enumerate
|
|
#endif
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// ProcObj Methods
|
|
//
|
|
|
|
ProcObj *ProcObj::Instantiate(VCManager *virtualChannelMgr)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create the correct instance of this class.
|
|
|
|
Arguments:
|
|
|
|
virtualChannelMgr - Associated Virtual Channel IO Manager
|
|
|
|
Return Value:
|
|
|
|
NULL if the object could not be created.
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("ProcObj::Instantiate");
|
|
|
|
TRC_NRM((TB, _T("Win9x, CE, or NT detected.")));
|
|
DC_END_FN();
|
|
return new W32ProcObj(virtualChannelMgr);
|
|
}
|
|
|
|
ProcObj::ProcObj(
|
|
IN VCManager *pVCM
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor
|
|
|
|
Arguments:
|
|
|
|
NA
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("ProcObj::ProcObj");
|
|
|
|
//
|
|
// Initialize Data Members
|
|
//
|
|
_pVCMgr = pVCM;
|
|
_sServerVersion.Major = 0;
|
|
_sServerVersion.Minor = 0;
|
|
_bDisableDeviceRedirection = FALSE;
|
|
_deviceMgr = NULL;
|
|
|
|
//
|
|
// Initialize the client capability set
|
|
// This is the capability set that we'll send to server
|
|
//
|
|
memcpy(&_cCapabilitySet, &CLIENT_CAPABILITY_SET_DEFAULT,
|
|
sizeof(CLIENT_CAPABILITY_SET_DEFAULT));
|
|
|
|
//
|
|
// Initialize the server capability set
|
|
// Once we receive the server side capability, we'll combine with our local
|
|
// capability and stores it.
|
|
//
|
|
memcpy(&_sCapabilitySet, &SERVER_CAPABILITY_SET_DEFAULT,
|
|
sizeof(SERVER_CAPABILITY_SET_DEFAULT));
|
|
|
|
//
|
|
//
|
|
// This instance has not yet been initialized.
|
|
//
|
|
_initialized = FALSE;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
ProcObj::~ProcObj()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor
|
|
|
|
Arguments:
|
|
|
|
NA
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DrDevice *dev;
|
|
|
|
DC_BEGIN_FN("ProcObj::~ProcObj");
|
|
|
|
//
|
|
// Clean up the device management list.
|
|
//
|
|
if (_deviceMgr != NULL) {
|
|
_deviceMgr->Lock();
|
|
while ((dev = _deviceMgr->GetFirstObject()) != NULL) {
|
|
_deviceMgr->RemoveObject(dev->GetID());
|
|
delete dev;
|
|
}
|
|
_deviceMgr->Unlock();
|
|
delete _deviceMgr;
|
|
}
|
|
|
|
#if (defined(OS_WINCE)) && (!defined(WINCE_SDKBUILD)) //delete this after all the devices in the device manager have been removed
|
|
if (gpCEFileMgr) {
|
|
gpCEFileMgr->Uninitialize();
|
|
delete gpCEFileMgr;
|
|
gpCEFileMgr = NULL;
|
|
}
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
ULONG
|
|
ProcObj::Initialize()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize an instance of this class.
|
|
|
|
Arguments:
|
|
|
|
NA
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS on success. Windows error status, otherwise.
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("ProcObj::Initialize");
|
|
DWORD result = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Fetch Configurable Variables.
|
|
//
|
|
GetDWordParameter(RDPDR_DISABLE_DR_PARAM, &_bDisableDeviceRedirection);
|
|
|
|
_deviceMgr = new DrDeviceMgr();
|
|
if (_deviceMgr == NULL) {
|
|
TRC_ERR((TB, L"Error allocating device manager."));
|
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
result = _deviceMgr->Initialize();
|
|
if (result != ERROR_SUCCESS) {
|
|
delete _deviceMgr;
|
|
_deviceMgr = NULL;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
#if (defined(OS_WINCE)) && (!defined(WINCE_SDKBUILD))
|
|
TRC_ASSERT((gpCEFileMgr == NULL), (TB, _T("gpCEFileMgr is not NULL")));
|
|
gpCEFileMgr = new CEFileMgr();
|
|
if (gpCEFileMgr) {
|
|
if (!gpCEFileMgr->Initialize()) {
|
|
delete gpCEFileMgr;
|
|
gpCEFileMgr = NULL;
|
|
}
|
|
}
|
|
|
|
if (!gpCEFileMgr) {
|
|
TRC_ERR((TB, _T("Memory allocation failed.")));
|
|
delete _deviceMgr;
|
|
_deviceMgr = NULL;
|
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
#endif
|
|
|
|
_initialized = TRUE;
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
DC_END_FN();
|
|
return result;
|
|
}
|
|
|
|
DWORD
|
|
ProcObj::DeviceEnumFunctionsCount()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the number of entries in the device enum function array.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
return(sizeof(_DeviceEnumFunctions) / sizeof(RDPDeviceEnum));
|
|
}
|
|
|
|
VOID
|
|
ProcObj::ProcessIORequestPacket(
|
|
PRDPDR_IOREQUEST_PACKET pIoRequestPacket,
|
|
UINT32 packetLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process an IO request packet.
|
|
|
|
Arguments:
|
|
|
|
pData - RDPDR packet as received by VC.
|
|
packetLen - length of the packet
|
|
|
|
Return Value:
|
|
|
|
TRUE - if the IO completed.
|
|
FALSE - if the IO pending and asynchronously completes.
|
|
|
|
--*/
|
|
{
|
|
PRDPDR_DEVICE_IOREQUEST pIoRequest = &pIoRequestPacket->IoRequest;
|
|
ULONG ulSize = 0;
|
|
|
|
DC_BEGIN_FN("ProcObj::ProcessIORequestPacket");
|
|
|
|
ASSERT(_initialized);
|
|
|
|
//
|
|
// Hand it to the proper device object.
|
|
//
|
|
DrDevice *device = _deviceMgr->GetObject(pIoRequest->DeviceId);
|
|
|
|
//
|
|
// If we have a device then hand off the object to handle the request.
|
|
//
|
|
if (device != NULL) {
|
|
device->ProcessIORequest(pIoRequestPacket, packetLen);
|
|
}
|
|
//
|
|
// Otherwise, clean up the server message because the transaction is
|
|
// complete.
|
|
//
|
|
// No response is sent to server.
|
|
//
|
|
else {
|
|
delete pIoRequestPacket;
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
VOID
|
|
ProcObj::ProcessServerPacket(
|
|
PVC_TX_DATA pData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses the protocol and delegates functionality to a whole horde of
|
|
overloaded functions.
|
|
|
|
This is the main entry point for all device-redirection related
|
|
operations.
|
|
|
|
Arguments:
|
|
|
|
pData - Data as received from the RDP Virtual Channel interface.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("ProcObj::Process");
|
|
|
|
PRDPDR_HEADER pRdpdrHeader;
|
|
|
|
ASSERT(_initialized);
|
|
|
|
//
|
|
// Get the header.
|
|
//
|
|
pRdpdrHeader = (PRDPDR_HEADER)(pData->pbData);
|
|
|
|
//
|
|
// Assert that it is valid.
|
|
//
|
|
ASSERT(IsValidHeader(pRdpdrHeader));
|
|
|
|
TRC_NRM((TB, _T("Processing component[%x], packetId[%x], ")
|
|
_T("component[%c%c], packetid[%c%c]."),
|
|
pRdpdrHeader->Component, pRdpdrHeader->PacketId,
|
|
HIBYTE(pRdpdrHeader->Component), LOBYTE(pRdpdrHeader->Component),
|
|
HIBYTE(pRdpdrHeader->PacketId),LOBYTE(pRdpdrHeader->PacketId))
|
|
);
|
|
|
|
//
|
|
// See if it's a CORE packet.
|
|
//
|
|
if (pRdpdrHeader->Component == RDPDR_CTYP_CORE) {
|
|
|
|
ProcessCoreServerPacket(pRdpdrHeader, pData->uiLength);
|
|
|
|
}
|
|
//
|
|
// If it's print-specific, hand it off to a static print-specific
|
|
// function. Ideally, this would have been handled transparently by
|
|
// having the server-side component send the message directly to the
|
|
// appropriate client-side object. The current protocol prohibits this,
|
|
// however.
|
|
//
|
|
else if( pRdpdrHeader->Component == RDPDR_CTYP_PRN ) {
|
|
|
|
switch (pRdpdrHeader->PacketId) {
|
|
|
|
case DR_PRN_CACHE_DATA : {
|
|
TRC_NRM((TB, _T("DR_CORE_DEVICE_CACHE_DATA")));
|
|
|
|
PRDPDR_PRINTER_CACHEDATA_PACKET pCachePacket;
|
|
pCachePacket = (PRDPDR_PRINTER_CACHEDATA_PACKET)pRdpdrHeader;
|
|
|
|
W32DrPRN::ProcessPrinterCacheInfo(pCachePacket, pData->uiLength);
|
|
break;
|
|
}
|
|
default: {
|
|
|
|
TRC_ALT((TB, _T("Invalid PacketID Issued, %ld."),
|
|
pRdpdrHeader->PacketId)
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// We don't recognize the packet. Close the channel.
|
|
GetVCMgr().ChannelClose();
|
|
delete pRdpdrHeader;
|
|
TRC_ALT((TB, _T("Unknown Component ID, %ld."), pRdpdrHeader->Component ));
|
|
}
|
|
|
|
DC_END_FN();
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ProcObj::ProcessCoreServerPacket(
|
|
PRDPDR_HEADER pRdpdrHeader,
|
|
UINT32 packetLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a "core" server packet.
|
|
|
|
Arguments:
|
|
|
|
rRdpdrHeader - Header for packet.
|
|
packetLen - Length of packet.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("ProcObj::ProcessCoreServerPacket");
|
|
|
|
ASSERT(_initialized);
|
|
|
|
//
|
|
// Switch on the packetID.
|
|
//
|
|
switch (pRdpdrHeader->PacketId) {
|
|
|
|
case DR_CORE_SERVER_ANNOUNCE : {
|
|
|
|
TRC_NRM((TB, _T("DR_CORE_SERVER_ANNOUNCE")));
|
|
|
|
//
|
|
// check to see we have a matching server.
|
|
//
|
|
if (packetLen != sizeof(RDPDR_SERVER_ANNOUNCE_PACKET) ) {
|
|
|
|
ASSERT(packetLen < sizeof(RDPDR_SERVER_ANNOUNCE_PACKET));
|
|
|
|
//
|
|
// we got a server announcement from an old version
|
|
// server that didn't have have any version info.
|
|
// simply return.
|
|
//
|
|
|
|
TRC_ERR((TB, _T("Mismatch server.")));
|
|
break;
|
|
}
|
|
|
|
MsgCoreAnnounce( (PRDPDR_SERVER_ANNOUNCE_PACKET)pRdpdrHeader );
|
|
|
|
break;
|
|
}
|
|
|
|
case DR_CORE_CLIENTID_CONFIRM : {
|
|
|
|
TRC_NRM((TB, _T("DR_CORE_CLIENTID_CONFIRM")));
|
|
|
|
//
|
|
// Send the client capability to the server if the server
|
|
// supports capability exchange
|
|
//
|
|
if (COMPARE_VERSION(_sServerVersion.Minor, _sServerVersion.Major,
|
|
5, 1) >= 0) {
|
|
AnnounceClientCapability();
|
|
}
|
|
|
|
//
|
|
// Send client computer display name if server supports it
|
|
//
|
|
AnnounceClientDisplayName();
|
|
|
|
// Don't announce devices if device redirection is disabled.
|
|
//
|
|
if (!_bDisableDeviceRedirection) {
|
|
//
|
|
// Announce redirected devices to the server via the subclass.
|
|
//
|
|
AnnounceDevicesToServer();
|
|
}
|
|
|
|
//
|
|
// Clean up the server message because the transaction is
|
|
// complete.
|
|
//
|
|
delete pRdpdrHeader;
|
|
break;
|
|
}
|
|
|
|
case DR_CORE_SERVER_CAPABILITY : {
|
|
TRC_NRM((TB, _T("DR_CORE_SERVER_CAPABILITY")));
|
|
//
|
|
// Received server capability set
|
|
//
|
|
OnServerCapability(pRdpdrHeader, packetLen);
|
|
|
|
//
|
|
// Cleanup the message because the transaction is complete
|
|
//
|
|
delete pRdpdrHeader;
|
|
|
|
break;
|
|
}
|
|
|
|
case DR_CORE_DEVICE_REPLY : {
|
|
|
|
TRC_NRM((TB, _T("DR_CORE_DEVICE_REPLY")));
|
|
|
|
PRDPDR_DEVICE_REPLY_PACKET pReply =
|
|
(PRDPDR_DEVICE_REPLY_PACKET)pRdpdrHeader;
|
|
|
|
TRC_NRM((TB, _T("Reply Device[0x%x], Code[0x%x]"),
|
|
pReply->DeviceReply.DeviceId,
|
|
pReply->DeviceReply.ResultCode)
|
|
);
|
|
|
|
//
|
|
// Clean up the server message because the transaction is
|
|
// complete.
|
|
//
|
|
delete pRdpdrHeader;
|
|
|
|
break;
|
|
}
|
|
|
|
case DR_CORE_DEVICELIST_REPLY : {
|
|
TRC_NRM((TB, _T("DR_CORE_DEVICELIST_REPLY")));
|
|
|
|
PRDPDR_DEVICE_REPLY_PACKET pReply =
|
|
(PRDPDR_DEVICE_REPLY_PACKET)pRdpdrHeader;
|
|
|
|
TRC_NRM((TB, _T("Reply Device[0x%x], Code[0x%x]"),
|
|
pReply->DeviceReply.DeviceId,
|
|
pReply->DeviceReply.ResultCode)
|
|
);
|
|
|
|
//
|
|
// Clean up the server message because the transaction is
|
|
// complete.
|
|
//
|
|
delete pRdpdrHeader;
|
|
|
|
break;
|
|
}
|
|
|
|
case DR_CORE_DEVICE_IOREQUEST : {
|
|
|
|
TRC_NRM((TB, _T("DR_CORE_DEVICE_IOREQUEST")));
|
|
|
|
// Make sure packetLen is at least sizeof(RDPDR_IOREQUEST_PACKET)
|
|
if (packetLen >= sizeof(RDPDR_IOREQUEST_PACKET)) {
|
|
ProcessIORequestPacket((PRDPDR_IOREQUEST_PACKET)pRdpdrHeader, packetLen);
|
|
|
|
TRC_NRM((TB, _T("MajorFunction processing completed.")));
|
|
}
|
|
else {
|
|
// VirtualChannelClose
|
|
GetVCMgr().ChannelClose();
|
|
TRC_ASSERT(FALSE, (TB, _T("Packet Length Error")));
|
|
delete pRdpdrHeader;
|
|
}
|
|
|
|
break; // DR_CORE_DEVICE_IOREQUEST
|
|
}
|
|
|
|
default: {
|
|
|
|
TRC_ALT((TB, _T("Invalid PacketID Issued, %ld."),
|
|
pRdpdrHeader->PacketId)
|
|
);
|
|
// We don't recognize the packet. Close the channel.
|
|
GetVCMgr().ChannelClose();
|
|
//
|
|
// Clean up the server message because the transaction is
|
|
// complete.
|
|
//
|
|
delete pRdpdrHeader;
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
VOID
|
|
ProcObj::MsgCoreAnnounce(
|
|
PRDPDR_SERVER_ANNOUNCE_PACKET pAnnounce
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processing for the Server Announce message. Generates and exports
|
|
the client confirmation as well as valid the device list.
|
|
|
|
Arguments:
|
|
|
|
pAnnounce - The data from the server minus the unnecessary headers.
|
|
|
|
Return Value:
|
|
|
|
Pointer to static function data containing the filename.
|
|
|
|
--*/
|
|
|
|
{
|
|
DrDevice *device;
|
|
|
|
DC_BEGIN_FN("ProcObj::MsgCoreAnnounce");
|
|
|
|
PRDPDR_CLIENT_CONFIRM_PACKET pClientConfirmPacket;
|
|
PRDPDR_CLIENT_NAME_PACKET pClientNamePacket;
|
|
|
|
ASSERT(_initialized);
|
|
|
|
//
|
|
// check server version info.
|
|
//
|
|
|
|
if( (pAnnounce->VersionInfo.Major != RDPDR_MAJOR_VERSION) ||
|
|
(pAnnounce->VersionInfo.Minor < 1) ) {
|
|
|
|
TRC_ERR((TB, _T("Server version mismatch.")));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Flush devices to make sure they don't have any outstanding IRPs
|
|
// from a previous connection
|
|
//
|
|
_deviceMgr->Lock();
|
|
|
|
device = _deviceMgr->GetFirstObject();
|
|
|
|
while (device != NULL) {
|
|
|
|
device->FlushIRPs();
|
|
device = _deviceMgr->GetNextObject();
|
|
}
|
|
|
|
_deviceMgr->Unlock();
|
|
|
|
//
|
|
// save server version number.
|
|
//
|
|
|
|
_sServerVersion = pAnnounce->VersionInfo;
|
|
|
|
pClientConfirmPacket = new RDPDR_CLIENT_CONFIRM_PACKET;
|
|
|
|
if (pClientConfirmPacket == NULL) {
|
|
TRC_ERR((TB, _T("Failed alloc memory.")));
|
|
goto Cleanup;
|
|
}
|
|
|
|
pClientConfirmPacket->Header.Component = RDPDR_CTYP_CORE;
|
|
pClientConfirmPacket->Header.PacketId = DR_CORE_CLIENTID_CONFIRM;
|
|
|
|
ULONG ulClientID;
|
|
ulClientID = GetClientID();
|
|
|
|
//
|
|
// fill in the client version info.
|
|
//
|
|
|
|
pClientConfirmPacket->VersionInfo.Major = RDPDR_MAJOR_VERSION;
|
|
pClientConfirmPacket->VersionInfo.Minor = RDPDR_MINOR_VERSION;
|
|
|
|
pClientConfirmPacket->ClientConfirm.ClientId =
|
|
( ulClientID != 0 ) ?
|
|
ulClientID :
|
|
pAnnounce->ServerAnnounce.ClientId;
|
|
|
|
//
|
|
// ulLen has the computer name length in bytes, add
|
|
// RDPDR_CLIENT_CONFIRM_PACKET structure size, to
|
|
// send just sufficient data.
|
|
//
|
|
|
|
_pVCMgr->ChannelWrite(pClientConfirmPacket, sizeof(RDPDR_CLIENT_CONFIRM_PACKET));
|
|
|
|
//
|
|
// now send the client computer name packet.
|
|
//
|
|
|
|
ULONG ulLen;
|
|
|
|
ulLen =
|
|
sizeof(RDPDR_CLIENT_NAME_PACKET) +
|
|
((MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR));
|
|
|
|
pClientNamePacket = (PRDPDR_CLIENT_NAME_PACKET) new BYTE[ulLen];
|
|
|
|
if (pClientNamePacket == NULL) {
|
|
TRC_ERR((TB, _T("Failed alloc memory.")));
|
|
goto Cleanup;
|
|
}
|
|
|
|
pClientNamePacket->Header.Component = RDPDR_CTYP_CORE;
|
|
pClientNamePacket->Header.PacketId = DR_CORE_CLIENT_NAME;
|
|
|
|
ulLen = ((MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR));
|
|
BOOL bUnicodeFlag;
|
|
|
|
GetClientComputerName(
|
|
(PBYTE)(pClientNamePacket + 1),
|
|
&ulLen,
|
|
&bUnicodeFlag,
|
|
&pClientNamePacket->Name.CodePage);
|
|
|
|
pClientNamePacket->Name.Unicode = (bUnicodeFlag) ? TRUE : FALSE;
|
|
pClientNamePacket->Name.ComputerNameLen = ulLen;
|
|
|
|
ulLen += sizeof(RDPDR_CLIENT_NAME_PACKET);
|
|
_pVCMgr->ChannelWrite(pClientNamePacket, (UINT)ulLen);
|
|
|
|
//
|
|
// don't free up the following buffers here, later a callback event from
|
|
// the VC will do so.
|
|
//
|
|
// - pClientConfirmPacket
|
|
// - pClientNamePacket
|
|
//
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Release the announce packet since the transaction is now complete.
|
|
//
|
|
delete pAnnounce;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
ULONG
|
|
ProcObj::GetClientID(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrive the client ID. Currently we send the IP address of the client machine
|
|
as its ID.
|
|
|
|
Assume : Winsock is startup.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
0 - if we can't find a unique client ID.
|
|
|
|
IP Address of the machine - otherwise.
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("ProcObj::GetClientID");
|
|
|
|
CHAR achHostName[MAX_PATH];
|
|
INT iRetVal;
|
|
ULONG ulClientID = 0;
|
|
HOSTENT *pHostent;
|
|
|
|
ASSERT(_initialized);
|
|
|
|
iRetVal = gethostname( (PCHAR)achHostName, sizeof(achHostName) );
|
|
|
|
if( iRetVal != 0 ) {
|
|
|
|
iRetVal = WSAGetLastError();
|
|
|
|
TRC_ERR((TB, _T("gethostname failed, %ld."), iRetVal));
|
|
goto Cleanup;
|
|
}
|
|
|
|
pHostent = gethostbyname( (PCHAR)achHostName );
|
|
|
|
if( pHostent == NULL ) {
|
|
|
|
iRetVal = WSAGetLastError();
|
|
|
|
TRC_ERR((TB, _T("gethostbyname() failed, %ld."), iRetVal));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// get the first address from the host ent.
|
|
//
|
|
|
|
ULONG *pAddr;
|
|
|
|
pAddr = (ULONG *)pHostent->h_addr_list[0];
|
|
|
|
if( pAddr != NULL ) {
|
|
ulClientID = *pAddr;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
DC_END_FN();
|
|
return ulClientID;
|
|
}
|
|
|
|
PRDPDR_HEADER
|
|
ProcObj::GenerateAnnouncePacket(
|
|
INT *piSize,
|
|
BOOL bCheckDeviceChange
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate a device announcement packet.
|
|
|
|
Arguments:
|
|
|
|
piSize - pointer to an integer variables where the size of the list is
|
|
returned.
|
|
|
|
Return Value:
|
|
|
|
pointer to a device announcement package.
|
|
NULL - if the list generation fails.
|
|
|
|
--*/
|
|
{
|
|
PRDPDR_HEADER pPacketHeader = NULL;
|
|
PRDPDR_DEVICELIST_ANNOUNCE pDeviceListAnnounce;
|
|
PRDPDR_DEVICE_ANNOUNCE pDeviceAnnounce;
|
|
ULONG ulDeviceCount;
|
|
ULONG announcePacketSize;
|
|
DrDevice *device;
|
|
|
|
DC_BEGIN_FN("ProcObj::GenerateAnnouncePacket");
|
|
|
|
ASSERT(_initialized);
|
|
|
|
//
|
|
// Lock the list of devices.
|
|
//
|
|
_deviceMgr->Lock();
|
|
|
|
//
|
|
// Calculate the number of bytes required for the announce packet.
|
|
//
|
|
announcePacketSize = sizeof(RDPDR_HEADER) + sizeof(RDPDR_DEVICELIST_ANNOUNCE);
|
|
device = _deviceMgr->GetFirstObject();
|
|
|
|
if (device == NULL) {
|
|
TRC_NRM((TB, _T("Zero devices found.")));
|
|
goto Cleanup;
|
|
}
|
|
|
|
while (device != NULL) {
|
|
|
|
if (!bCheckDeviceChange || device->_deviceChange == DEVICENEW) {
|
|
announcePacketSize += device->GetDevAnnounceDataSize();
|
|
}
|
|
|
|
device = _deviceMgr->GetNextObject();
|
|
}
|
|
|
|
//
|
|
// Allocate the announcement packet header.
|
|
//
|
|
pPacketHeader = (PRDPDR_HEADER)new BYTE[announcePacketSize];
|
|
if( pPacketHeader == NULL ) {
|
|
|
|
TRC_ERR((TB, _T("Memory Allocation failed.")));
|
|
goto Cleanup;
|
|
}
|
|
memset(pPacketHeader, 0, (size_t)announcePacketSize);
|
|
|
|
//
|
|
// Get pointers to the relevant packet header fields.
|
|
//
|
|
pDeviceListAnnounce = (PRDPDR_DEVICELIST_ANNOUNCE)(pPacketHeader + 1);
|
|
pDeviceAnnounce = (PRDPDR_DEVICE_ANNOUNCE)(pDeviceListAnnounce + 1);
|
|
|
|
//
|
|
// Have each device object add its own device announcement information.
|
|
//
|
|
PBYTE pbPacketEnd;
|
|
|
|
pbPacketEnd = ((PBYTE)pPacketHeader) + announcePacketSize;
|
|
|
|
ulDeviceCount = 0;
|
|
device = _deviceMgr->GetFirstObject();
|
|
while (device != NULL) {
|
|
|
|
if (!bCheckDeviceChange || device->_deviceChange == DEVICENEW) {
|
|
//
|
|
// Increment the device count.
|
|
//
|
|
ulDeviceCount++;
|
|
|
|
//
|
|
// Get the current devices data.
|
|
//
|
|
device->GetDevAnnounceData(pDeviceAnnounce);
|
|
|
|
device->_deviceChange = DEVICEANNOUCED;
|
|
|
|
//
|
|
// Move to the next location in the announce packet.
|
|
//
|
|
pDeviceAnnounce = (PRDPDR_DEVICE_ANNOUNCE)(
|
|
((PBYTE)pDeviceAnnounce) +
|
|
device->GetDevAnnounceDataSize()
|
|
);
|
|
}
|
|
|
|
//
|
|
// Get the next device.
|
|
//
|
|
device = _deviceMgr->GetNextObject();
|
|
}
|
|
|
|
//
|
|
// Record the device count to the device list announce header.
|
|
//
|
|
pDeviceListAnnounce->DeviceCount = ulDeviceCount;
|
|
|
|
//
|
|
// Return the size of the buffer.
|
|
//
|
|
*piSize = (INT)announcePacketSize;
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Unlock the device list.
|
|
//
|
|
_deviceMgr->Unlock();
|
|
|
|
TRC_NRM((TB, _T("Announcing %ld Devices."), ulDeviceCount));
|
|
|
|
|
|
|
|
//
|
|
// Return the buffer.
|
|
//
|
|
DC_END_FN();
|
|
return pPacketHeader;
|
|
}
|
|
|
|
PRDPDR_HEADER
|
|
ProcObj::GenerateDeviceRemovePacket(
|
|
INT *piSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate a device remove packet.
|
|
|
|
Arguments:
|
|
|
|
piSize - pointer to an integer variables where the size of the list is
|
|
returned.
|
|
|
|
Return Value:
|
|
|
|
pointer to a device remove package.
|
|
NULL - if the list generation fails.
|
|
|
|
--*/
|
|
{
|
|
PRDPDR_HEADER pPacketHeader = NULL;
|
|
PRDPDR_DEVICELIST_REMOVE pDeviceListRemove;
|
|
PRDPDR_DEVICE_REMOVE pDeviceRemove;
|
|
ULONG ulDeviceCount;
|
|
ULONG removePacketSize;
|
|
DrDevice *device;
|
|
|
|
DC_BEGIN_FN("ProcObj::GenerateDeviceRemovePacket");
|
|
|
|
ASSERT(_initialized);
|
|
|
|
//
|
|
// Lock the list of devices.
|
|
//
|
|
_deviceMgr->Lock();
|
|
|
|
//
|
|
// Calculate the number of bytes required for the announce packet.
|
|
//
|
|
removePacketSize = sizeof(RDPDR_HEADER) + sizeof(RDPDR_DEVICELIST_REMOVE);
|
|
|
|
device = _deviceMgr->GetFirstObject();
|
|
|
|
if (device == NULL) {
|
|
TRC_NRM((TB, _T("Zero devices found.")));
|
|
goto Cleanup;
|
|
}
|
|
|
|
ulDeviceCount = 0;
|
|
while (device != NULL) {
|
|
if (device->_deviceChange == DEVICEREMOVE) {
|
|
ulDeviceCount++;
|
|
}
|
|
device = _deviceMgr->GetNextObject();
|
|
}
|
|
|
|
//
|
|
// Didn't find any device to be removed
|
|
//
|
|
if (ulDeviceCount == 0) {
|
|
TRC_NRM((TB, _T("Zero device for removal")));
|
|
goto Cleanup;
|
|
}
|
|
|
|
removePacketSize += ulDeviceCount * sizeof(RDPDR_DEVICE_REMOVE);
|
|
|
|
//
|
|
// Allocate the announcement packet header.
|
|
//
|
|
pPacketHeader = (PRDPDR_HEADER)new BYTE[removePacketSize];
|
|
if( pPacketHeader == NULL ) {
|
|
|
|
TRC_ERR((TB, _T("Memory Allocation failed.")));
|
|
goto Cleanup;
|
|
}
|
|
memset(pPacketHeader, 0, (size_t)removePacketSize);
|
|
|
|
//
|
|
// Get pointers to the relevant packet header fields.
|
|
//
|
|
pDeviceListRemove = (PRDPDR_DEVICELIST_REMOVE)(pPacketHeader + 1);
|
|
pDeviceRemove = (PRDPDR_DEVICE_REMOVE)(pDeviceListRemove + 1);
|
|
|
|
//
|
|
// Have each device object add its own device remove information.
|
|
//
|
|
ulDeviceCount = 0;
|
|
device = _deviceMgr->GetFirstObject();
|
|
while (device != NULL) {
|
|
|
|
if (device->_deviceChange == DEVICEREMOVE) {
|
|
//
|
|
// Increment the device count.
|
|
//
|
|
ulDeviceCount++;
|
|
|
|
//
|
|
// Get the current devices data.
|
|
//
|
|
pDeviceRemove->DeviceId = device->GetID();
|
|
|
|
//
|
|
// Move to the next location in the announce packet.
|
|
//
|
|
pDeviceRemove++;
|
|
}
|
|
|
|
//
|
|
// Get the next device.
|
|
//
|
|
device = _deviceMgr->GetNextObject();
|
|
}
|
|
|
|
//
|
|
// Record the device count to the device list announce header.
|
|
//
|
|
pDeviceListRemove->DeviceCount = ulDeviceCount;
|
|
|
|
//
|
|
// Return the size of the buffer.
|
|
//
|
|
*piSize = (INT)removePacketSize;
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Unlock the device list.
|
|
//
|
|
_deviceMgr->Unlock();
|
|
|
|
TRC_NRM((TB, _T("Removing %ld Devices."), ulDeviceCount));
|
|
|
|
//
|
|
// Return the buffer.
|
|
//
|
|
DC_END_FN();
|
|
return pPacketHeader;
|
|
}
|
|
|
|
VOID ProcObj::AnnounceClientCapability()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate a client capability set announcement packet.
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
OSVERSIONINFO OsVersionInfo;
|
|
PRDPDR_CLIENT_COMBINED_CAPABILITYSET pClientCapSet;
|
|
|
|
DC_BEGIN_FN("ProcObj::AnnounceClientCapability");
|
|
|
|
//
|
|
// Setup the client OS version
|
|
//
|
|
OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
if (GetVersionEx(&OsVersionInfo)) {
|
|
_cCapabilitySet.GeneralCap.osType = OsVersionInfo.dwPlatformId;
|
|
|
|
//
|
|
// Setup the client OS type
|
|
//
|
|
switch (_cCapabilitySet.GeneralCap.osType) {
|
|
case VER_PLATFORM_WIN32_WINDOWS:
|
|
_cCapabilitySet.GeneralCap.osType = RDPDR_OS_TYPE_WIN9X;
|
|
break;
|
|
|
|
case VER_PLATFORM_WIN32_NT:
|
|
_cCapabilitySet.GeneralCap.osType = RDPDR_OS_TYPE_WINNT;
|
|
break;
|
|
|
|
case VER_PLATFORM_WIN32s:
|
|
ASSERT(FALSE);
|
|
break;
|
|
|
|
default:
|
|
_cCapabilitySet.GeneralCap.osType = RDPDR_OS_TYPE_UNKNOWN;
|
|
}
|
|
|
|
//
|
|
// Setup the client OS version
|
|
//
|
|
_cCapabilitySet.GeneralCap.osVersion =
|
|
MAKELONG(OsVersionInfo.dwMinorVersion, OsVersionInfo.dwMajorVersion);
|
|
|
|
//
|
|
// Since win9x doesn't support security, we don't adversise these IRPs
|
|
//
|
|
if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
|
|
_cCapabilitySet.GeneralCap.ioCode1 &= ~RDPDR_IRP_MJ_QUERY_SECURITY;
|
|
_cCapabilitySet.GeneralCap.ioCode1 &= ~RDPDR_IRP_MJ_SET_SECURITY;
|
|
}
|
|
}
|
|
|
|
pClientCapSet = (PRDPDR_CLIENT_COMBINED_CAPABILITYSET) new
|
|
BYTE[sizeof(RDPDR_CLIENT_COMBINED_CAPABILITYSET)];
|
|
|
|
if (pClientCapSet != NULL) {
|
|
|
|
memcpy(pClientCapSet, &_cCapabilitySet, sizeof(_cCapabilitySet));
|
|
//
|
|
// Send the client capability to the server
|
|
//
|
|
_pVCMgr->ChannelWrite(pClientCapSet, sizeof(_cCapabilitySet));
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
void ProcObj::AnnounceClientDisplayName()
|
|
{
|
|
PRDPDR_CLIENT_DISPLAY_NAME_PACKET pClientDisplayNamePDU;
|
|
unsigned ClientDisplayNameLen;
|
|
WCHAR ClientDisplayName[RDPDR_MAX_CLIENT_DISPLAY_NAME];
|
|
|
|
DC_BEGIN_FN("ProcObj::AnnounceClientDisplayName");
|
|
|
|
ClientDisplayNameLen = 0;
|
|
ClientDisplayName[0] = L'\0';
|
|
|
|
if (_sCapabilitySet.GeneralCap.extendedPDU & RDPDR_CLIENT_DISPLAY_NAME_PDU) {
|
|
|
|
//
|
|
// TODO: Need to use shell API to get client display name
|
|
//
|
|
// ClientDisplayNameLen = (wcslen(ClientDisplayName) + 1) * sizeof(WCHAR);
|
|
|
|
if (ClientDisplayNameLen) {
|
|
|
|
pClientDisplayNamePDU = (PRDPDR_CLIENT_DISPLAY_NAME_PACKET) new
|
|
BYTE[sizeof(RDPDR_CLIENT_DISPLAY_NAME_PACKET) + ClientDisplayNameLen];
|
|
|
|
if (pClientDisplayNamePDU != NULL) {
|
|
pClientDisplayNamePDU->Header.Component = RDPDR_CTYP_CORE;
|
|
pClientDisplayNamePDU->Header.PacketId = DR_CORE_CLIENT_DISPLAY_NAME;
|
|
|
|
pClientDisplayNamePDU->Name.ComputerDisplayNameLen = (BYTE)ClientDisplayNameLen;
|
|
|
|
memcpy(pClientDisplayNamePDU + 1, ClientDisplayName, ClientDisplayNameLen);
|
|
|
|
//
|
|
// Send the client capability to the server
|
|
//
|
|
_pVCMgr->ChannelWrite(pClientDisplayNamePDU, sizeof(RDPDR_CLIENT_DISPLAY_NAME_PACKET) +
|
|
ClientDisplayNameLen);
|
|
}
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
BOOL ProcObj::InitServerCapability(PRDPDR_CAPABILITY_HEADER pCapHdr, PBYTE packetLimit)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
On receiving server capability set, initialize it with the
|
|
local default server capability set.
|
|
|
|
Arguments:
|
|
|
|
pCapHdr - Capability from the server
|
|
|
|
Return Value:
|
|
|
|
TRUE - if the server capability exists locally
|
|
FALSE - if the local client doesn't support this capability
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL rc = FALSE;
|
|
//
|
|
// Check the packet for minimum sizes
|
|
//
|
|
if ((PBYTE)(pCapHdr + 1) > packetLimit) {
|
|
return rc;
|
|
}
|
|
|
|
switch(pCapHdr->capabilityType) {
|
|
|
|
case RDPDR_GENERAL_CAPABILITY_TYPE:
|
|
{
|
|
PRDPDR_GENERAL_CAPABILITY pGeneralCap = (PRDPDR_GENERAL_CAPABILITY)pCapHdr;
|
|
//
|
|
// Check the packet data size for this type.
|
|
// For the remaining, the above check will suffice.
|
|
//
|
|
if ((PBYTE)(pGeneralCap+1) <= packetLimit) {
|
|
_sCapabilitySet.GeneralCap.version = pGeneralCap->version;
|
|
_sCapabilitySet.GeneralCap.osType = pGeneralCap->osType;
|
|
_sCapabilitySet.GeneralCap.osVersion = pGeneralCap->osVersion;
|
|
_sCapabilitySet.GeneralCap.ioCode1 = pGeneralCap->ioCode1;
|
|
_sCapabilitySet.GeneralCap.extendedPDU = pGeneralCap->extendedPDU;
|
|
_sCapabilitySet.GeneralCap.protocolMajorVersion = pGeneralCap->protocolMajorVersion;
|
|
_sCapabilitySet.GeneralCap.protocolMinorVersion = pGeneralCap->protocolMinorVersion;
|
|
rc = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RDPDR_PRINT_CAPABILITY_TYPE:
|
|
{
|
|
PRDPDR_PRINT_CAPABILITY pPrintCap = (PRDPDR_PRINT_CAPABILITY)pCapHdr;
|
|
_sCapabilitySet.PrintCap.version = pPrintCap->version;
|
|
rc = TRUE;
|
|
}
|
|
break;
|
|
|
|
case RDPDR_PORT_CAPABILITY_TYPE:
|
|
{
|
|
PRDPDR_PORT_CAPABILITY pPortCap = (PRDPDR_PORT_CAPABILITY)pCapHdr;
|
|
_sCapabilitySet.PortCap.version = pPortCap->version;
|
|
rc = TRUE;
|
|
}
|
|
break;
|
|
|
|
case RDPDR_FS_CAPABILITY_TYPE:
|
|
{
|
|
PRDPDR_FS_CAPABILITY pFsCap = (PRDPDR_FS_CAPABILITY)pCapHdr;
|
|
_sCapabilitySet.FileSysCap.version = pFsCap->version;
|
|
rc = TRUE;
|
|
}
|
|
break;
|
|
|
|
case RDPDR_SMARTCARD_CAPABILITY_TYPE:
|
|
{
|
|
PRDPDR_SMARTCARD_CAPABILITY pSmartCardCap = (PRDPDR_SMARTCARD_CAPABILITY)pCapHdr;
|
|
_sCapabilitySet.SmartCardCap.version = pSmartCardCap->version;
|
|
rc = TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rc = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
VOID ProcObj::OnServerCapability(PRDPDR_HEADER pRdpdrHeader, ULONG maxDataLength)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
On receiving server capability set.
|
|
|
|
Arguments:
|
|
|
|
pRdpdrHeader - Capability Set from the server
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
|
|
{
|
|
DC_BEGIN_FN("ProcObj::OnServerCapability");
|
|
//
|
|
// Validate data lengths
|
|
//
|
|
PBYTE packetLimit = ((PBYTE)pRdpdrHeader) + maxDataLength;
|
|
|
|
if (maxDataLength < sizeof(RDPDR_CAPABILITY_SET_HEADER)) {
|
|
TRC_ASSERT(FALSE,
|
|
(TB, _T("Server Capability Header Packet Length Error")));
|
|
TRC_ERR((TB, _T("Invalid Data Length for Server Capability Header")));
|
|
return;
|
|
}
|
|
|
|
|
|
PRDPDR_CAPABILITY_SET_HEADER pCapSetHeader = (PRDPDR_CAPABILITY_SET_HEADER)pRdpdrHeader;
|
|
PRDPDR_CAPABILITY_HEADER pCapHdr = (PRDPDR_CAPABILITY_HEADER)(pCapSetHeader + 1);
|
|
|
|
//
|
|
// Grab the supported capability info from server's capability PDU
|
|
//
|
|
for (unsigned i = 0; i < pCapSetHeader->numberCapabilities; i++) {
|
|
if (InitServerCapability(pCapHdr, packetLimit)) {
|
|
pCapHdr = (PRDPDR_CAPABILITY_HEADER)(((PBYTE)pCapHdr) + pCapHdr->capabilityLength);
|
|
}
|
|
else {
|
|
TRC_ASSERT(FALSE,
|
|
(TB, _T("Server Capability Packet Length Error")));
|
|
TRC_ERR((TB, _T("Invalid Data Length for Server Capability.")));
|
|
_pVCMgr->ChannelClose();
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|