WindowsXP-SP1/termsrv/remdsk/server/rdhost/tsrdpremotedesktopsession.cpp
2020-09-30 16:53:49 +02:00

540 lines
12 KiB
C++

/*++
Copyright (c) 1999-2000 Microsoft Corporation
Module Name:
TSRDPRemoteDesktopSession
Abstract:
This is the TS/RDP implementation of the Remote Desktop Session class.
The Remote Desktop Session class defines functions that define
pluggable C++ interface for remote desktop access, by abstracting
the implementation specific details of remote desktop access for the
server-side into the following C++ methods:
Author:
Tad Brockway 02/00
Revision History:
--*/
#include <RemoteDesktop.h>
#include "stdafx.h"
#ifdef TRC_FILE
#undef TRC_FILE
#endif
#define TRC_FILE "_tsrdss"
#include <RDSHost.h>
#include "TSRDPRemoteDesktopSession.h"
#include "TSRDPServerDataChannelMgr.h"
#include <RemoteDesktopChannels.h>
#include "RemoteDesktopUtils.h"
#include <Sddl.h>
#include <windows.h>
///////////////////////////////////////////////////////
//
// CTSRDPRemoteDesktopSession Methods
//
CTSRDPRemoteDesktopSession::CTSRDPRemoteDesktopSession() :
m_ChannelMgr(NULL)
/*++
Routine Description:
Constructor
Arguments:
Return Value:
None.
--*/
{
DC_BEGIN_FN("CTSRDPRemoteDesktopSession::CTSRDPRemoteDesktopSession");
DC_END_FN();
}
CTSRDPRemoteDesktopSession::~CTSRDPRemoteDesktopSession()
/*++
Routine Description:
Destructor
Arguments:
Return Value:
None.
--*/
{
DC_BEGIN_FN("CTSRDPRemoteDesktopSession::~CTSRDPRemoteDesktopSession");
Shutdown();
DC_END_FN();
}
HRESULT
CTSRDPRemoteDesktopSession::Initialize(
BSTR connectParms,
CRemoteDesktopServerHost *hostObject,
REMOTE_DESKTOP_SHARING_CLASS sharingClass,
BOOL bEnableCallback,
DWORD timeOut,
BSTR userHelpCreateBlob,
LONG tsSessionID,
BSTR userSID
)
/*++
Routine Description:
The Initialize method prepares the COM object for connection by
the client-side Remote Desktop Host ActiveX Control.
Arguments:
connectParms - If parms are non-NULL, then the session already exists.
Otherwise, a new session should be created.
hostObject - Back pointer to containing RDS Host object.
sharingClass - Level of desktop sharing for a new session.
callbackCLSID - Callback object class ID for a new session.
timeOut - Help session timeout value. 0, if not specified.
userHelpCreateBlob - user specific help session create blob.
tsSessionID - Terminal Services Session ID or -1 if
undefined.
userSID - User SID or "" if undefined.
Return Value:
S_OK on success. Otherwise, an error code is returned.
--*/
{
DC_BEGIN_FN("CTSRDPRemoteDesktopSession::Initialize");
WSADATA wsData;
CComBSTR helpAccountName;
CComBSTR helpSessionID;
HANDLE tokenHandle;
PTOKEN_USER tokenUser = NULL;
HRESULT hr = S_OK;
CComBSTR tmpBstr;
LPTSTR sidStr;
//
// Make a copy of connect parms.
//
m_ConnectParms = connectParms;
//
// Get our session ID if one is not provided.
//
if (tsSessionID != -1) {
m_SessionID = tsSessionID;
}
else {
if (!ProcessIdToSessionId(GetCurrentProcessId(), &m_SessionID)) {
hr = HRESULT_FROM_WIN32(GetLastError());
TRC_ERR((TB, TEXT("Error fetching session ID: %08X."),
GetLastError()));
goto CLEANUPANDEXIT;
}
}
//
// If we didn't get a SID, use our SID.
//
UINT len = SysStringByteLen(userSID);
if (len == 0) {
hr = FetchOurTokenUser(&tokenUser);
if (hr != S_OK) {
goto CLEANUPANDEXIT;
}
userSID = NULL;
//
// Copy the user SID into a BSTR.
//
if (!ConvertSidToStringSid(tokenUser->User.Sid, &sidStr)) {
hr = HRESULT_FROM_WIN32(GetLastError());
TRC_ERR((TB, L"ConvertSidToStringSid: %08X", hr));
goto CLEANUPANDEXIT;
}
tmpBstr = sidStr;
}
//
// Give the parent class a chance to initialize.
//
hr = CRemoteDesktopSession::Initialize(
connectParms, hostObject,
sharingClass,
bEnableCallback,
timeOut,
userHelpCreateBlob,
m_SessionID,
(userSID != NULL) ? userSID : tmpBstr
);
if (!SUCCEEDED(hr)) {
goto CLEANUPANDEXIT;
}
#if 0
// WinSock is initialize as main(), we need to keep code here so
// when we move from EXE to DLL, need to un-comment this
//
// Need to initialize winsock to get our host name.
//
if (WSAStartup(0x0101, &wsData) != 0) {
TRC_ERR((TB, TEXT("WSAStartup: %08X"), WSAGetLastError()));
hr = HRESULT_FROM_WIN32(WSAGetLastError());
goto CLEANUPANDEXIT;
}
#endif
//
// Instantiate the channel manager object and store in the parent
// class.
//
m_ChannelMgr = new CComObject<CTSRDPServerChannelMgr>();
if (m_ChannelMgr == NULL) {
TRC_ERR((TB, TEXT("Error instantiating channel manager.")));
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
goto CLEANUPANDEXIT;
}
m_ChannelMgr->AddRef();
//
// Get the help account name.
//
hr = m_HelpSession->get_AssistantAccountName(&helpAccountName);
if (!SUCCEEDED(hr)) {
TRC_ERR((TB, L"get_AssistantAccountName: %08X", hr));
goto CLEANUPANDEXIT;
}
//
// Get the help session ID.
//
hr = m_HelpSession->get_HelpSessionId(&helpSessionID);
if (!SUCCEEDED(hr)) {
TRC_ERR((TB, L"get_HelpSessionId: %08X", hr));
goto CLEANUPANDEXIT;
}
//
// Initialize the channel mnager
//
hr = m_ChannelMgr->Initialize(this, helpSessionID);
if (hr != S_OK) {
goto CLEANUPANDEXIT;
}
CLEANUPANDEXIT:
if (tokenUser != NULL) {
LocalFree(tokenUser);
}
SetValid(SUCCEEDED(hr));
DC_END_FN();
return hr;
}
STDMETHODIMP
CTSRDPRemoteDesktopSession::Disconnect()
/*++
Routine Description:
Force a disconnect of the currently connected client,
if one is connected.
Arguments:
Return Value:
S_OK on success. Otherwise, an error code is returned.
--*/
{
DC_BEGIN_FN("CTSRDPRemoteDesktopSession::Disconnect");
if (m_ChannelMgr != NULL) {
m_ChannelMgr->Disconnect();
}
DC_END_FN();
return S_OK;
}
void
CTSRDPRemoteDesktopSession::Shutdown()
/*++
Routine Description:
Final Initialization
Arguments:
Return Value:
S_OK on success. Otherwise, an error code is returned.
--*/
{
DC_BEGIN_FN("CTSRDPRemoteDesktopSession::Shutdown");
//
// Tell the channel manager to stop listening for data so it can
// shut down when its ref count goes to 0. And, decrement its
// ref count.
//
if (m_ChannelMgr != NULL) {
m_ChannelMgr->StopListening();
m_ChannelMgr->Release();
m_ChannelMgr = NULL;
}
DC_END_FN();
}
STDMETHODIMP
CTSRDPRemoteDesktopSession::get_ConnectParms(
OUT BSTR *parms
)
/*++
Routine Description:
Return parms that can be used to connect from the ActiveX client
control.
Arguments:
parms - Parms returned here.
Return Value:
--*/
{
DC_BEGIN_FN("CTSRDPRemoteDesktopSession::get_ConnectParms");
HRESULT hr = S_OK;
//
// If we are not valid, fail.
//
if (!IsValid()) {
hr = E_FAIL;
ASSERT(FALSE);
goto CLEANUPANDEXIT;
}
// Always get latest connect parm again, IP address might
// change
hr = m_HelpSession->get_ConnectParms( parms );
CLEANUPANDEXIT:
DC_END_FN();
return hr;
}
VOID
CTSRDPRemoteDesktopSession::GetSessionName(
CComBSTR &name
)
/*++
Routine Description:
Return a string representation for the session.
Arguments:
Return Value:
--*/
{
DC_BEGIN_FN("CTSRDPRemoteDesktopSession::GetSessionName");
WCHAR buf[256];
ASSERT(IsValid());
wsprintf(buf, L"TSRDP%ld", m_SessionID);
name = buf;
DC_END_FN();
}
VOID
CTSRDPRemoteDesktopSession::GetSessionDescription(
CComBSTR &descr
)
{
GetSessionName(descr);
}
HRESULT
CTSRDPRemoteDesktopSession::FetchOurTokenUser(
PTOKEN_USER *tokenUser
)
/*++
Routine Description:
Fetch our Token User struct.
Arguments:
tokenUser - Returned token user for this thread. Should
be freed using LocalFree.
Return Value:
S_OK on success. An error HRESULT otherwise.
--*/
{
HRESULT hr = S_OK;
ULONG bufferLength;
HANDLE tokenHandle = NULL;
DC_BEGIN_FN("CTSRDPRemoteDesktopSession::FetchOurTokenUser");
*tokenUser = NULL;
//
// Get our process token.
//
if (!OpenProcessToken(
GetCurrentProcess(),
TOKEN_QUERY,
&tokenHandle
)) {
hr = HRESULT_FROM_WIN32(GetLastError());
TRC_ERR((TB, L"OpenThreadToken: %08X", hr));
goto CLEANUPANDEXIT;
}
//
// Fetch our Token User struct.
//
bufferLength = 0;
GetTokenInformation(
tokenHandle,
TokenUser,
NULL,
0,
&bufferLength
);
if (bufferLength == 0) {
hr = HRESULT_FROM_WIN32(GetLastError());
TRC_ERR((TB, L"OpenThreadToken: %08X", hr));
goto CLEANUPANDEXIT;
}
*tokenUser = (PTOKEN_USER)LocalAlloc(LPTR, bufferLength);
if (*tokenUser == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
TRC_ERR((TB, L"LocalAlloc: %08X", GetLastError()));
goto CLEANUPANDEXIT;
}
if (!GetTokenInformation(
tokenHandle,
TokenUser,
*tokenUser,
bufferLength,
&bufferLength
)) {
hr = HRESULT_FROM_WIN32(GetLastError());
LocalFree(*tokenUser);
*tokenUser = NULL;
}
CLEANUPANDEXIT:
if (tokenHandle != NULL) {
CloseHandle(tokenHandle);
}
DC_END_FN();
return hr;
}
HRESULT CTSRDPRemoteDesktopSession::StartListening()
/*++
Routine Description:
Start listening
Should be called everytime the client disconnects and everytime we open
a remote desktop session
This is because the named pipe would have been closed in the disconnect
Return Value:
S_OK on success. An error HRESULT otherwise.
--*/
{
DC_BEGIN_FN("CTSRDPRemoteDesktopSession::StartListening");
HRESULT hr = E_FAIL;
CComBSTR helpAccountName;
//
// Tell the channel manager to start listening
//
if (m_ChannelMgr != NULL) {
//
// Get the help account name.
//
hr = m_HelpSession->get_AssistantAccountName(&helpAccountName);
if (!SUCCEEDED(hr)) {
TRC_ERR((TB, L"get_AssistantAccountName: %08X", hr));
goto CLEANUPANDEXIT;
}
hr = m_ChannelMgr->StartListening(helpAccountName);
}
DC_END_FN();
CLEANUPANDEXIT:
return hr;
}