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.

2476 lines
66 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. rdsaddin.cpp
  5. Abstract:
  6. The TSRDP Assistant Session VC Add-In is an executable that is
  7. loaded in the session that is created when the TSRDP client plug-in
  8. first logs in to the server machine. It acts, primarily, as a
  9. proxy between the client VC interface and the Remote Desktop Host
  10. COM Object. Channel data is routed from the TSRDP Assistant Session
  11. VC Add-In to the Remote Desktop Host COM Object using a named pipe
  12. that is created by the Remote Desktop Host COM Object when it enters
  13. "listen" mode.
  14. In addition to its duties as a proxy, the Add-In also manages a control
  15. channel between the client and the server. This control channel is
  16. used by the client-side to direct the server side to initiate remote
  17. control of the end user's TS session.
  18. TODO: We should make the pipe IO synchronous since we now have two
  19. IO threads.
  20. Author:
  21. Tad Brockway 02/00
  22. Revision History:
  23. --*/
  24. #ifdef TRC_FILE
  25. #undef TRC_FILE
  26. #endif
  27. #define TRC_FILE "_sesa"
  28. #include <windows.h>
  29. #include <process.h>
  30. #include <RemoteDesktop.h>
  31. #include <RemoteDesktopDBG.h>
  32. #include <RemoteDesktopChannels.h>
  33. #include <TSRDPRemoteDesktop.h>
  34. #include <wtblobj.h>
  35. #include <wtsapi32.h>
  36. #include <sessmgr.h>
  37. #include <winsta.h>
  38. #include <atlbase.h>
  39. #include <RemoteDesktopUtils.h>
  40. #include <sessmgr_i.c>
  41. #include <pchannel.h>
  42. #include <RDCHost.h>
  43. #include <regapi.h>
  44. ///////////////////////////////////////////////////////
  45. //
  46. // Defines
  47. //
  48. #define CLIENTPIPE_CONNECTTIMEOUT (20 * 1000) // 20 seconds.
  49. #define VCBUFFER_RESIZE_DELTA CHANNEL_CHUNK_LENGTH
  50. #define RDS_CHECKCONN_TIMEOUT (30 * 1000) //millisec. default value to ping is 30 seconds
  51. #define RDC_CONNCHECK_ENTRY L"ConnectionCheck"
  52. #define THREADSHUTDOWN_WAITTIMEOUT 30 * 1000
  53. ///////////////////////////////////////////////////////
  54. //
  55. // Typedefs
  56. //
  57. typedef struct _IOBuffer {
  58. PREMOTEDESKTOP_CHANNELBUFHEADER buffer;
  59. DWORD bufSize;
  60. DWORD offset;
  61. } IOBUFFER;
  62. ///////////////////////////////////////////////////////
  63. //
  64. // Internal Prototypes
  65. //
  66. DWORD ReturnResultToClient(
  67. LONG result
  68. );
  69. VOID RemoteControlDesktop(
  70. BSTR parms
  71. );
  72. BOOL ClientVersionCompatible(
  73. DWORD dwMajor,
  74. DWORD dwMinor
  75. );
  76. VOID ClientAuthenticate(
  77. BSTR parms,
  78. BSTR blob
  79. );
  80. DWORD ProcessControlChannelRequest(
  81. IOBUFFER &msg
  82. );
  83. DWORD SendMsgToClient(
  84. PREMOTEDESKTOP_CHANNELBUFHEADER msg
  85. );
  86. VOID HandleVCReadComplete(
  87. HANDLE waitableObject,
  88. PVOID clientData
  89. );
  90. DWORD HandleReceivedVCMsg(
  91. IOBUFFER &msg
  92. );
  93. VOID HandleVCClientConnect(
  94. HANDLE waitableObject,
  95. PVOID clientData
  96. );
  97. VOID HandleVCClientDisconnect(
  98. HANDLE waitableObject,
  99. PVOID clientData
  100. );
  101. VOID HandleNamedPipeReadComplete(
  102. OVERLAPPED &incomingPipeOL,
  103. IOBUFFER &incomingPipeBuf
  104. );
  105. VOID HandleReceivedPipeMsg(
  106. IOBUFFER &msg
  107. );
  108. DWORD ConnectVC();
  109. DWORD ConnectClientSessionPipe();
  110. DWORD IssueVCOverlappedRead(
  111. IOBUFFER &msg,
  112. OVERLAPPED &ol
  113. );
  114. DWORD IssueNamedPipeOverlappedRead(
  115. IOBUFFER &msg,
  116. OVERLAPPED &ol
  117. );
  118. unsigned __stdcall
  119. NamedPipeReadThread(
  120. void* ptr
  121. );
  122. VOID WakeUpFunc(
  123. HANDLE waitableObject,
  124. PVOID clientData
  125. );
  126. VOID HandleHelpCenterExit(
  127. HANDLE waitableObject,
  128. PVOID clientData
  129. );
  130. DWORD
  131. SendNullDataToClient(
  132. );
  133. BOOL GetDwordFromRegistry(PDWORD pdwValue);
  134. ///////////////////////////////////////////////////////
  135. //
  136. // Globals to this Module
  137. //
  138. CComBSTR g_bstrCmdLineHelpSessionId;
  139. WTBLOBJMGR g_WaitObjMgr = NULL;
  140. BOOL g_Shutdown = FALSE;
  141. HANDLE g_VCHandle = NULL;
  142. HANDLE g_ProcHandle = NULL;
  143. DWORD g_SessionID = 0;
  144. HANDLE g_ProcToken = NULL;
  145. HANDLE g_WakeUpForegroundThreadEvent = NULL;
  146. DWORD g_PrevTimer = 0;
  147. DWORD g_dwTimeOutInterval = 0;
  148. HANDLE g_ShutdownEvent = NULL;
  149. HANDLE g_RemoteControlDesktopThread = NULL;
  150. HANDLE g_NamedPipeReadThread = NULL;
  151. HANDLE g_NamedPipeWriteEvent = NULL;
  152. //
  153. // VC Globals
  154. //
  155. HANDLE g_ClientIsconnectEvent = NULL;
  156. HANDLE g_VCFileHandle = NULL;
  157. OVERLAPPED g_VCReadOverlapped = { 0, 0, 0, 0, NULL };
  158. BOOL g_ClientConnected = FALSE;
  159. //
  160. // Client Session Information
  161. //
  162. LONG g_ClientSessionID = -1;
  163. HANDLE g_ClientSessionPipe = NULL;
  164. //
  165. // True if the client has been successfully authenticated.
  166. //
  167. BOOL g_ClientAuthenticated = FALSE;
  168. //
  169. // Incoming Virtual Channel Buf.
  170. //
  171. IOBUFFER g_IncomingVCBuf = { NULL, 0, 0 };
  172. //
  173. // Global help session manager object, this need to be
  174. // global so that when process exit, object destructor
  175. // can inform resolver about the disconnect
  176. //
  177. CComPtr<IRemoteDesktopHelpSessionMgr> g_HelpSessionManager;
  178. //
  179. // Help Session Identifier for the Current Client Connection
  180. //
  181. CComBSTR g_HelpSessionID;
  182. //
  183. // Client (expert side) rdchost major version
  184. //
  185. DWORD g_ClientMajor;
  186. DWORD g_ClientMinor;
  187. //
  188. // Handle to Help Center : B2 blocker workaround for BUG:342742
  189. //
  190. HANDLE g_hHelpCenterProcess = NULL;
  191. CRITICAL_SECTION g_cs;
  192. //------------------------------------------------------------------
  193. BOOL WINAPI
  194. ControlHandler(
  195. IN DWORD dwCtrlType
  196. )
  197. /*++
  198. Abstract:
  199. Parameter:
  200. IN dwCtrlType : control type
  201. Return:
  202. ++*/
  203. {
  204. switch( dwCtrlType )
  205. {
  206. case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
  207. case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
  208. case CTRL_CLOSE_EVENT:
  209. case CTRL_LOGOFF_EVENT:
  210. case CTRL_SHUTDOWN_EVENT:
  211. SetEvent( g_ShutdownEvent );
  212. g_Shutdown = TRUE;
  213. return TRUE;
  214. }
  215. return FALSE;
  216. }
  217. DWORD
  218. IsZeroterminateString(
  219. LPTSTR pszString,
  220. int length
  221. )
  222. /*++
  223. Routine Description;
  224. Check is string is NULL terminated, code modified from TermSrv's IsZeroterminateStringW()
  225. Parameters:
  226. pszString : Pointer to string.
  227. dwLength : Length of string.
  228. Returns:
  229. ERROR_SUCCESS or ERROR_INVALID_PARAMETER
  230. --*/
  231. {
  232. if (pszString == NULL || length <= 0) {
  233. return ERROR_INVALID_PARAMETER;
  234. }
  235. for (; 0 < length; ++pszString, --length ) {
  236. if (*pszString == (TCHAR)0) {
  237. return ERROR_SUCCESS;
  238. }
  239. }
  240. return ERROR_INVALID_PARAMETER;
  241. }
  242. DWORD
  243. ReturnResultToClient(
  244. LONG clientResult
  245. )
  246. /*++
  247. Routine Description:
  248. Return a result code to the client in the form of a
  249. REMOTEDESKTOP_RC_CONTROL_CHANNEL channel REMOTEDESKTOP_CTL_RESULT message.
  250. Arguments:
  251. Return Value:
  252. ERROR_SUCCESS on success. Otherwise, an error code is returned.
  253. --*/
  254. {
  255. DC_BEGIN_FN("ReturnResultToClient");
  256. DWORD result;
  257. REMOTEDESKTOP_CTL_RESULT_PACKET msg;
  258. memcpy(msg.packetHeader.channelName, REMOTEDESKTOP_RC_CONTROL_CHANNEL,
  259. sizeof(REMOTEDESKTOP_RC_CONTROL_CHANNEL));
  260. msg.packetHeader.channelBufHeader.channelNameLen = REMOTEDESKTOP_RC_CHANNELNAME_LENGTH;
  261. #ifdef USE_MAGICNO
  262. msg.packetHeader.channelBufHeader.magicNo = CHANNELBUF_MAGICNO;
  263. #endif
  264. msg.packetHeader.channelBufHeader.dataLen = sizeof(REMOTEDESKTOP_CTL_RESULT_PACKET) -
  265. sizeof(REMOTEDESKTOP_CTL_PACKETHEADER);
  266. msg.msgHeader.msgType = REMOTEDESKTOP_CTL_RESULT;
  267. msg.result = clientResult;
  268. result = SendMsgToClient((PREMOTEDESKTOP_CHANNELBUFHEADER )&msg);
  269. DC_END_FN();
  270. return result;
  271. }
  272. unsigned __stdcall
  273. RemoteControlDesktopThread(
  274. void* ptr
  275. )
  276. /*++
  277. Routine Description:
  278. Thread func for Remote Control
  279. Arguments:
  280. Return Value:
  281. This function returns a status back to the Salem client when shadow
  282. terminates. It is only allowed to return error codes that are prefixed by
  283. SAFERROR_SHADOWEND
  284. --*/
  285. {
  286. BSTR parms = (BSTR) ptr;
  287. DC_BEGIN_FN("RemoteControlDesktopThread");
  288. CComPtr<IRemoteDesktopHelpSessionMgr> helpSessionManager;
  289. CComPtr<IRemoteDesktopHelpSession> helpSession;
  290. HRESULT hr;
  291. DWORD result;
  292. LONG errReturnCode = SAFERROR_SHADOWEND_UNKNOWN;
  293. //
  294. // If we have not resolve the right user session ID
  295. //
  296. if( g_ClientSessionID == -1 ) {
  297. TRC_ALT((TB, L"Invalid user session ID %ld",
  298. g_ClientSessionID));
  299. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD);
  300. errReturnCode = SAFERROR_SHADOWEND_UNKNOWN;
  301. ASSERT(FALSE);
  302. goto CLEANUPANDEXIT;
  303. }
  304. CoInitialize(NULL);
  305. //
  306. // Create a new instance of helpmgr object to get around threading issue
  307. // in COM
  308. //
  309. hr = helpSessionManager.CoCreateInstance(CLSID_RemoteDesktopHelpSessionMgr, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_DISABLE_AAA);
  310. if (!SUCCEEDED(hr)) {
  311. TRC_ERR((TB, TEXT("Can't create help session manager: %08X"), hr));
  312. // Setup issue
  313. errReturnCode = SAFERROR_SHADOWEND_UNKNOWN;
  314. ASSERT(FALSE);
  315. goto CLEANUPANDEXIT;
  316. }
  317. //
  318. // Set the security level to impersonate. This is required by
  319. // the session manager.
  320. //
  321. hr = CoSetProxyBlanket(
  322. (IUnknown *)helpSessionManager,
  323. RPC_C_AUTHN_DEFAULT,
  324. RPC_C_AUTHZ_DEFAULT,
  325. NULL,
  326. RPC_C_AUTHN_LEVEL_DEFAULT,
  327. RPC_C_IMP_LEVEL_IDENTIFY,
  328. NULL,
  329. EOAC_NONE
  330. );
  331. if (!SUCCEEDED(hr)) {
  332. TRC_ERR((TB, TEXT("CoSetProxyBlanket: %08X"), hr));
  333. ASSERT(FALSE);
  334. errReturnCode = SAFERROR_SHADOWEND_UNKNOWN;
  335. goto CLEANUPANDEXIT;
  336. }
  337. //
  338. // Retrieve help session object for the incident
  339. //
  340. hr = helpSessionManager->RetrieveHelpSession(
  341. g_HelpSessionID,
  342. &helpSession
  343. );
  344. if (!SUCCEEDED(hr)) {
  345. TRC_ERR((TB, L"RetrieveHelpSession: %08X", hr));
  346. errReturnCode = SAFERROR_SHADOWEND_UNKNOWN;
  347. goto CLEANUPANDEXIT;
  348. }
  349. //
  350. // Set shadow configuration to help session RDS setting
  351. // Console shadow always reset shadow class back to
  352. // original value.
  353. //
  354. hr = helpSession->EnableUserSessionRdsSetting(TRUE);
  355. if( FAILED(hr) ) {
  356. TRC_ERR((TB, L"Can't set shadow setting on %ld : %08X.", hr));
  357. errReturnCode = SAFERROR_SHADOWEND_UNKNOWN;
  358. goto CLEANUPANDEXIT;
  359. }
  360. //
  361. // Shadow the desktop.
  362. //
  363. if (!WinStationShadow(
  364. SERVERNAME_CURRENT,
  365. NULL, //machineName,
  366. g_ClientSessionID,
  367. TSRDPREMOTEDESKTOP_SHADOWVKEY,
  368. TSRDPREMOTEDESKTOP_SHADOWVKEYMODIFIER
  369. )) {
  370. result = GetLastError();
  371. hr = HRESULT_FROM_WIN32(result);
  372. //
  373. // Map the error code to a SAF error code.
  374. //
  375. if( result == ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE ) {
  376. errReturnCode = SAFERROR_SHADOWEND_CONFIGCHANGE;
  377. }
  378. else {
  379. errReturnCode = SAFERROR_SHADOWEND_UNKNOWN;
  380. }
  381. }
  382. //
  383. // No need to reset g_ClientSessionID, we don't support multiple instance.
  384. //
  385. //
  386. // Inform help session object that shadow has completed, NotifyRemoteControl()
  387. // internally invoke EnableUserSessionRdsSetting(TRUE) to change
  388. // TS shadow class
  389. // No need to reset g_ClientSessionID, we don't support multiple instance.
  390. //
  391. //
  392. // Inform help session object that shadow has completed
  393. //
  394. hr = helpSession->EnableUserSessionRdsSetting( FALSE );
  395. if (FAILED(hr)) {
  396. TRC_ERR((TB, L"Can't reset shadow setting on %ld : %08X.",
  397. g_ClientSessionID, hr));
  398. //
  399. // not a critical error.
  400. //
  401. }
  402. CLEANUPANDEXIT:
  403. //
  404. // Send the result to the client on failure to shadow.
  405. //
  406. ReturnResultToClient(errReturnCode);
  407. CoUninitialize();
  408. DC_END_FN();
  409. _endthreadex(errReturnCode);
  410. return errReturnCode;
  411. }
  412. VOID
  413. RemoteControlDesktop(
  414. BSTR parms
  415. )
  416. /*++
  417. Routine Description:
  418. Arguments:
  419. Connection Parameters
  420. Return Value:
  421. --*/
  422. {
  423. unsigned dump;
  424. DC_BEGIN_FN("RemoteControlDesktop");
  425. //
  426. // RDCHOST.DLL will not send any control message so there is no checking on
  427. // second remote control command.
  428. //
  429. g_RemoteControlDesktopThread = (HANDLE)_beginthreadex( NULL, 0, RemoteControlDesktopThread, (void *)parms, 0, &dump );
  430. if ((uintptr_t)g_RemoteControlDesktopThread == -1 ) {
  431. g_RemoteControlDesktopThread = NULL;
  432. TRC_ERR((TB, L"Failed to create RemoteControlDesktopThread for session %d - %ld",
  433. g_ClientSessionID, GetLastError()));
  434. // return error code only when
  435. // failed to spawn another thread
  436. ReturnResultToClient(SAFERROR_SHADOWEND_UNKNOWN);
  437. }
  438. DC_END_FN();
  439. }
  440. BOOL
  441. ClientVersionCompatible(
  442. DWORD dwMajor,
  443. DWORD dwMinor
  444. )
  445. /*++
  446. Routine Description:
  447. Verify client (expert) version is compatible with our version.
  448. Parameters:
  449. dwMajor : Client major version.
  450. dwMinor : Client minor version.
  451. Returns:
  452. None.
  453. --*/
  454. {
  455. //
  456. // Build 2409 or earlier (including B1 release has major version of 1 and minor version of 1
  457. // rdchost/rdsaddin need to deal with versioning, for build 2409 or earlier, we
  458. // just make it in-compatible since we need some expert identity from rdchost.dll
  459. //
  460. #if FEATURE_USERBLOBS
  461. if( dwMajor == 1 && dwMinor == 1 ) {
  462. return FALSE;
  463. }
  464. #endif
  465. return TRUE;
  466. }
  467. VOID
  468. ClientAuthenticate(
  469. BSTR parms,
  470. BSTR blob
  471. )
  472. /*++
  473. Routine Description:
  474. Handle a REMOTEDESKTOP_CTL_AUTHENTICATE request from the client.
  475. Arguments:
  476. Return Value:
  477. This function will return the following results back to the client,
  478. based on the following
  479. --*/
  480. {
  481. DC_BEGIN_FN("ClientAuthenticate");
  482. HRESULT hr;
  483. DWORD result = ERROR_NOT_AUTHENTICATED;
  484. CComBSTR machineName;
  485. CComBSTR assistantAccount;
  486. CComBSTR assistantAccountPwd;
  487. CComBSTR helpSessionPwd;
  488. CComBSTR helpSessionName;
  489. CComBSTR protocolSpecificParms;
  490. BOOL match = FALSE;
  491. DWORD protocolType;
  492. long userTSSessionID;
  493. DWORD dwVersion;
  494. LONG clientReturnCode = SAFERROR_NOERROR;
  495. if( FALSE == ClientVersionCompatible( g_ClientMajor, g_ClientMinor ) ) {
  496. clientReturnCode = SAFERROR_INCOMPATIBLEVERSION;
  497. goto CLEANUPANDEXIT;
  498. }
  499. //
  500. // Parse the parms.
  501. //
  502. result = ParseConnectParmsString(
  503. parms,
  504. &dwVersion,
  505. &protocolType,
  506. machineName,
  507. assistantAccount,
  508. assistantAccountPwd,
  509. g_HelpSessionID,
  510. helpSessionName,
  511. helpSessionPwd,
  512. protocolSpecificParms
  513. );
  514. if (result != ERROR_SUCCESS) {
  515. clientReturnCode = SAFERROR_INVALIDPARAMETERSTRING;
  516. goto CLEANUPANDEXIT;
  517. }
  518. //
  519. // Verify HelpSession ID and password match with our command line
  520. // parameter
  521. //
  522. if( !(g_bstrCmdLineHelpSessionId == g_HelpSessionID) ) {
  523. clientReturnCode = SAFERROR_MISMATCHPARMS;
  524. TRC_ERR((TB, TEXT("Parameter mismatched")));
  525. goto CLEANUPANDEXIT;
  526. }
  527. //
  528. // Open an instance of the Remote Desktop Help Session Manager service.
  529. //
  530. hr = g_HelpSessionManager.CoCreateInstance(CLSID_RemoteDesktopHelpSessionMgr, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_DISABLE_AAA);
  531. if (!SUCCEEDED(hr)) {
  532. clientReturnCode = SAFERROR_INTERNALERROR;
  533. goto CLEANUPANDEXIT;
  534. }
  535. //
  536. // Set the security level to impersonate. This is required by
  537. // the session manager.
  538. //
  539. hr = CoSetProxyBlanket(
  540. (IUnknown *)g_HelpSessionManager,
  541. RPC_C_AUTHN_DEFAULT,
  542. RPC_C_AUTHZ_DEFAULT,
  543. NULL,
  544. RPC_C_AUTHN_LEVEL_DEFAULT,
  545. RPC_C_IMP_LEVEL_IDENTIFY,
  546. NULL,
  547. EOAC_NONE
  548. );
  549. if (!SUCCEEDED(hr)) {
  550. TRC_ERR((TB, TEXT("CoSetProxyBlanket: %08X"), hr));
  551. ASSERT(FALSE);
  552. clientReturnCode = SAFERROR_INTERNALERROR;
  553. goto CLEANUPANDEXIT;
  554. }
  555. //
  556. // Resolve the Terminal Services session with help from the session
  557. // manager. This gives the help application the opportunity to "find
  558. // the user" and to start the TS-session named pipe component,
  559. // by opening the relevant Remote Desktopping Session Object.
  560. //
  561. hr = g_HelpSessionManager->VerifyUserHelpSession(
  562. g_HelpSessionID,
  563. helpSessionPwd,
  564. CComBSTR(parms),
  565. blob,
  566. GetCurrentProcessId(),
  567. (ULONG_PTR*)&g_hHelpCenterProcess,
  568. &clientReturnCode,
  569. &userTSSessionID
  570. );
  571. if (SUCCEEDED(hr)) {
  572. if( userTSSessionID != -1 ) {
  573. //
  574. // Cache the session ID so we don't have to make extra call
  575. // to get the actual session ID, note, one instance of RDSADDIN
  576. // per help assistant connection.
  577. //
  578. g_ClientSessionID = userTSSessionID;
  579. match = TRUE;
  580. }
  581. if (match) {
  582. TRC_NRM((TB, L"Successful password authentication for %ld",
  583. g_ClientSessionID));
  584. }
  585. else {
  586. TRC_ALT((TB, L"Can't authenticate pasword %s for %s",
  587. helpSessionPwd, g_HelpSessionID));
  588. clientReturnCode = SAFERROR_INVALIDPASSWORD;
  589. goto CLEANUPANDEXIT;
  590. }
  591. }
  592. else {
  593. TRC_ERR((TB, L"Can't verify user help session %s: %08X.",
  594. g_HelpSessionID, hr));
  595. if( SAFERROR_NOERROR == clientReturnCode ) {
  596. ASSERT(FALSE);
  597. TRC_ERR((TB, L"Sessmgr did not return correct error code for VerifyUserHelpSession."));
  598. clientReturnCode = SAFERROR_UNKNOWNSESSMGRERROR;
  599. }
  600. goto CLEANUPANDEXIT;
  601. }
  602. #ifndef DISABLESECURITYCHECKS
  603. //
  604. // Wait on Help Center to terminate as a fix for B2 Stopper: 342742.
  605. //
  606. if (g_hHelpCenterProcess == NULL) {
  607. TRC_ERR((TB, L"Invalid g_HelpCenterProcess."));
  608. ASSERT(FALSE);
  609. clientReturnCode = SAFERROR_INTERNALERROR;
  610. goto CLEANUPANDEXIT;
  611. }
  612. result = WTBLOBJ_AddWaitableObject(
  613. g_WaitObjMgr, NULL,
  614. g_hHelpCenterProcess,
  615. HandleHelpCenterExit
  616. );
  617. if (result != ERROR_SUCCESS) {
  618. clientReturnCode = SAFERROR_INTERNALERROR;
  619. goto CLEANUPANDEXIT;
  620. }
  621. #endif
  622. //
  623. // Connect to the client session's named pipe.
  624. //
  625. result = ConnectClientSessionPipe();
  626. if (result != ERROR_SUCCESS) {
  627. clientReturnCode = SAFERROR_CANTFORMLINKTOUSERSESSION;
  628. }
  629. else {
  630. g_ClientAuthenticated = TRUE;
  631. }
  632. CLEANUPANDEXIT:
  633. //
  634. // Send the result to the client.
  635. //
  636. ReturnResultToClient(clientReturnCode);
  637. DC_END_FN();
  638. }
  639. DWORD
  640. ProcessControlChannelRequest(
  641. IOBUFFER &msg
  642. )
  643. /*++
  644. Routine Description:
  645. Arguments:
  646. Return Value:
  647. ERROR_SUCCESS on success. Otherwise, an error status is returned.
  648. --*/
  649. {
  650. DC_BEGIN_FN("ProcessControlChannelRequest");
  651. PREMOTEDESKTOP_CTL_BUFHEADER ctlHdr;
  652. PBYTE ptr;
  653. PBYTE end_ptr;
  654. //
  655. // Sanity check the message size.
  656. //
  657. DWORD minSize = sizeof(REMOTEDESKTOP_CHANNELBUFHEADER) + sizeof(REMOTEDESKTOP_CTL_BUFHEADER);
  658. if (msg.bufSize < minSize) {
  659. TRC_ERR((TB, L"minSize == %ld", minSize));
  660. ASSERT(FALSE);
  661. DC_END_FN();
  662. return E_FAIL;
  663. }
  664. //
  665. // Switch on the request type.
  666. //
  667. ptr = (PBYTE)(msg.buffer + 1);
  668. ptr += msg.buffer->channelNameLen;
  669. ctlHdr = (PREMOTEDESKTOP_CTL_BUFHEADER)ptr;
  670. end_ptr = ptr + msg.buffer->dataLen;
  671. switch(ctlHdr->msgType)
  672. {
  673. case REMOTEDESKTOP_CTL_AUTHENTICATE:
  674. {
  675. CComBSTR bstrConnectParm;
  676. #if FEATURE_USERBLOBS
  677. CComBSTR bstrExpertBlob;
  678. #endif
  679. // check to see if connectParm even exist.
  680. if( end_ptr <= (ptr+sizeof(REMOTEDESKTOP_CTL_BUFHEADER)) )
  681. {
  682. ReturnResultToClient( SAFERROR_INVALIDPARAMETERSTRING );
  683. return ERROR_INVALID_DATA;
  684. }
  685. //
  686. // advance pointer to start of connect parm.
  687. //
  688. ptr += sizeof(REMOTEDESKTOP_CTL_BUFHEADER);
  689. if( 0 != ((PtrToLong(end_ptr) - PtrToLong(ptr)) % 2) )
  690. {
  691. // connect parm and expert blob is BSTR so remaining data should be even bytes
  692. ReturnResultToClient( SAFERROR_INVALIDPARAMETERSTRING );
  693. return ERROR_INVALID_DATA;
  694. }
  695. if( ERROR_SUCCESS != IsZeroterminateString( (LPTSTR)ptr, PtrToLong(end_ptr) - PtrToLong(ptr) ) )
  696. {
  697. ReturnResultToClient( SAFERROR_INVALIDPARAMETERSTRING );
  698. return ERROR_INVALID_DATA;
  699. }
  700. bstrConnectParm = (BSTR)ptr;
  701. #if FEATURE_USERBLOBS
  702. ptr += (bstrConnectParm.Length()+1)*sizeof(WCHAR);
  703. // check bound of connectParm
  704. if( end_ptr < ptr )
  705. {
  706. ReturnResultToClient( SAFERROR_INVALIDPARAMETERSTRING );
  707. return ERROR_INVALID_DATA;
  708. }
  709. else if( end_ptr > ptr )
  710. {
  711. // check to see if we have an expert blob
  712. if( ERROR_SUCCESS != IsZeroterminateString( (LPTSTR)ptr, PtrToLong(end_ptr) - PtrToLong(ptr) ) )
  713. {
  714. ReturnResultToClient( SAFERROR_INVALIDPARAMETERSTRING );
  715. return ERROR_INVALID_DATA;
  716. }
  717. bstrExpertBlob = (BSTR)ptr;
  718. ptr += ( bstrExpertBlob.Length() + 1 ) * sizeof( WCHAR );
  719. if( ptr != end_ptr )
  720. {
  721. ReturnResultToClient( SAFERROR_INVALIDPARAMETERSTRING );
  722. return ERROR_INVALID_DATA;
  723. }
  724. }
  725. else
  726. {
  727. // Authentication packet does not contain expert specific blob,
  728. // pass empty string over or RPC call will fail.
  729. bstrExpertBlob = L"";
  730. }
  731. #endif
  732. ClientAuthenticate(
  733. bstrConnectParm,
  734. #if FEATURE_USERBLOBS
  735. bstrExpertBlob
  736. #else
  737. CComBSTR(L"")
  738. #endif
  739. );
  740. }
  741. break;
  742. case REMOTEDESKTOP_CTL_REMOTE_CONTROL_DESKTOP :
  743. // RemoteControlDesktop((BSTR)(ptr+sizeof(REMOTEDESKTOP_CTL_BUFHEADER)));
  744. // thread makes no use of bstrparm leave it for null in case we need to
  745. // cbange this for later
  746. RemoteControlDesktop( ( BSTR )NULL );
  747. break;
  748. case REMOTEDESKTOP_CTL_VERSIONINFO:
  749. g_ClientMajor = *(DWORD *)(ptr + sizeof(REMOTEDESKTOP_CTL_BUFHEADER));
  750. g_ClientMinor = *(DWORD *)(ptr + sizeof(REMOTEDESKTOP_CTL_BUFHEADER) + sizeof(DWORD));
  751. TRC_NRM((TB, L"dwMajor = %ld, dwMinor = %d", g_ClientMajor, g_ClientMinor));
  752. //
  753. // We only store version number and let ClientAuthenticate() disconnect client,
  754. // rdchost.dll send two packets, version and AUTHENTICATE in sequence.
  755. //
  756. break;
  757. default:
  758. //
  759. // We will ignore unknown control messages for forward compatibility
  760. //
  761. TRC_NRM((TB, L"Unknown ctl message from client: %ld", ctlHdr->msgType));
  762. }
  763. DC_END_FN();
  764. return ERROR_SUCCESS;
  765. }
  766. DWORD
  767. SendMsgToClient(
  768. PREMOTEDESKTOP_CHANNELBUFHEADER msg
  769. )
  770. /*++
  771. Routine Description:
  772. Arguments:
  773. msg - Message to send.
  774. Return Value:
  775. ERROR_SUCCESS on success. Otherwise, an error status is returned.
  776. --*/
  777. {
  778. DC_BEGIN_FN("SendMsgToClient");
  779. OVERLAPPED overlapped;
  780. PBYTE ptr;
  781. DWORD bytesToWrite;
  782. DWORD bytesWritten;
  783. DWORD result = ERROR_SUCCESS;
  784. #ifdef USE_MAGICNO
  785. ASSERT(msg->magicNo == CHANNELBUF_MAGICNO);
  786. #endif
  787. //
  788. // Send the data out the virtual channel interface.
  789. //
  790. // TODO: Figure out why this flag is not getting set ... and
  791. // if it really matters. Likely, remove the flag.
  792. //
  793. //if (g_ClientConnected) {
  794. EnterCriticalSection( &g_cs );
  795. ptr = (PBYTE)msg;
  796. bytesToWrite = msg->dataLen + msg->channelNameLen +
  797. sizeof(REMOTEDESKTOP_CHANNELBUFHEADER);
  798. while (bytesToWrite > 0) {
  799. //
  800. // Write
  801. //
  802. memset(&overlapped, 0, sizeof(overlapped));
  803. if (!WriteFile(g_VCFileHandle, ptr, bytesToWrite,
  804. &bytesWritten, &overlapped)) {
  805. if (GetLastError() == ERROR_IO_PENDING) {
  806. if (!GetOverlappedResult(
  807. g_VCFileHandle,
  808. &overlapped,
  809. &bytesWritten,
  810. TRUE)) {
  811. result = GetLastError();
  812. TRC_ERR((TB, L"GetOverlappedResult: %08X", result));
  813. break;
  814. }
  815. }
  816. else {
  817. result = GetLastError();
  818. TRC_ERR((TB, L"WriteFile: %08X", result));
  819. // ASSERT(FALSE); overactive assert after disconnect
  820. break;
  821. }
  822. }
  823. //
  824. // Increment the ptr and decrement the bytes remaining.
  825. //
  826. bytesToWrite -= bytesWritten;
  827. ptr += bytesWritten;
  828. }
  829. LeaveCriticalSection( &g_cs );
  830. /*
  831. else {
  832. result = ERROR_NOT_CONNECTED;
  833. }
  834. */
  835. //
  836. //update the timer
  837. //
  838. g_PrevTimer = GetTickCount();
  839. DC_END_FN();
  840. return result;
  841. }
  842. VOID
  843. HandleVCReadComplete(
  844. HANDLE waitableObject,
  845. PVOID clientData
  846. )
  847. /*++
  848. Routine Description:
  849. Arguments:
  850. Return Value:
  851. --*/
  852. {
  853. DC_BEGIN_FN("HandleVCReadComplete");
  854. DWORD bytesRead;
  855. DWORD result = ERROR_SUCCESS;
  856. BOOL resizeBuf = FALSE;
  857. //
  858. // Get the results of the read.
  859. //
  860. if (!GetOverlappedResult(
  861. g_VCFileHandle,
  862. &g_VCReadOverlapped,
  863. &bytesRead,
  864. FALSE)) {
  865. //
  866. // If we are too small, then reissue the read with a larger buffer.
  867. //
  868. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  869. resizeBuf = TRUE;
  870. }
  871. else {
  872. result = GetLastError();
  873. TRC_ERR((TB, L"GetOverlappedResult: %08X", result));
  874. goto CLEANUPANDEXIT;
  875. }
  876. }
  877. else {
  878. g_IncomingVCBuf.offset += bytesRead;
  879. }
  880. //
  881. // See if we have a complete packet from the client.
  882. //
  883. if (g_IncomingVCBuf.offset >= sizeof(REMOTEDESKTOP_CHANNELBUFHEADER)) {
  884. DWORD packetSize = g_IncomingVCBuf.buffer->dataLen +
  885. g_IncomingVCBuf.buffer->channelNameLen +
  886. sizeof(REMOTEDESKTOP_CHANNELBUFHEADER);
  887. //
  888. // If we have a complete packet, then handle the read and reset the offset.
  889. //
  890. if (g_IncomingVCBuf.offset >= packetSize) {
  891. result = HandleReceivedVCMsg(g_IncomingVCBuf);
  892. if (result == ERROR_SUCCESS) {
  893. g_IncomingVCBuf.offset = 0;
  894. }
  895. else {
  896. goto CLEANUPANDEXIT;
  897. }
  898. }
  899. //
  900. // Otherwise, resize the incoming buf if we are exactly at the incoming
  901. // buffer boundary.
  902. //
  903. else if (g_IncomingVCBuf.offset == g_IncomingVCBuf.bufSize) {
  904. resizeBuf = TRUE;
  905. }
  906. }
  907. //
  908. // Resize, if necessary.
  909. //
  910. if (resizeBuf) {
  911. PREMOTEDESKTOP_CHANNELBUFHEADER pBuffer = NULL;
  912. pBuffer = (PREMOTEDESKTOP_CHANNELBUFHEADER )REALLOCMEM(
  913. g_IncomingVCBuf.buffer,
  914. g_IncomingVCBuf.bufSize + VCBUFFER_RESIZE_DELTA
  915. );
  916. if (pBuffer != NULL) {
  917. g_IncomingVCBuf.buffer = pBuffer;
  918. result = ERROR_SUCCESS;
  919. g_IncomingVCBuf.bufSize = g_IncomingVCBuf.bufSize +
  920. VCBUFFER_RESIZE_DELTA;
  921. }
  922. else {
  923. result = ERROR_NOT_ENOUGH_MEMORY;
  924. TRC_ERR((TB, L"Couldn't allocate incoming VC buf."));
  925. goto CLEANUPANDEXIT;
  926. }
  927. }
  928. //
  929. //update the timer
  930. //
  931. g_PrevTimer = GetTickCount();
  932. //
  933. // Issue the next read request.
  934. //
  935. result = IssueVCOverlappedRead(g_IncomingVCBuf, g_VCReadOverlapped) ;
  936. CLEANUPANDEXIT:
  937. //
  938. // Any failure is fatal. The client will need to reconnect to get things
  939. // started again.
  940. //
  941. if (result != ERROR_SUCCESS) {
  942. TRC_ERR((TB, L"Client considered disconnected. Shutting down."));
  943. g_Shutdown = TRUE;
  944. }
  945. DC_END_FN();
  946. }
  947. DWORD
  948. IssueVCOverlappedRead(
  949. IOBUFFER &msg,
  950. OVERLAPPED &ol
  951. )
  952. /*++
  953. Routine Description:
  954. Issue an overlapped read for the next VC buffer.
  955. Arguments:
  956. msg - Incoming VC buffer.
  957. ol - Corresponding overlapped IO struct.
  958. Return Value:
  959. Returns ERROR_SUCCESS on success. Otherwise, an error code is returned.
  960. --*/
  961. {
  962. DC_BEGIN_FN("IssueVCOverlappedRead");
  963. DWORD result = ERROR_SUCCESS;
  964. ol.Internal = 0;
  965. ol.InternalHigh = 0;
  966. ol.Offset = 0;
  967. ol.OffsetHigh = 0;
  968. ResetEvent(ol.hEvent);
  969. if (!ReadFile(g_VCFileHandle, ((PBYTE)msg.buffer)+msg.offset,
  970. msg.bufSize - msg.offset, NULL, &ol)) {
  971. if (GetLastError() != ERROR_IO_PENDING) {
  972. result = GetLastError();
  973. TRC_ERR((TB, L"ReadFile failed: %08X", result));
  974. }
  975. }
  976. DC_END_FN();
  977. return result;
  978. }
  979. DWORD
  980. IssueNamedPipeOverlappedRead(
  981. IOBUFFER &msg,
  982. OVERLAPPED &ol,
  983. DWORD len
  984. )
  985. /*++
  986. Routine Description:
  987. Issue an overlapped read for the next named pipe buffer.
  988. Arguments:
  989. msg - Incoming Named Pipe buffer.
  990. ol - Corresponding overlapped IO struct.
  991. Return Value:
  992. Returns ERROR_SUCCESS on success. Otherwise, an error code is returned.
  993. --*/
  994. {
  995. DC_BEGIN_FN("IssueNamedPipeOverlappedRead");
  996. DWORD result = ERROR_SUCCESS;
  997. ol.Internal = 0;
  998. ol.InternalHigh = 0;
  999. ol.Offset = 0;
  1000. ol.OffsetHigh = 0;
  1001. ResetEvent(ol.hEvent);
  1002. if (!ReadFile(g_ClientSessionPipe, ((PBYTE)msg.buffer), len, NULL, &ol)) {
  1003. if (GetLastError() != ERROR_IO_PENDING) {
  1004. result = GetLastError();
  1005. TRC_ERR((TB, L"ReadFile failed: %08X", result));
  1006. }
  1007. }
  1008. DC_END_FN();
  1009. return result;
  1010. }
  1011. DWORD
  1012. HandleReceivedVCMsg(
  1013. IOBUFFER &msg
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. Arguments:
  1018. Return Value:
  1019. --*/
  1020. {
  1021. DC_BEGIN_FN("HandleReceivedVCMsg");
  1022. OVERLAPPED overlapped;
  1023. PBYTE ptr;
  1024. DWORD bytesToWrite;
  1025. DWORD bytesWritten;
  1026. DWORD result = ERROR_SUCCESS;
  1027. BSTR channelName;
  1028. BSTREqual isBSTREqual;
  1029. CComBSTR tmpStr;
  1030. #ifdef USE_MAGICNO
  1031. ASSERT(msg.buffer->magicNo == CHANNELBUF_MAGICNO);
  1032. #endif
  1033. //
  1034. // Get the channel name.
  1035. // TODO: We could actually be smarter about this by checking the
  1036. // length for a match, first.
  1037. //
  1038. channelName = SysAllocStringByteLen(NULL, msg.buffer->channelNameLen);
  1039. if (channelName == NULL) {
  1040. TRC_ERR((TB, TEXT("Can't allocate channel name.")));
  1041. goto CLEANUPANDEXIT;
  1042. }
  1043. ptr = (PBYTE)(msg.buffer + 1);
  1044. memcpy(channelName, ptr, msg.buffer->channelNameLen);
  1045. //
  1046. // Filter control channel data.
  1047. //
  1048. tmpStr = REMOTEDESKTOP_RC_CONTROL_CHANNEL;
  1049. if (isBSTREqual(channelName, tmpStr)) {
  1050. result = ProcessControlChannelRequest(msg);
  1051. goto CLEANUPANDEXIT;
  1052. }
  1053. //
  1054. // If the client is not yet authenticated.
  1055. //
  1056. if (!g_ClientAuthenticated) {
  1057. result = E_FAIL;
  1058. goto CLEANUPANDEXIT;
  1059. }
  1060. if( g_ClientSessionPipe == INVALID_HANDLE_VALUE ||
  1061. g_ClientSessionPipe == NULL ) {
  1062. //
  1063. // when client is authenticated, g_ClientSessionPipe must
  1064. // have valid value.
  1065. ASSERT(FALSE);
  1066. result = E_FAIL;
  1067. goto CLEANUPANDEXIT;
  1068. }
  1069. //
  1070. // Send the message header.
  1071. //
  1072. memset(&overlapped, 0, sizeof(overlapped));
  1073. overlapped.hEvent = g_NamedPipeWriteEvent;
  1074. ResetEvent(g_NamedPipeWriteEvent);
  1075. if (!WriteFile(g_ClientSessionPipe,
  1076. msg.buffer, sizeof(REMOTEDESKTOP_CHANNELBUFHEADER),
  1077. &bytesWritten, &overlapped)) {
  1078. if (GetLastError() == ERROR_IO_PENDING) {
  1079. if (WaitForSingleObject(
  1080. g_NamedPipeWriteEvent,
  1081. INFINITE
  1082. ) != WAIT_OBJECT_0) {
  1083. result = GetLastError();
  1084. TRC_ERR((TB, L"WaitForSingleObject: %08X", result));
  1085. goto CLEANUPANDEXIT;
  1086. }
  1087. if (!GetOverlappedResult(
  1088. g_ClientSessionPipe,
  1089. &overlapped,
  1090. &bytesWritten,
  1091. FALSE)) {
  1092. result = GetLastError();
  1093. TRC_ERR((TB, L"GetOverlappedResult: %08X", result));
  1094. goto CLEANUPANDEXIT;
  1095. }
  1096. }
  1097. else {
  1098. result = GetLastError();
  1099. TRC_ERR((TB, L"WriteFile: %08X", result));
  1100. goto CLEANUPANDEXIT;
  1101. }
  1102. }
  1103. ASSERT(bytesWritten == sizeof(REMOTEDESKTOP_CHANNELBUFHEADER));
  1104. //
  1105. // Send the message data.
  1106. //
  1107. ptr = ((PBYTE)msg.buffer) + sizeof(REMOTEDESKTOP_CHANNELBUFHEADER);
  1108. memset(&overlapped, 0, sizeof(overlapped));
  1109. overlapped.hEvent = g_NamedPipeWriteEvent;
  1110. ResetEvent(g_NamedPipeWriteEvent);
  1111. if (!WriteFile(g_ClientSessionPipe,
  1112. ptr, msg.buffer->dataLen +
  1113. msg.buffer->channelNameLen,
  1114. &bytesWritten, &overlapped)) {
  1115. if (GetLastError() == ERROR_IO_PENDING) {
  1116. if (WaitForSingleObject(
  1117. g_NamedPipeWriteEvent,
  1118. INFINITE
  1119. ) != WAIT_OBJECT_0) {
  1120. result = GetLastError();
  1121. TRC_ERR((TB, L"WaitForSingleObject: %08X", result));
  1122. goto CLEANUPANDEXIT;
  1123. }
  1124. if (!GetOverlappedResult(
  1125. g_ClientSessionPipe,
  1126. &overlapped,
  1127. &bytesWritten,
  1128. FALSE)) {
  1129. result = GetLastError();
  1130. TRC_ERR((TB, L"GetOverlappedResult: %08X", result));
  1131. goto CLEANUPANDEXIT;
  1132. }
  1133. }
  1134. else {
  1135. result = GetLastError();
  1136. TRC_ERR((TB, L"WriteFile: %08X", result));
  1137. goto CLEANUPANDEXIT;
  1138. }
  1139. }
  1140. ASSERT(bytesWritten == msg.buffer->dataLen +
  1141. msg.buffer->channelNameLen);
  1142. CLEANUPANDEXIT:
  1143. if (channelName != NULL) {
  1144. SysFreeString(channelName);
  1145. }
  1146. DC_END_FN();
  1147. return result;
  1148. }
  1149. VOID
  1150. HandleVCClientConnect(
  1151. HANDLE waitableObject,
  1152. PVOID clientData
  1153. )
  1154. /*++
  1155. Routine Description:
  1156. Arguments:
  1157. Return Value:
  1158. --*/
  1159. {
  1160. DC_BEGIN_FN("HandleVCClientConnect");
  1161. g_ClientConnected = TRUE;
  1162. DC_END_FN();
  1163. }
  1164. VOID
  1165. HandleVCClientDisconnect(
  1166. HANDLE waitableObject,
  1167. PVOID clientData
  1168. )
  1169. /*++
  1170. Routine Description:
  1171. Arguments:
  1172. Return Value:
  1173. ERROR_SUCCESS on success. Otherwise, an error status is returned.
  1174. --*/
  1175. {
  1176. DC_BEGIN_FN("HandleVCClientDisconnect");
  1177. DWORD dwCurTimer = GetTickCount();
  1178. //
  1179. //see if the timer wrapped around to zero (does so if the system was up 49.7 days or something), if so reset it
  1180. //
  1181. if(dwCurTimer > g_PrevTimer && ( dwCurTimer - g_PrevTimer >= g_dwTimeOutInterval)) {
  1182. //
  1183. //enough time passed since the last check. send data to client
  1184. if( SendNullDataToClient() != ERROR_SUCCESS ) {
  1185. //
  1186. //set the shutdown flag
  1187. //
  1188. g_Shutdown = TRUE;
  1189. g_ClientConnected = FALSE;
  1190. }
  1191. }
  1192. g_PrevTimer = dwCurTimer;
  1193. DC_END_FN();
  1194. }
  1195. VOID
  1196. HandleNamedPipeReadComplete(
  1197. OVERLAPPED &incomingPipeOL,
  1198. IOBUFFER &incomingPipeBuf
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. Handle a read complete event on the session's named pipe.
  1203. Arguments:
  1204. incomingPipeOL - Overlapped Read Struct
  1205. incomingPipeBuf - Incoming Data Buffer.
  1206. Return Value:
  1207. --*/
  1208. {
  1209. DC_BEGIN_FN("HandleNamedPipeReadComplete");
  1210. DWORD bytesRead;
  1211. DWORD requiredSize;
  1212. BOOL disconnectClientPipe = FALSE;
  1213. DWORD result;
  1214. DWORD bytesToRead;
  1215. HANDLE waitableObjects[2];
  1216. DWORD waitResult;
  1217. //
  1218. // Get the results of the read on the buffer header.
  1219. //
  1220. if (!GetOverlappedResult(
  1221. g_ClientSessionPipe,
  1222. &incomingPipeOL,
  1223. &bytesRead,
  1224. FALSE)
  1225. || (bytesRead != sizeof(REMOTEDESKTOP_CHANNELBUFHEADER))) {
  1226. disconnectClientPipe = TRUE;
  1227. goto CLEANUPANDEXIT;
  1228. }
  1229. //
  1230. // Make sure the incoming buffer is large enough.
  1231. //
  1232. requiredSize = incomingPipeBuf.buffer->dataLen +
  1233. incomingPipeBuf.buffer->channelNameLen +
  1234. sizeof(REMOTEDESKTOP_CHANNELBUFHEADER);
  1235. if (incomingPipeBuf.bufSize < requiredSize) {
  1236. PREMOTEDESKTOP_CHANNELBUFHEADER pBuffer = NULL;
  1237. pBuffer = (PREMOTEDESKTOP_CHANNELBUFHEADER )REALLOCMEM(
  1238. incomingPipeBuf.buffer,
  1239. requiredSize
  1240. );
  1241. if (pBuffer != NULL) {
  1242. incomingPipeBuf.buffer = pBuffer;
  1243. incomingPipeBuf.bufSize = requiredSize;
  1244. }
  1245. else {
  1246. TRC_ERR((TB, L"Shutting down because of memory allocation failure."));
  1247. g_Shutdown = TRUE;
  1248. goto CLEANUPANDEXIT;
  1249. }
  1250. }
  1251. //
  1252. // Now read the buffer data.
  1253. //
  1254. incomingPipeOL.Internal = 0;
  1255. incomingPipeOL.InternalHigh = 0;
  1256. incomingPipeOL.Offset = 0;
  1257. incomingPipeOL.OffsetHigh = 0;
  1258. ResetEvent(incomingPipeOL.hEvent);
  1259. if (!ReadFile(
  1260. g_ClientSessionPipe,
  1261. incomingPipeBuf.buffer + 1,
  1262. incomingPipeBuf.buffer->channelNameLen +
  1263. incomingPipeBuf.buffer->dataLen,
  1264. &bytesRead, &incomingPipeOL)
  1265. ) {
  1266. if (GetLastError() == ERROR_IO_PENDING) {
  1267. waitableObjects[0] = incomingPipeOL.hEvent;
  1268. waitableObjects[1] = g_ShutdownEvent;
  1269. waitResult = WaitForMultipleObjects(
  1270. 2, waitableObjects,
  1271. FALSE,
  1272. INFINITE
  1273. );
  1274. if ((waitResult != WAIT_OBJECT_0) || g_Shutdown) {
  1275. disconnectClientPipe = TRUE;
  1276. goto CLEANUPANDEXIT;
  1277. }
  1278. if (!GetOverlappedResult(
  1279. g_ClientSessionPipe,
  1280. &incomingPipeOL,
  1281. &bytesRead,
  1282. FALSE)) {
  1283. disconnectClientPipe = TRUE;
  1284. goto CLEANUPANDEXIT;
  1285. }
  1286. }
  1287. else {
  1288. disconnectClientPipe = TRUE;
  1289. goto CLEANUPANDEXIT;
  1290. }
  1291. }
  1292. //
  1293. // Make sure we got all the data.
  1294. //
  1295. bytesToRead = incomingPipeBuf.buffer->channelNameLen +
  1296. incomingPipeBuf.buffer->dataLen;
  1297. if (bytesRead != bytesToRead) {
  1298. TRC_ERR((TB, L"Bytes read: %ld != bytes requested: %ld",
  1299. bytesRead, bytesToRead));
  1300. ASSERT(FALSE);
  1301. disconnectClientPipe = TRUE;
  1302. goto CLEANUPANDEXIT;
  1303. }
  1304. //
  1305. // Handle the read data.
  1306. //
  1307. HandleReceivedPipeMsg(incomingPipeBuf);
  1308. //
  1309. // Issue the read for the next message header.
  1310. //
  1311. result = IssueNamedPipeOverlappedRead(
  1312. incomingPipeBuf,
  1313. incomingPipeOL,
  1314. sizeof(REMOTEDESKTOP_CHANNELBUFHEADER)
  1315. );
  1316. disconnectClientPipe = (result != ERROR_SUCCESS);
  1317. CLEANUPANDEXIT:
  1318. //
  1319. // This is considered a fatal error because the client session must
  1320. // no longer be in "listen" mode.
  1321. //
  1322. if (disconnectClientPipe) {
  1323. TRC_ERR((TB, L"Connection to client pipe lost: %08X",
  1324. GetLastError()));
  1325. g_Shutdown = TRUE;
  1326. }
  1327. DC_END_FN();
  1328. }
  1329. VOID
  1330. HandleReceivedPipeMsg(
  1331. IOBUFFER &msg
  1332. )
  1333. /*++
  1334. Routine Description:
  1335. Arguments:
  1336. Return Value:
  1337. --*/
  1338. {
  1339. DC_BEGIN_FN("HandleReceivedPipeMsg");
  1340. DWORD result;
  1341. //
  1342. // Forward the message to the client.
  1343. //
  1344. result = SendMsgToClient(msg.buffer);
  1345. //
  1346. // This is considered a fatal error. The client will need to reconnect
  1347. // to get things started again.
  1348. //
  1349. if (result != ERROR_SUCCESS) {
  1350. TRC_ERR((TB, L"Shutting down because of VC IO error."));
  1351. g_Shutdown = TRUE;
  1352. }
  1353. DC_END_FN();
  1354. }
  1355. DWORD
  1356. ConnectVC()
  1357. /*++
  1358. Routine Description:
  1359. Arguments:
  1360. Return Value:
  1361. ERROR_SUCCESS on success. Otherwise, an error status is returned.
  1362. --*/
  1363. {
  1364. DC_BEGIN_FN("ConnectVC");
  1365. WCHAR buf[256];
  1366. DWORD len;
  1367. PVOID vcFileHandlePtr;
  1368. REMOTEDESKTOP_CTL_SERVERANNOUNCE_PACKET msg;
  1369. REMOTEDESKTOP_CTL_VERSIONINFO_PACKET versionInfoMsg;
  1370. DWORD result = ERROR_SUCCESS;
  1371. //
  1372. // Open the virtual channel.
  1373. //
  1374. g_VCHandle = WTSVirtualChannelOpen(
  1375. WTS_CURRENT_SERVER_HANDLE,
  1376. WTS_CURRENT_SESSION,
  1377. TSRDPREMOTEDESKTOP_VC_CHANNEL_A
  1378. );
  1379. if (g_VCHandle == NULL) {
  1380. result = GetLastError();
  1381. if (result == ERROR_SUCCESS) { result = E_FAIL; }
  1382. TRC_ERR((TB, L"WTSVirtualChannelOpen: %08X", result));
  1383. goto CLEANUPANDEXIT;
  1384. }
  1385. //
  1386. // Get access to the underlying file handle for async IO.
  1387. //
  1388. if (!WTSVirtualChannelQuery(
  1389. g_VCHandle,
  1390. WTSVirtualFileHandle,
  1391. &vcFileHandlePtr,
  1392. &len
  1393. )) {
  1394. result = GetLastError();
  1395. TRC_ERR((TB, L"WTSQuerySessionInformation: %08X", result));
  1396. goto CLEANUPANDEXIT;
  1397. }
  1398. ASSERT(len == sizeof(g_VCFileHandle));
  1399. //
  1400. // WTSVirtualChannelQuery allocates the returned buffer.
  1401. //
  1402. memcpy(&g_VCFileHandle, vcFileHandlePtr, sizeof(g_VCFileHandle));
  1403. LocalFree(vcFileHandlePtr);
  1404. //
  1405. //create the timer event, we will start it later
  1406. //it will be signaled when the time is up
  1407. //
  1408. g_ClientIsconnectEvent = CreateWaitableTimer( NULL, FALSE, NULL);
  1409. if (g_ClientIsconnectEvent == NULL) {
  1410. result = GetLastError();
  1411. TRC_ERR((TB, L"CreateEvent: %08X", result));
  1412. goto CLEANUPANDEXIT;
  1413. }
  1414. //
  1415. // Create the read finish event.
  1416. //
  1417. g_VCReadOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1418. if (g_VCReadOverlapped.hEvent == NULL) {
  1419. result = GetLastError();
  1420. TRC_ERR((TB, L"CreateEvent: %08X", result));
  1421. goto CLEANUPANDEXIT;
  1422. }
  1423. //
  1424. // Register the read finish event.
  1425. //
  1426. result = WTBLOBJ_AddWaitableObject(
  1427. g_WaitObjMgr, NULL,
  1428. g_VCReadOverlapped.hEvent,
  1429. HandleVCReadComplete
  1430. );
  1431. if (result != ERROR_SUCCESS) {
  1432. goto CLEANUPANDEXIT;
  1433. }
  1434. // register the disconnect event
  1435. //NOTE : order IS important
  1436. //waitformultipleobjects returns the lowest index
  1437. //when more than one are signaled
  1438. //we want to use the read event, not the disconnect event
  1439. //in case both are signaled
  1440. result = WTBLOBJ_AddWaitableObject(
  1441. g_WaitObjMgr, NULL,
  1442. g_ClientIsconnectEvent,
  1443. HandleVCClientDisconnect
  1444. );
  1445. if (result != ERROR_SUCCESS) {
  1446. goto CLEANUPANDEXIT;
  1447. }
  1448. //
  1449. // Allocate space for the first VC read.
  1450. //
  1451. g_IncomingVCBuf.buffer = (PREMOTEDESKTOP_CHANNELBUFHEADER )ALLOCMEM(
  1452. VCBUFFER_RESIZE_DELTA
  1453. );
  1454. if (g_IncomingVCBuf.buffer != NULL) {
  1455. g_IncomingVCBuf.bufSize = VCBUFFER_RESIZE_DELTA;
  1456. g_IncomingVCBuf.offset = 0;
  1457. }
  1458. else {
  1459. TRC_ERR((TB, L"Can't allocate VC read buffer."));
  1460. result = ERROR_NOT_ENOUGH_MEMORY;
  1461. goto CLEANUPANDEXIT;
  1462. }
  1463. //
  1464. // Issue the first overlapped read on the VC.
  1465. //
  1466. result = IssueVCOverlappedRead(g_IncomingVCBuf, g_VCReadOverlapped);
  1467. if (result != ERROR_SUCCESS) {
  1468. goto CLEANUPANDEXIT;
  1469. }
  1470. //
  1471. // Notify the client that we are alive.
  1472. //
  1473. memcpy(msg.packetHeader.channelName, REMOTEDESKTOP_RC_CONTROL_CHANNEL,
  1474. sizeof(REMOTEDESKTOP_RC_CONTROL_CHANNEL));
  1475. msg.packetHeader.channelBufHeader.channelNameLen = REMOTEDESKTOP_RC_CHANNELNAME_LENGTH;
  1476. #ifdef USE_MAGICNO
  1477. msg.packetHeader.channelBufHeader.magicNo = CHANNELBUF_MAGICNO;
  1478. #endif
  1479. msg.packetHeader.channelBufHeader.dataLen =
  1480. sizeof(REMOTEDESKTOP_CTL_SERVERANNOUNCE_PACKET) -
  1481. sizeof(REMOTEDESKTOP_CTL_PACKETHEADER);
  1482. msg.msgHeader.msgType = REMOTEDESKTOP_CTL_SERVER_ANNOUNCE;
  1483. result = SendMsgToClient((PREMOTEDESKTOP_CHANNELBUFHEADER)&msg);
  1484. if (result != ERROR_SUCCESS) {
  1485. goto CLEANUPANDEXIT;
  1486. }
  1487. //
  1488. // Send the server protocol version information.
  1489. //
  1490. memcpy(versionInfoMsg.packetHeader.channelName, REMOTEDESKTOP_RC_CONTROL_CHANNEL,
  1491. sizeof(REMOTEDESKTOP_RC_CONTROL_CHANNEL));
  1492. versionInfoMsg.packetHeader.channelBufHeader.channelNameLen = REMOTEDESKTOP_RC_CHANNELNAME_LENGTH;
  1493. #ifdef USE_MAGICNO
  1494. versionInfoMsg.packetHeader.channelBufHeader.magicNo = CHANNELBUF_MAGICNO;
  1495. #endif
  1496. versionInfoMsg.packetHeader.channelBufHeader.dataLen =
  1497. sizeof(REMOTEDESKTOP_CTL_VERSIONINFO_PACKET) -
  1498. sizeof(REMOTEDESKTOP_CTL_PACKETHEADER);
  1499. versionInfoMsg.msgHeader.msgType = REMOTEDESKTOP_CTL_VERSIONINFO;
  1500. versionInfoMsg.versionMajor = REMOTEDESKTOP_VERSION_MAJOR;
  1501. versionInfoMsg.versionMinor = REMOTEDESKTOP_VERSION_MINOR;
  1502. result = SendMsgToClient((PREMOTEDESKTOP_CHANNELBUFHEADER)&versionInfoMsg);
  1503. if (result != ERROR_SUCCESS) {
  1504. goto CLEANUPANDEXIT;
  1505. }
  1506. CLEANUPANDEXIT:
  1507. DC_END_FN();
  1508. return result;
  1509. }
  1510. DWORD
  1511. ConnectClientSessionPipe()
  1512. /*++
  1513. Routine Description:
  1514. Connect to the client session TSRDP plug-in named pipe.
  1515. Arguments:
  1516. Return Value:
  1517. ERROR_SUCCESS on success. Otherwise, an error status is returned.
  1518. --*/
  1519. {
  1520. DC_BEGIN_FN("ConnectClientSessionPipe");
  1521. unsigned dump;
  1522. WCHAR pipePath[MAX_PATH+1];
  1523. DWORD result;
  1524. DWORD pipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
  1525. //
  1526. // Loop until we are connected or time out.
  1527. //
  1528. ASSERT(g_ClientSessionPipe == NULL);
  1529. while(g_ClientSessionPipe == NULL) {
  1530. wsprintf(pipePath, L"\\\\.\\pipe\\%s-%s",
  1531. TSRDPREMOTEDESKTOP_PIPENAME, g_HelpSessionID);
  1532. g_ClientSessionPipe = CreateFile(
  1533. pipePath,
  1534. GENERIC_READ |
  1535. GENERIC_WRITE,
  1536. 0,
  1537. NULL,
  1538. OPEN_EXISTING,
  1539. FILE_FLAG_OVERLAPPED, NULL
  1540. );
  1541. if (g_ClientSessionPipe != INVALID_HANDLE_VALUE) {
  1542. TRC_NRM((TB, L"Pipe successfully connected."));
  1543. result = ERROR_SUCCESS;
  1544. break;
  1545. }
  1546. else {
  1547. TRC_ALT((TB, L"Waiting for pipe availability: %08X.",
  1548. GetLastError()));
  1549. WaitNamedPipe(pipePath, CLIENTPIPE_CONNECTTIMEOUT);
  1550. result = GetLastError();
  1551. if (result != ERROR_SUCCESS) {
  1552. TRC_ERR((TB, L"WaitNamedPipe: %08X", result));
  1553. break;
  1554. }
  1555. }
  1556. }
  1557. //
  1558. // If we didn't get a valid connection, then bail out of
  1559. // this function and shut down.
  1560. //
  1561. if (g_ClientSessionPipe == INVALID_HANDLE_VALUE) {
  1562. ASSERT(result != ERROR_SUCCESS);
  1563. TRC_ERR((TB, L"Shutting down because of named pipe error."));
  1564. g_Shutdown = TRUE;
  1565. goto CLEANUPANDEXIT;
  1566. }
  1567. //
  1568. //set the options on the pipe to be the same as that of the server end to avoid problems
  1569. //fatal if we could not set it
  1570. //
  1571. if(!SetNamedPipeHandleState(g_ClientSessionPipe,
  1572. &pipeMode, // new pipe mode
  1573. NULL,
  1574. NULL
  1575. )) {
  1576. result = GetLastError();
  1577. TRC_ERR((TB, L"Shutting down, SetNamedPipeHandleState: %08X", result));
  1578. g_Shutdown = TRUE;
  1579. goto CLEANUPANDEXIT;
  1580. }
  1581. //
  1582. // Spin off the pipe read background thread.
  1583. //
  1584. g_NamedPipeReadThread = (HANDLE)_beginthreadex(NULL, 0, NamedPipeReadThread, NULL, 0, &dump);
  1585. if ((uintptr_t)g_NamedPipeReadThread == -1) {
  1586. g_NamedPipeReadThread = NULL;
  1587. TRC_ERR((TB, L"Failed to create NamedPipeReadThread: %08X", GetLastError()));
  1588. g_Shutdown = TRUE;
  1589. result = errno;
  1590. goto CLEANUPANDEXIT;
  1591. }
  1592. CLEANUPANDEXIT:
  1593. DC_END_FN();
  1594. return result;
  1595. }
  1596. unsigned __stdcall
  1597. NamedPipeReadThread(
  1598. void* ptr
  1599. )
  1600. /*++
  1601. Routine Description:
  1602. Named Pipe Input Thread
  1603. Arguments:
  1604. ptr - Ignored
  1605. Return Value:
  1606. NA
  1607. --*/
  1608. {
  1609. DC_BEGIN_FN("NamedPipeReadThread");
  1610. IOBUFFER incomingPipeBuf = { NULL, 0, 0 };
  1611. OVERLAPPED overlapped = { 0, 0, 0, 0, NULL };
  1612. DWORD waitResult;
  1613. DWORD ret;
  1614. HANDLE waitableObjects[2];
  1615. //
  1616. // Allocate the initial buffer for incoming named pipe data.
  1617. //
  1618. incomingPipeBuf.buffer = (PREMOTEDESKTOP_CHANNELBUFHEADER )
  1619. ALLOCMEM(sizeof(REMOTEDESKTOP_CHANNELBUFHEADER));
  1620. if (incomingPipeBuf.buffer != NULL) {
  1621. incomingPipeBuf.bufSize = sizeof(REMOTEDESKTOP_CHANNELBUFHEADER);
  1622. }
  1623. else {
  1624. TRC_ERR((TB, L"Can't allocate named pipe buf."));
  1625. g_Shutdown = TRUE;
  1626. goto CLEANUPANDEXIT;
  1627. }
  1628. //
  1629. // Create the overlapped pipe read event.
  1630. //
  1631. overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1632. if (overlapped.hEvent == NULL) {
  1633. TRC_ERR((TB, L"CreateEvent: %08X", GetLastError()));
  1634. g_Shutdown = TRUE;
  1635. goto CLEANUPANDEXIT;
  1636. }
  1637. //
  1638. // Issue the read for the first message header.
  1639. //
  1640. ret = IssueNamedPipeOverlappedRead(
  1641. incomingPipeBuf,
  1642. overlapped,
  1643. sizeof(REMOTEDESKTOP_CHANNELBUFHEADER)
  1644. );
  1645. //
  1646. // If we can't connect, that's considered a fatal error because
  1647. // the client must no longer be in "listen" mode.
  1648. //
  1649. if (ret != ERROR_SUCCESS) {
  1650. TRC_ERR((TB, L"Shutting down because of named pipe error."));
  1651. g_Shutdown = TRUE;
  1652. }
  1653. //
  1654. // Loop until shut down.
  1655. //
  1656. waitableObjects[0] = overlapped.hEvent;
  1657. waitableObjects[1] = g_ShutdownEvent;
  1658. while (!g_Shutdown) {
  1659. //
  1660. // We will be signalled when the pipe closes or the read completes.
  1661. //
  1662. waitResult = WaitForMultipleObjects(
  1663. 2, waitableObjects,
  1664. FALSE,
  1665. INFINITE
  1666. );
  1667. if ((waitResult == WAIT_OBJECT_0) && !g_Shutdown) {
  1668. HandleNamedPipeReadComplete(overlapped, incomingPipeBuf);
  1669. }
  1670. else {
  1671. TRC_ERR((TB, L"WaitForMultipleObjects: %08X", GetLastError()));
  1672. g_Shutdown = TRUE;
  1673. }
  1674. }
  1675. CLEANUPANDEXIT:
  1676. //
  1677. // Make sure the foreground thread knows that we are shutting down.
  1678. //
  1679. if (g_WakeUpForegroundThreadEvent != NULL) {
  1680. SetEvent(g_WakeUpForegroundThreadEvent);
  1681. }
  1682. if (overlapped.hEvent != NULL) {
  1683. CloseHandle(overlapped.hEvent);
  1684. }
  1685. if (incomingPipeBuf.buffer != NULL) {
  1686. FREEMEM(incomingPipeBuf.buffer);
  1687. }
  1688. DC_END_FN();
  1689. _endthreadex(0);
  1690. return 0;
  1691. }
  1692. VOID WakeUpFunc(
  1693. HANDLE waitableObject,
  1694. PVOID clientData
  1695. )
  1696. /*++
  1697. Routine Description:
  1698. Stub function, called when the background thread wants the foreground
  1699. thread to wake up because of a state change.
  1700. Arguments:
  1701. Return Value:
  1702. --*/
  1703. {
  1704. DC_BEGIN_FN("WakeUpFunc");
  1705. DC_END_FN();
  1706. }
  1707. VOID HandleHelpCenterExit(
  1708. HANDLE waitableObject,
  1709. PVOID clientData
  1710. )
  1711. /*++
  1712. Routine Description:
  1713. Woken up when Help Center exits as a fix for B2 Stopper: 342742
  1714. Arguments:
  1715. Return Value:
  1716. --*/
  1717. {
  1718. DC_BEGIN_FN("HandleHelpCenterExit");
  1719. g_Shutdown = TRUE;
  1720. DC_END_FN();
  1721. }
  1722. extern "C"
  1723. int
  1724. __cdecl
  1725. wmain( int argc, wchar_t *argv[])
  1726. {
  1727. DC_BEGIN_FN("Main");
  1728. DWORD result = ERROR_SUCCESS;
  1729. DWORD sz;
  1730. HRESULT hr;
  1731. LARGE_INTEGER liDueTime;
  1732. BOOL backgroundThreadFailedToExit = FALSE;
  1733. DWORD waitResult;
  1734. SetConsoleCtrlHandler( ControlHandler, TRUE );
  1735. //
  1736. // Expecting two parameters, first is HelpSession ID and second is
  1737. // HelpSession Password, we don't want to failed here just because
  1738. // number of argument mismatched, we will let authentication fail and
  1739. // return error code.
  1740. //
  1741. ASSERT( argc == 2 );
  1742. if( argc >= 2 ) {
  1743. g_bstrCmdLineHelpSessionId = argv[1];
  1744. TRC_ALT((TB, L"Input Parameters 1 : %ws ", argv[1]));
  1745. }
  1746. //
  1747. // Initialize Critical Section
  1748. //
  1749. __try
  1750. {
  1751. InitializeCriticalSection( &g_cs );
  1752. }
  1753. __except( EXCEPTION_EXECUTE_HANDLER )
  1754. {
  1755. TRC_ERR( ( TB , L"InitializeCriticalSection failed" ) );
  1756. return E_OUTOFMEMORY;
  1757. }
  1758. //
  1759. // Initialize COM.
  1760. //
  1761. hr = CoInitialize(NULL);
  1762. if (!SUCCEEDED(hr)) {
  1763. result = E_FAIL;
  1764. TRC_ERR((TB, L"CoInitialize: %08X", hr));
  1765. goto CLEANUPANDEXIT;
  1766. }
  1767. //
  1768. // Get our process.
  1769. //
  1770. g_ProcHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
  1771. GetCurrentProcessId());
  1772. if (g_ProcHandle == NULL) {
  1773. result = GetLastError();
  1774. TRC_ERR((TB, L"OpenProcess: %08X", result));
  1775. goto CLEANUPANDEXIT;
  1776. }
  1777. //
  1778. // Get our process token.
  1779. //
  1780. if (!OpenProcessToken(g_ProcHandle, TOKEN_READ, &g_ProcToken)) {
  1781. result = GetLastError();
  1782. TRC_ERR((TB, L"OpenProcessToken: %08X", result));
  1783. goto CLEANUPANDEXIT;
  1784. }
  1785. //
  1786. // Get our session ID.
  1787. //
  1788. if (!GetTokenInformation(g_ProcToken, TokenSessionId,
  1789. &g_SessionID, sizeof(g_SessionID), &sz)) {
  1790. result = GetLastError();
  1791. TRC_ERR((TB, L"GetTokenInformation: %08X", result));
  1792. goto CLEANUPANDEXIT;
  1793. }
  1794. //
  1795. // Initialize the waitable object manager.
  1796. //
  1797. g_WaitObjMgr = WTBLOBJ_CreateWaitableObjectMgr();
  1798. if (g_WaitObjMgr == NULL) {
  1799. result = E_FAIL;
  1800. goto CLEANUPANDEXIT;
  1801. }
  1802. //
  1803. //initialize the timer, get the timer interval from registry or use default
  1804. //used for finding if the client (expert) is still connected
  1805. //
  1806. g_PrevTimer = GetTickCount();
  1807. if(!GetDwordFromRegistry(&g_dwTimeOutInterval))
  1808. g_dwTimeOutInterval = RDS_CHECKCONN_TIMEOUT;
  1809. else
  1810. g_dwTimeOutInterval *= 1000; //we need this in millisec
  1811. liDueTime.QuadPart = -1 * g_dwTimeOutInterval * 1000 * 100; //in one hundred nanoseconds
  1812. //
  1813. // Initiate the VC channel connection.
  1814. //
  1815. result = ConnectVC();
  1816. if (result != ERROR_SUCCESS) {
  1817. goto CLEANUPANDEXIT;
  1818. }
  1819. //
  1820. // This is an event the background thread can use to wake up the
  1821. // foreground thread in order to check state.
  1822. //
  1823. g_WakeUpForegroundThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1824. if (g_WakeUpForegroundThreadEvent == NULL) {
  1825. TRC_ERR((TB, L"CreateEvent: %08X", GetLastError()));
  1826. result = E_FAIL;
  1827. goto CLEANUPANDEXIT;
  1828. }
  1829. result = WTBLOBJ_AddWaitableObject(
  1830. g_WaitObjMgr, NULL,
  1831. g_WakeUpForegroundThreadEvent,
  1832. WakeUpFunc
  1833. );
  1834. if (result != ERROR_SUCCESS) {
  1835. goto CLEANUPANDEXIT;
  1836. }
  1837. //
  1838. // Create the named pipe write complete event.
  1839. //
  1840. g_NamedPipeWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1841. if (g_NamedPipeWriteEvent == NULL) {
  1842. result = GetLastError();
  1843. TRC_ERR((TB, L"CreateEvent: %08X", result));
  1844. goto CLEANUPANDEXIT;
  1845. }
  1846. //
  1847. //start the timer event, ignore error. 0 in the registry means don't send any pings
  1848. //worst case, we don't get disconnected which is fine
  1849. //
  1850. if(g_dwTimeOutInterval)
  1851. SetWaitableTimer( g_ClientIsconnectEvent, &liDueTime, g_dwTimeOutInterval, NULL, NULL, FALSE );
  1852. //
  1853. // Create the shutdown event.
  1854. //
  1855. g_ShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1856. if (g_ShutdownEvent == NULL) {
  1857. result = GetLastError();
  1858. TRC_ERR((TB, L"CreateEvent: %08X", result));
  1859. goto CLEANUPANDEXIT;
  1860. }
  1861. //
  1862. // Handle IO events until the shut down flag is set.
  1863. //
  1864. while (!g_Shutdown) {
  1865. result = WTBLOBJ_PollWaitableObjects(g_WaitObjMgr);
  1866. if (result != ERROR_SUCCESS) {
  1867. g_Shutdown = TRUE;
  1868. }
  1869. }
  1870. //
  1871. // Notify the client that we have disconnected, in case it hasn't
  1872. // figured it out yet.
  1873. //
  1874. if (g_VCFileHandle != NULL) {
  1875. REMOTEDESKTOP_CTL_DISCONNECT_PACKET msg;
  1876. memcpy(msg.packetHeader.channelName, REMOTEDESKTOP_RC_CONTROL_CHANNEL,
  1877. sizeof(REMOTEDESKTOP_RC_CONTROL_CHANNEL));
  1878. msg.packetHeader.channelBufHeader.channelNameLen =
  1879. REMOTEDESKTOP_RC_CHANNELNAME_LENGTH;
  1880. #ifdef USE_MAGICNO
  1881. msg.packetHeader.channelBufHeader.magicNo = CHANNELBUF_MAGICNO;
  1882. #endif
  1883. msg.packetHeader.channelBufHeader.dataLen =
  1884. sizeof(REMOTEDESKTOP_CTL_DISCONNECT_PACKET) -
  1885. sizeof(REMOTEDESKTOP_CTL_PACKETHEADER);
  1886. msg.msgHeader.msgType = REMOTEDESKTOP_CTL_DISCONNECT;
  1887. SendMsgToClient((PREMOTEDESKTOP_CHANNELBUFHEADER)&msg);
  1888. }
  1889. CLEANUPANDEXIT:
  1890. //
  1891. // Signal the shutdown event.
  1892. //
  1893. if (g_ShutdownEvent != NULL) {
  1894. SetEvent(g_ShutdownEvent);
  1895. }
  1896. //
  1897. // Wait for the background threads to exit.
  1898. //
  1899. if (g_RemoteControlDesktopThread != NULL) {
  1900. // if we can get here, force a shadow stop
  1901. WinStationShadowStop(
  1902. SERVERNAME_CURRENT,
  1903. g_ClientSessionID,
  1904. TRUE
  1905. );
  1906. waitResult = WaitForSingleObject(
  1907. g_RemoteControlDesktopThread,
  1908. THREADSHUTDOWN_WAITTIMEOUT
  1909. );
  1910. if (waitResult != WAIT_OBJECT_0) {
  1911. backgroundThreadFailedToExit = TRUE;
  1912. TRC_ERR((TB, L"WaitForSingleObject g_RemoteControlDesktopThread: %ld",
  1913. waitResult));
  1914. }
  1915. CloseHandle( g_RemoteControlDesktopThread );
  1916. }
  1917. if (g_NamedPipeReadThread != NULL) {
  1918. waitResult = WaitForSingleObject(
  1919. g_NamedPipeReadThread,
  1920. THREADSHUTDOWN_WAITTIMEOUT
  1921. );
  1922. if (waitResult != WAIT_OBJECT_0) {
  1923. backgroundThreadFailedToExit = TRUE;
  1924. TRC_ERR((TB, L"WaitForSingleObject g_NamedPipeReadThread: %ld", waitResult));
  1925. }
  1926. CloseHandle( g_NamedPipeReadThread );
  1927. }
  1928. if (g_hHelpCenterProcess) {
  1929. CloseHandle(g_hHelpCenterProcess);
  1930. }
  1931. if( g_HelpSessionManager != NULL ) {
  1932. g_HelpSessionManager.Release();
  1933. }
  1934. if (g_WaitObjMgr != NULL) {
  1935. WTBLOBJ_DeleteWaitableObjectMgr(g_WaitObjMgr);
  1936. }
  1937. if (g_ProcHandle != NULL) {
  1938. CloseHandle(g_ProcHandle);
  1939. }
  1940. if (g_ClientIsconnectEvent != NULL) {
  1941. CloseHandle(g_ClientIsconnectEvent);
  1942. }
  1943. if (g_VCReadOverlapped.hEvent != NULL) {
  1944. CloseHandle(g_VCReadOverlapped.hEvent);
  1945. }
  1946. if (g_ClientSessionPipe != NULL) {
  1947. CloseHandle(g_ClientSessionPipe);
  1948. }
  1949. if (g_IncomingVCBuf.buffer != NULL) {
  1950. FREEMEM(g_IncomingVCBuf.buffer);
  1951. }
  1952. if (g_ShutdownEvent != NULL) {
  1953. CloseHandle(g_ShutdownEvent);
  1954. g_ShutdownEvent = NULL;
  1955. }
  1956. if (g_NamedPipeWriteEvent != NULL) {
  1957. CloseHandle(g_NamedPipeWriteEvent);
  1958. }
  1959. CoUninitialize();
  1960. DeleteCriticalSection( &g_cs );
  1961. DC_END_FN();
  1962. //
  1963. // If any of the background threads failed to exit then terminate
  1964. // the process.
  1965. //
  1966. if (backgroundThreadFailedToExit) {
  1967. ExitProcess(0);
  1968. }
  1969. return result;
  1970. }
  1971. DWORD
  1972. SendNullDataToClient(
  1973. )
  1974. /*++
  1975. Routine Description:
  1976. sends a null data packet to client.
  1977. Only purpose is to find out if the client is still connected; if not we exit the process
  1978. REMOTEDESKTOP_RC_CONTROL_CHANNEL channel REMOTEDESKTOP_CTL_RESULT message.
  1979. Arguments:
  1980. Return Value:
  1981. ERROR_SUCCESS on success. Otherwise, an error code is returned.
  1982. --*/
  1983. {
  1984. DC_BEGIN_FN("SendNullDataToClient");
  1985. DWORD result;
  1986. DWORD bytesWritten = 0;
  1987. REMOTEDESKTOP_CTL_ISCONNECTED_PACKET msg;
  1988. memcpy(msg.packetHeader.channelName, REMOTEDESKTOP_RC_CONTROL_CHANNEL,
  1989. sizeof(REMOTEDESKTOP_RC_CONTROL_CHANNEL));
  1990. msg.packetHeader.channelBufHeader.channelNameLen = REMOTEDESKTOP_RC_CHANNELNAME_LENGTH;
  1991. #ifdef USE_MAGICNO
  1992. msg.packetHeader.channelBufHeader.magicNo = CHANNELBUF_MAGICNO;
  1993. #endif
  1994. msg.packetHeader.channelBufHeader.dataLen = sizeof(REMOTEDESKTOP_CTL_ISCONNECTED_PACKET) -
  1995. sizeof(REMOTEDESKTOP_CTL_PACKETHEADER);
  1996. msg.msgHeader.msgType = REMOTEDESKTOP_CTL_ISCONNECTED;
  1997. result = SendMsgToClient((PREMOTEDESKTOP_CHANNELBUFHEADER )&msg);
  1998. //if we couldn't write all data to the client
  1999. //if we could write some data, assume it is still connected
  2000. //client probably disconnected
  2001. if(result != ERROR_SUCCESS)
  2002. result = SAFERROR_SESSIONNOTCONNECTED;
  2003. DC_END_FN();
  2004. return result;
  2005. }
  2006. BOOL GetDwordFromRegistry(PDWORD pdwValue)
  2007. {
  2008. BOOL fSuccess = FALSE;
  2009. HKEY hKey = NULL;
  2010. if( NULL == pdwValue )
  2011. return FALSE;
  2012. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2013. REG_CONTROL_SALEM,
  2014. 0,
  2015. KEY_READ,
  2016. &hKey
  2017. ) == ERROR_SUCCESS ) {
  2018. DWORD dwSize = sizeof(DWORD);
  2019. DWORD dwType;
  2020. if((RegQueryValueEx(hKey,
  2021. RDC_CONNCHECK_ENTRY,
  2022. NULL,
  2023. &dwType,
  2024. (PBYTE) pdwValue,
  2025. &dwSize
  2026. ) == ERROR_SUCCESS) && dwType == REG_DWORD ) {
  2027. //
  2028. //fall back to default
  2029. //
  2030. fSuccess = TRUE;
  2031. }
  2032. }
  2033. CLEANUPANDEXIT:
  2034. if(NULL != hKey )
  2035. RegCloseKey(hKey);
  2036. return fSuccess;
  2037. }