Source code of Windows XP (NT5)
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.

539 lines
11 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. TSRDPRemoteDesktopSession
  5. Abstract:
  6. This is the TS/RDP implementation of the Remote Desktop Session class.
  7. The Remote Desktop Session class defines functions that define
  8. pluggable C++ interface for remote desktop access, by abstracting
  9. the implementation specific details of remote desktop access for the
  10. server-side into the following C++ methods:
  11. Author:
  12. Tad Brockway 02/00
  13. Revision History:
  14. --*/
  15. #include <RemoteDesktop.h>
  16. #include "stdafx.h"
  17. #ifdef TRC_FILE
  18. #undef TRC_FILE
  19. #endif
  20. #define TRC_FILE "_tsrdss"
  21. #include <RDSHost.h>
  22. #include "TSRDPRemoteDesktopSession.h"
  23. #include "TSRDPServerDataChannelMgr.h"
  24. #include <RemoteDesktopChannels.h>
  25. #include "RemoteDesktopUtils.h"
  26. #include <Sddl.h>
  27. #include <windows.h>
  28. ///////////////////////////////////////////////////////
  29. //
  30. // CTSRDPRemoteDesktopSession Methods
  31. //
  32. CTSRDPRemoteDesktopSession::CTSRDPRemoteDesktopSession() :
  33. m_ChannelMgr(NULL)
  34. /*++
  35. Routine Description:
  36. Constructor
  37. Arguments:
  38. Return Value:
  39. None.
  40. --*/
  41. {
  42. DC_BEGIN_FN("CTSRDPRemoteDesktopSession::CTSRDPRemoteDesktopSession");
  43. DC_END_FN();
  44. }
  45. CTSRDPRemoteDesktopSession::~CTSRDPRemoteDesktopSession()
  46. /*++
  47. Routine Description:
  48. Destructor
  49. Arguments:
  50. Return Value:
  51. None.
  52. --*/
  53. {
  54. DC_BEGIN_FN("CTSRDPRemoteDesktopSession::~CTSRDPRemoteDesktopSession");
  55. Shutdown();
  56. DC_END_FN();
  57. }
  58. HRESULT
  59. CTSRDPRemoteDesktopSession::Initialize(
  60. BSTR connectParms,
  61. CRemoteDesktopServerHost *hostObject,
  62. REMOTE_DESKTOP_SHARING_CLASS sharingClass,
  63. BOOL bEnableCallback,
  64. DWORD timeOut,
  65. BSTR userHelpCreateBlob,
  66. LONG tsSessionID,
  67. BSTR userSID
  68. )
  69. /*++
  70. Routine Description:
  71. The Initialize method prepares the COM object for connection by
  72. the client-side Remote Desktop Host ActiveX Control.
  73. Arguments:
  74. connectParms - If parms are non-NULL, then the session already exists.
  75. Otherwise, a new session should be created.
  76. hostObject - Back pointer to containing RDS Host object.
  77. sharingClass - Level of desktop sharing for a new session.
  78. callbackCLSID - Callback object class ID for a new session.
  79. timeOut - Help session timeout value. 0, if not specified.
  80. userHelpCreateBlob - user specific help session create blob.
  81. tsSessionID - Terminal Services Session ID or -1 if
  82. undefined.
  83. userSID - User SID or "" if undefined.
  84. Return Value:
  85. S_OK on success. Otherwise, an error code is returned.
  86. --*/
  87. {
  88. DC_BEGIN_FN("CTSRDPRemoteDesktopSession::Initialize");
  89. WSADATA wsData;
  90. CComBSTR helpAccountName;
  91. CComBSTR helpSessionID;
  92. HANDLE tokenHandle;
  93. PTOKEN_USER tokenUser = NULL;
  94. HRESULT hr = S_OK;
  95. CComBSTR tmpBstr;
  96. LPTSTR sidStr;
  97. //
  98. // Make a copy of connect parms.
  99. //
  100. m_ConnectParms = connectParms;
  101. //
  102. // Get our session ID if one is not provided.
  103. //
  104. if (tsSessionID != -1) {
  105. m_SessionID = tsSessionID;
  106. }
  107. else {
  108. if (!ProcessIdToSessionId(GetCurrentProcessId(), &m_SessionID)) {
  109. hr = HRESULT_FROM_WIN32(GetLastError());
  110. TRC_ERR((TB, TEXT("Error fetching session ID: %08X."),
  111. GetLastError()));
  112. goto CLEANUPANDEXIT;
  113. }
  114. }
  115. //
  116. // If we didn't get a SID, use our SID.
  117. //
  118. UINT len = SysStringByteLen(userSID);
  119. if (len == 0) {
  120. hr = FetchOurTokenUser(&tokenUser);
  121. if (hr != S_OK) {
  122. goto CLEANUPANDEXIT;
  123. }
  124. userSID = NULL;
  125. //
  126. // Copy the user SID into a BSTR.
  127. //
  128. if (!ConvertSidToStringSid(tokenUser->User.Sid, &sidStr)) {
  129. hr = HRESULT_FROM_WIN32(GetLastError());
  130. TRC_ERR((TB, L"ConvertSidToStringSid: %08X", hr));
  131. goto CLEANUPANDEXIT;
  132. }
  133. tmpBstr = sidStr;
  134. }
  135. //
  136. // Give the parent class a chance to initialize.
  137. //
  138. hr = CRemoteDesktopSession::Initialize(
  139. connectParms, hostObject,
  140. sharingClass,
  141. bEnableCallback,
  142. timeOut,
  143. userHelpCreateBlob,
  144. m_SessionID,
  145. (userSID != NULL) ? userSID : tmpBstr
  146. );
  147. if (!SUCCEEDED(hr)) {
  148. goto CLEANUPANDEXIT;
  149. }
  150. #if 0
  151. // WinSock is initialize as main(), we need to keep code here so
  152. // when we move from EXE to DLL, need to un-comment this
  153. //
  154. // Need to initialize winsock to get our host name.
  155. //
  156. if (WSAStartup(0x0101, &wsData) != 0) {
  157. TRC_ERR((TB, TEXT("WSAStartup: %08X"), WSAGetLastError()));
  158. hr = HRESULT_FROM_WIN32(WSAGetLastError());
  159. goto CLEANUPANDEXIT;
  160. }
  161. #endif
  162. //
  163. // Instantiate the channel manager object and store in the parent
  164. // class.
  165. //
  166. m_ChannelMgr = new CComObject<CTSRDPServerChannelMgr>();
  167. if (m_ChannelMgr == NULL) {
  168. TRC_ERR((TB, TEXT("Error instantiating channel manager.")));
  169. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  170. goto CLEANUPANDEXIT;
  171. }
  172. m_ChannelMgr->AddRef();
  173. //
  174. // Get the help account name.
  175. //
  176. hr = m_HelpSession->get_AssistantAccountName(&helpAccountName);
  177. if (!SUCCEEDED(hr)) {
  178. TRC_ERR((TB, L"get_AssistantAccountName: %08X", hr));
  179. goto CLEANUPANDEXIT;
  180. }
  181. //
  182. // Get the help session ID.
  183. //
  184. hr = m_HelpSession->get_HelpSessionId(&helpSessionID);
  185. if (!SUCCEEDED(hr)) {
  186. TRC_ERR((TB, L"get_HelpSessionId: %08X", hr));
  187. goto CLEANUPANDEXIT;
  188. }
  189. //
  190. // Initialize the channel mnager
  191. //
  192. hr = m_ChannelMgr->Initialize(this, helpSessionID);
  193. if (hr != S_OK) {
  194. goto CLEANUPANDEXIT;
  195. }
  196. CLEANUPANDEXIT:
  197. if (tokenUser != NULL) {
  198. LocalFree(tokenUser);
  199. }
  200. SetValid(SUCCEEDED(hr));
  201. DC_END_FN();
  202. return hr;
  203. }
  204. STDMETHODIMP
  205. CTSRDPRemoteDesktopSession::Disconnect()
  206. /*++
  207. Routine Description:
  208. Force a disconnect of the currently connected client,
  209. if one is connected.
  210. Arguments:
  211. Return Value:
  212. S_OK on success. Otherwise, an error code is returned.
  213. --*/
  214. {
  215. DC_BEGIN_FN("CTSRDPRemoteDesktopSession::Disconnect");
  216. if (m_ChannelMgr != NULL) {
  217. m_ChannelMgr->Disconnect();
  218. }
  219. DC_END_FN();
  220. return S_OK;
  221. }
  222. void
  223. CTSRDPRemoteDesktopSession::Shutdown()
  224. /*++
  225. Routine Description:
  226. Final Initialization
  227. Arguments:
  228. Return Value:
  229. S_OK on success. Otherwise, an error code is returned.
  230. --*/
  231. {
  232. DC_BEGIN_FN("CTSRDPRemoteDesktopSession::Shutdown");
  233. //
  234. // Tell the channel manager to stop listening for data so it can
  235. // shut down when its ref count goes to 0. And, decrement its
  236. // ref count.
  237. //
  238. if (m_ChannelMgr != NULL) {
  239. m_ChannelMgr->StopListening();
  240. m_ChannelMgr->Release();
  241. m_ChannelMgr = NULL;
  242. }
  243. DC_END_FN();
  244. }
  245. STDMETHODIMP
  246. CTSRDPRemoteDesktopSession::get_ConnectParms(
  247. OUT BSTR *parms
  248. )
  249. /*++
  250. Routine Description:
  251. Return parms that can be used to connect from the ActiveX client
  252. control.
  253. Arguments:
  254. parms - Parms returned here.
  255. Return Value:
  256. --*/
  257. {
  258. DC_BEGIN_FN("CTSRDPRemoteDesktopSession::get_ConnectParms");
  259. HRESULT hr = S_OK;
  260. //
  261. // If we are not valid, fail.
  262. //
  263. if (!IsValid()) {
  264. hr = E_FAIL;
  265. ASSERT(FALSE);
  266. goto CLEANUPANDEXIT;
  267. }
  268. // Always get latest connect parm again, IP address might
  269. // change
  270. hr = m_HelpSession->get_ConnectParms( parms );
  271. CLEANUPANDEXIT:
  272. DC_END_FN();
  273. return hr;
  274. }
  275. VOID
  276. CTSRDPRemoteDesktopSession::GetSessionName(
  277. CComBSTR &name
  278. )
  279. /*++
  280. Routine Description:
  281. Return a string representation for the session.
  282. Arguments:
  283. Return Value:
  284. --*/
  285. {
  286. DC_BEGIN_FN("CTSRDPRemoteDesktopSession::GetSessionName");
  287. WCHAR buf[256];
  288. ASSERT(IsValid());
  289. wsprintf(buf, L"TSRDP%ld", m_SessionID);
  290. name = buf;
  291. DC_END_FN();
  292. }
  293. VOID
  294. CTSRDPRemoteDesktopSession::GetSessionDescription(
  295. CComBSTR &descr
  296. )
  297. {
  298. GetSessionName(descr);
  299. }
  300. HRESULT
  301. CTSRDPRemoteDesktopSession::FetchOurTokenUser(
  302. PTOKEN_USER *tokenUser
  303. )
  304. /*++
  305. Routine Description:
  306. Fetch our Token User struct.
  307. Arguments:
  308. tokenUser - Returned token user for this thread. Should
  309. be freed using LocalFree.
  310. Return Value:
  311. S_OK on success. An error HRESULT otherwise.
  312. --*/
  313. {
  314. HRESULT hr = S_OK;
  315. ULONG bufferLength;
  316. HANDLE tokenHandle = NULL;
  317. DC_BEGIN_FN("CTSRDPRemoteDesktopSession::FetchOurTokenUser");
  318. *tokenUser = NULL;
  319. //
  320. // Get our process token.
  321. //
  322. if (!OpenProcessToken(
  323. GetCurrentProcess(),
  324. TOKEN_QUERY,
  325. &tokenHandle
  326. )) {
  327. hr = HRESULT_FROM_WIN32(GetLastError());
  328. TRC_ERR((TB, L"OpenThreadToken: %08X", hr));
  329. goto CLEANUPANDEXIT;
  330. }
  331. //
  332. // Fetch our Token User struct.
  333. //
  334. bufferLength = 0;
  335. GetTokenInformation(
  336. tokenHandle,
  337. TokenUser,
  338. NULL,
  339. 0,
  340. &bufferLength
  341. );
  342. if (bufferLength == 0) {
  343. hr = HRESULT_FROM_WIN32(GetLastError());
  344. TRC_ERR((TB, L"OpenThreadToken: %08X", hr));
  345. goto CLEANUPANDEXIT;
  346. }
  347. *tokenUser = (PTOKEN_USER)LocalAlloc(LPTR, bufferLength);
  348. if (*tokenUser == NULL) {
  349. hr = HRESULT_FROM_WIN32(GetLastError());
  350. TRC_ERR((TB, L"LocalAlloc: %08X", GetLastError()));
  351. goto CLEANUPANDEXIT;
  352. }
  353. if (!GetTokenInformation(
  354. tokenHandle,
  355. TokenUser,
  356. *tokenUser,
  357. bufferLength,
  358. &bufferLength
  359. )) {
  360. hr = HRESULT_FROM_WIN32(GetLastError());
  361. LocalFree(*tokenUser);
  362. *tokenUser = NULL;
  363. }
  364. CLEANUPANDEXIT:
  365. if (tokenHandle != NULL) {
  366. CloseHandle(tokenHandle);
  367. }
  368. DC_END_FN();
  369. return hr;
  370. }
  371. HRESULT CTSRDPRemoteDesktopSession::StartListening()
  372. /*++
  373. Routine Description:
  374. Start listening
  375. Should be called everytime the client disconnects and everytime we open
  376. a remote desktop session
  377. This is because the named pipe would have been closed in the disconnect
  378. Return Value:
  379. S_OK on success. An error HRESULT otherwise.
  380. --*/
  381. {
  382. DC_BEGIN_FN("CTSRDPRemoteDesktopSession::StartListening");
  383. HRESULT hr = E_FAIL;
  384. CComBSTR helpAccountName;
  385. //
  386. // Tell the channel manager to start listening
  387. //
  388. if (m_ChannelMgr != NULL) {
  389. //
  390. // Get the help account name.
  391. //
  392. hr = m_HelpSession->get_AssistantAccountName(&helpAccountName);
  393. if (!SUCCEEDED(hr)) {
  394. TRC_ERR((TB, L"get_AssistantAccountName: %08X", hr));
  395. goto CLEANUPANDEXIT;
  396. }
  397. hr = m_ChannelMgr->StartListening(helpAccountName);
  398. }
  399. DC_END_FN();
  400. CLEANUPANDEXIT:
  401. return hr;
  402. }