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.

3304 lines
83 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. TSRDPRemoteDesktopClient
  5. Abstract:
  6. This is the TS/RDP implementation of the Remote Desktop Client class.
  7. The Remote Desktop Client class hierarchy provides a pluggable C++
  8. interface for remote desktop access, by abstracting the implementation
  9. specific details of remote desktop access for the client-side
  10. The TSRDPRemoteDesktopClass implements remote-desktopping
  11. with the help of an instance of the MSTSC ActiveX client control.
  12. Author:
  13. Tad Brockway 02/00
  14. Revision History:
  15. --*/
  16. #include "stdafx.h"
  17. #ifdef TRC_FILE
  18. #undef TRC_FILE
  19. #endif
  20. #define TRC_FILE "_tsrdpc"
  21. #include "RDCHost.h"
  22. #include "TSRDPRemoteDesktopClient.h"
  23. #include <RemoteDesktopChannels.h>
  24. #include <mstsax_i.c>
  25. #include <TSRDPRemoteDesktop.h>
  26. #include <Security.h>
  27. #include "pchannel.h"
  28. #include <tsremdsk.h>
  29. #include <sessmgr.h>
  30. #include <sessmgr_i.c>
  31. #include <regapi.h>
  32. #include "parseaddr.h"
  33. #include "icshelpapi.h"
  34. #include <tsperf.h>
  35. #include "base64.h"
  36. #include "RAEventMsg.h"
  37. #define ISRCSTATUSCODE(code) ((code) > SAFERROR_SHADOWEND_BASE)
  38. //
  39. // Variable to manage WinSock and ICS library startup/shutdown
  40. //
  41. LONG CTSRDPRemoteDesktopClient::gm_ListeningLibraryRefCount = 0; // Number of time that WinSock is intialized
  42. HRESULT
  43. CTSRDPRemoteDesktopClient::InitListeningLibrary()
  44. /*++
  45. Description:
  46. Function to initialize WinSock and ICS library for StartListen(), function add
  47. reference count to library if WinSock/ICS library already initialized.
  48. Parameters:
  49. None.
  50. Returns:
  51. S_OK or error code.
  52. --*/
  53. {
  54. WSADATA wsaData;
  55. WORD versionRequested;
  56. INT intRC;
  57. DWORD dwStatus;
  58. HRESULT hr = S_OK;
  59. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::InitListeningLibrary");
  60. // Our COM object is apartment-threaded model, need a critical section if
  61. // we switch to multi-threaded
  62. if( gm_ListeningLibraryRefCount == 0 )
  63. {
  64. //
  65. // Initialize WinSock.
  66. //
  67. versionRequested = MAKEWORD(1, 1);
  68. intRC = WSAStartup(versionRequested, &wsaData);
  69. if( intRC != 0 )
  70. {
  71. intRC = WSAGetLastError();
  72. TRC_ERR((TB, _T("WSAStartup failed %d"), intRC));
  73. TRC_ASSERT( (intRC == 0), (TB, _T("WSAStartup failed...\n")) );
  74. hr = HRESULT_FROM_WIN32( intRC );
  75. goto CLEANUPANDEXIT;
  76. }
  77. /************************************************************************/
  78. /* Now confirm that this WinSock supports version 1.1. Note that if */
  79. /* the DLL supports versions greater than 1.1 in addition to 1.1 then */
  80. /* it will still return 1.1 in the version information as that is the */
  81. /* version requested. */
  82. /************************************************************************/
  83. if ((LOBYTE(wsaData.wVersion) != 1) ||
  84. (HIBYTE(wsaData.wVersion) != 1))
  85. {
  86. /********************************************************************/
  87. /* Oops - this WinSock doesn't support version 1.1. */
  88. /********************************************************************/
  89. TRC_ERR((TB, _T("WinSock doesn't support version 1.1")));
  90. WSACleanup();
  91. hr = HRESULT_FROM_WIN32( WSAVERNOTSUPPORTED );
  92. goto CLEANUPANDEXIT;
  93. }
  94. //
  95. // Initialize ICS library.
  96. //
  97. dwStatus = StartICSLib();
  98. if( ERROR_SUCCESS != dwStatus )
  99. {
  100. // Shutdown WinSock so that we have a matching WSAStatup() and StartICSLib().
  101. WSACleanup();
  102. hr = HRESULT_FROM_WIN32( dwStatus );
  103. TRC_ERR((TB, _T("StartICSLib() failed with %d"), dwStatus));
  104. TRC_ASSERT( (ERROR_SUCCESS == dwStatus), (TB, _T("StartICSLib() failed...\n")) );
  105. goto CLEANUPANDEXIT;
  106. }
  107. }
  108. InterlockedIncrement( &gm_ListeningLibraryRefCount );
  109. CLEANUPANDEXIT:
  110. DC_END_FN();
  111. return hr;
  112. }
  113. HRESULT
  114. CTSRDPRemoteDesktopClient::TerminateListeningLibrary()
  115. /*++
  116. Description:
  117. Function to shutdown ICS libaray and WinSock, decrement reference count
  118. if more than one object is referencing WinSock/ICS library.
  119. Parameters:
  120. None.
  121. Returns:
  122. S_OK or error code
  123. Note:
  124. Not multi-thread safe, need CRITICAL_SECTION if we switch to multi-threaded
  125. model.
  126. --*/
  127. {
  128. HRESULT hr = S_OK;
  129. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::TerminateListeningLibrary");
  130. ASSERT( gm_ListeningLibraryRefCount > 0 );
  131. if( gm_ListeningLibraryRefCount <= 0 )
  132. {
  133. TRC_ERR((TB, _T("TerminateListeningLibrary() called before InitListeningLibrary()")));
  134. hr = HRESULT_FROM_WIN32(WSANOTINITIALISED);
  135. goto CLEANUPANDEXIT;
  136. }
  137. if( 0 == InterlockedDecrement( &gm_ListeningLibraryRefCount ) )
  138. {
  139. // Stop ICS libray.
  140. StopICSLib();
  141. // Shutdown WinSock
  142. WSACleanup();
  143. }
  144. CLEANUPANDEXIT:
  145. DC_END_FN();
  146. return hr;
  147. }
  148. ///////////////////////////////////////////////////////
  149. //
  150. // CMSTSCClientEventSink Methods
  151. //
  152. CMSTSCClientEventSink::~CMSTSCClientEventSink()
  153. {
  154. DC_BEGIN_FN("CMSTSCClientEventSink::~CMSTSCClientEventSink");
  155. if (m_Obj) {
  156. ASSERT(m_Obj->IsValid());
  157. }
  158. DC_END_FN();
  159. }
  160. //
  161. // Event Sinks
  162. //
  163. HRESULT __stdcall
  164. CMSTSCClientEventSink::OnRDPConnected()
  165. {
  166. m_Obj->OnRDPConnected();
  167. return S_OK;
  168. }
  169. HRESULT __stdcall
  170. CMSTSCClientEventSink::OnLoginComplete()
  171. {
  172. m_Obj->OnLoginComplete();
  173. return S_OK;
  174. }
  175. HRESULT __stdcall
  176. CMSTSCClientEventSink::OnDisconnected(
  177. long disconReason
  178. )
  179. {
  180. m_Obj->OnDisconnected(disconReason);
  181. return S_OK;
  182. }
  183. void __stdcall CMSTSCClientEventSink::OnReceiveData(
  184. BSTR chanName,
  185. BSTR data
  186. )
  187. {
  188. m_Obj->OnMSTSCReceiveData(data);
  189. }
  190. void __stdcall CMSTSCClientEventSink::OnReceivedTSPublicKey(
  191. BSTR publicKey,
  192. VARIANT_BOOL* pfbContinueLogon
  193. )
  194. {
  195. m_Obj->OnReceivedTSPublicKey(publicKey, pfbContinueLogon);
  196. }
  197. ///////////////////////////////////////////////////////
  198. //
  199. // CCtlChannelEventSink Methods
  200. //
  201. CCtlChannelEventSink::~CCtlChannelEventSink()
  202. {
  203. DC_BEGIN_FN("CCtlChannelEventSink::~CCtlChannelEventSink");
  204. if (m_Obj) {
  205. ASSERT(m_Obj->IsValid());
  206. }
  207. DC_END_FN();
  208. }
  209. //
  210. // Event Sinks
  211. //
  212. void __stdcall
  213. CCtlChannelEventSink::DataReady(BSTR channelName)
  214. {
  215. m_Obj->HandleControlChannelMsg();
  216. }
  217. ///////////////////////////////////////////////////////
  218. //
  219. // CTSRDPRemoteDesktopClient Methods
  220. //
  221. HRESULT
  222. CTSRDPRemoteDesktopClient::FinalConstruct()
  223. {
  224. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::FinalConstruct");
  225. HRESULT hr = S_OK;
  226. if (!AtlAxWinInit()) {
  227. TRC_ERR((TB, L"AtlAxWinInit failed."));
  228. hr = E_FAIL;
  229. }
  230. DC_END_FN();
  231. return hr;
  232. }
  233. CTSRDPRemoteDesktopClient::~CTSRDPRemoteDesktopClient()
  234. /*++
  235. Routine Description:
  236. The Destructor
  237. Arguments:
  238. Return Value:
  239. --*/
  240. {
  241. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::~CTSRDPRemoteDesktopClient");
  242. if (m_ChannelMgr) {
  243. m_CtlChannelEventSink.DispEventUnadvise(m_CtlChannel);
  244. }
  245. if (m_TSClient != NULL) {
  246. m_TSClient->Release();
  247. m_TSClient = NULL;
  248. }
  249. if( m_TimerId > 0 ) {
  250. KillTimer( m_TimerId );
  251. }
  252. ListenConnectCleanup();
  253. if( m_InitListeningLibrary )
  254. {
  255. // Dereference listening library.
  256. TerminateListeningLibrary();
  257. }
  258. DC_END_FN();
  259. }
  260. HRESULT
  261. CTSRDPRemoteDesktopClient::Initialize(
  262. LPCREATESTRUCT pCreateStruct
  263. )
  264. /*++
  265. Routine Description:
  266. Final Initialization
  267. Arguments:
  268. pCreateStruct - WM_CREATE, create struct.
  269. Return Value:
  270. S_OK on success. Otherwise, an error code is returned.
  271. --*/
  272. {
  273. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::Initialize");
  274. RECT rcClient = { 0, 0, pCreateStruct->cx, pCreateStruct->cy };
  275. HRESULT hr;
  276. IUnknown *pUnk = NULL;
  277. DWORD result;
  278. IMsRdpClientAdvancedSettings2 *advancedSettings;
  279. CComBSTR bstr;
  280. HKEY hKey = NULL;
  281. HRESULT hrIgnore;
  282. ASSERT(!m_Initialized);
  283. //
  284. // Create the client Window.
  285. //
  286. m_TSClientWnd = m_TSClientAxView.Create(
  287. m_hWnd, rcClient, MSTSCAX_TEXTGUID,
  288. WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, 0
  289. );
  290. if (m_TSClientWnd == NULL) {
  291. hr = HRESULT_FROM_WIN32(GetLastError());
  292. TRC_ERR((TB, L"Window Create: %08X", GetLastError()));
  293. goto CLEANUPANDEXIT;
  294. }
  295. //
  296. // Get IUnknown
  297. //
  298. hr = AtlAxGetControl(m_TSClientWnd, &pUnk);
  299. if (!SUCCEEDED(hr)) {
  300. TRC_ERR((TB, L"AtlAxGetControl: %08X", hr));
  301. pUnk = NULL;
  302. goto CLEANUPANDEXIT;
  303. }
  304. //
  305. // Initialize the event sink.
  306. //
  307. m_TSClientEventSink.m_Obj = this;
  308. //
  309. // Add the event sink.
  310. //
  311. hr = m_TSClientEventSink.DispEventAdvise(pUnk);
  312. if (!SUCCEEDED(hr)) {
  313. TRC_ERR((TB, L"DispEventAdvise: %08X", hr));
  314. goto CLEANUPANDEXIT;
  315. }
  316. //
  317. // Get the control.
  318. //
  319. hr = pUnk->QueryInterface(__uuidof(IMsRdpClient2), (void**)&m_TSClient);
  320. if (!SUCCEEDED(hr)) {
  321. TRC_ERR((TB, L"QueryInterface: %08X", hr));
  322. goto CLEANUPANDEXIT;
  323. }
  324. //
  325. // Specify that the MSTSC input handler window should accept background
  326. // events.
  327. //
  328. hr = m_TSClient->get_AdvancedSettings3(&advancedSettings);
  329. if (!SUCCEEDED(hr)) {
  330. TRC_ERR((TB, L"IMsTscAdvancedSettings: %08X", hr));
  331. goto CLEANUPANDEXIT;
  332. }
  333. hr = advancedSettings->put_allowBackgroundInput(1);
  334. //
  335. // Disable autoreconnect it doesn't apply to Salem
  336. //
  337. hr = advancedSettings->put_EnableAutoReconnect(VARIANT_FALSE);
  338. if (!SUCCEEDED(hr)) {
  339. TRC_ERR((TB, L"put_EnableAutoReconnect: %08X", hr));
  340. result = E_FAIL;
  341. goto CLEANUPANDEXIT;
  342. }
  343. //
  344. // Disable advanced desktop features for the help session.
  345. // An error here is not critical, so we ignore it.
  346. //
  347. LONG flags = TS_PERF_DISABLE_WALLPAPER | TS_PERF_DISABLE_THEMING;
  348. hrIgnore = advancedSettings->put_PerformanceFlags(flags);
  349. if (!SUCCEEDED(hrIgnore)) {
  350. TRC_ERR((TB, L"put_PerformanceFlags: %08X", hrIgnore));
  351. }
  352. //
  353. // Disable CTRL_ALT_BREAK, ignore error
  354. //
  355. hrIgnore = advancedSettings->put_HotKeyFullScreen(0);
  356. if (!SUCCEEDED(hrIgnore)) {
  357. TRC_ERR((TB, L"put_HotKeyFullScreen: %08X", hrIgnore));
  358. }
  359. //
  360. // Don't allow mstscax to grab input focus on connect. Ignore error
  361. // on failure.
  362. //
  363. hrIgnore = advancedSettings->put_GrabFocusOnConnect(FALSE);
  364. if (!SUCCEEDED(hrIgnore)) {
  365. TRC_ERR((TB, L"put_HotKeyFullScreen: %08X", hrIgnore));
  366. }
  367. advancedSettings->Release();
  368. if (!SUCCEEDED(hr)) {
  369. TRC_ERR((TB, L"put_allowBackgroundInput: %08X", hr));
  370. goto CLEANUPANDEXIT;
  371. }
  372. //
  373. // Create the "remote desktop" virtual channel with the TS Client.
  374. //
  375. bstr = TSRDPREMOTEDESKTOP_VC_CHANNEL;
  376. hr = m_TSClient->CreateVirtualChannels(bstr);
  377. if (!SUCCEEDED(hr)) {
  378. TRC_ERR((TB, L"CreateVirtualChannels: %08X", hr));
  379. result = E_FAIL;
  380. goto CLEANUPANDEXIT;
  381. }
  382. //
  383. // Set the Shadow Persistent option
  384. //
  385. hr = m_TSClient->SetVirtualChannelOptions(bstr, CHANNEL_OPTION_REMOTE_CONTROL_PERSISTENT);
  386. if (!SUCCEEDED(hr)) {
  387. TRC_ERR((TB, L"SetVirtualChannelOptions: %08X", hr));
  388. result = E_FAIL;
  389. goto CLEANUPANDEXIT;
  390. }
  391. //initialize timer-related stuff
  392. m_PrevTimer = GetTickCount();
  393. //
  394. //get the time interval for pings from the registry
  395. //
  396. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  397. REG_CONTROL_SALEM,
  398. 0,
  399. KEY_READ,
  400. &hKey
  401. ) == ERROR_SUCCESS ) {
  402. DWORD dwSize = sizeof(DWORD);
  403. DWORD dwType;
  404. if((RegQueryValueEx(hKey,
  405. RDC_CONNCHECK_ENTRY,
  406. NULL,
  407. &dwType,
  408. (PBYTE) &m_RdcConnCheckTimeInterval,
  409. &dwSize
  410. ) == ERROR_SUCCESS) && dwType == REG_DWORD ) {
  411. m_RdcConnCheckTimeInterval *= 1000; //we need this in millisecs
  412. }
  413. else
  414. {
  415. //
  416. //fall back to default, if reg lookup failed
  417. //
  418. m_RdcConnCheckTimeInterval = RDC_CHECKCONN_TIMEOUT;
  419. }
  420. }
  421. CLEANUPANDEXIT:
  422. if(NULL != hKey )
  423. RegCloseKey(hKey);
  424. //
  425. // m_TSClient keeps our reference to the client object until
  426. // the destructor is called.
  427. //
  428. if (pUnk != NULL) {
  429. pUnk->Release();
  430. }
  431. SetValid(SUCCEEDED(hr));
  432. DC_END_FN();
  433. return hr;
  434. }
  435. STDMETHODIMP
  436. CTSRDPRemoteDesktopClient::SendData(
  437. BSTR data
  438. )
  439. /*++
  440. Routine Description:
  441. IDataChannelIO Data Channel Send Method
  442. Arguments:
  443. data - Data to send.
  444. Return Value:
  445. S_OK on success. Otherwise, an error code is returned.
  446. --*/
  447. {
  448. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::SendData");
  449. CComBSTR channelName;
  450. HRESULT hr;
  451. ASSERT(IsValid());
  452. channelName = TSRDPREMOTEDESKTOP_VC_CHANNEL;
  453. hr = m_TSClient->SendOnVirtualChannel(
  454. channelName,
  455. (BSTR)data
  456. );
  457. if (!SUCCEEDED(hr)) {
  458. TRC_ERR((TB, L"SendOnVirtualChannel: %08X", hr));
  459. }
  460. //
  461. //update timer
  462. //
  463. m_PrevTimer = GetTickCount();
  464. DC_END_FN();
  465. return hr;
  466. }
  467. STDMETHODIMP
  468. CTSRDPRemoteDesktopClient::put_EnableSmartSizing(
  469. BOOL val
  470. )
  471. /*++
  472. Routine Description:
  473. Enable/Disable Smart Sizing
  474. Arguments:
  475. val - TRUE for enable. FALSE, otherwise.
  476. Return Value:
  477. S_OK on success. Otherwise, an error code is returned.
  478. --*/
  479. {
  480. HRESULT hr;
  481. IMsRdpClientAdvancedSettings *pAdvSettings = NULL;
  482. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::put_EnableSmartSizing");
  483. if (!IsValid()) {
  484. ASSERT(FALSE);
  485. hr = E_FAIL;
  486. goto CLEANUPANDEXIT;
  487. }
  488. hr = m_TSClient->get_AdvancedSettings2(&pAdvSettings);
  489. if (hr != S_OK) {
  490. TRC_ERR((TB, L"get_AdvancedSettings2: %08X", hr));
  491. goto CLEANUPANDEXIT;
  492. }
  493. hr = pAdvSettings->put_SmartSizing(val ? VARIANT_TRUE : VARIANT_FALSE);
  494. pAdvSettings->Release();
  495. CLEANUPANDEXIT:
  496. DC_END_FN();
  497. return hr;
  498. }
  499. STDMETHODIMP
  500. CTSRDPRemoteDesktopClient::get_EnableSmartSizing(
  501. BOOL *pVal
  502. )
  503. /*++
  504. Routine Description:
  505. Enable/Disable Smart Sizing
  506. Arguments:
  507. val - TRUE for enable. FALSE, otherwise.
  508. Return Value:
  509. S_OK on success. Otherwise, an error code is returned.
  510. --*/
  511. {
  512. HRESULT hr;
  513. VARIANT_BOOL vb;
  514. IMsRdpClientAdvancedSettings *pAdvSettings = NULL;
  515. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::put_EnableSmartSizing");
  516. if (!IsValid()) {
  517. ASSERT(FALSE);
  518. hr = E_FAIL;
  519. goto CLEANUPANDEXIT;
  520. }
  521. hr = m_TSClient->get_AdvancedSettings2(&pAdvSettings);
  522. if (hr != S_OK) {
  523. TRC_ERR((TB, L"get_AdvancedSettings2: %08X", hr));
  524. goto CLEANUPANDEXIT;
  525. }
  526. hr = pAdvSettings->get_SmartSizing(&vb);
  527. *pVal = (vb != 0);
  528. pAdvSettings->Release();
  529. CLEANUPANDEXIT:
  530. DC_END_FN();
  531. return hr;
  532. }
  533. STDMETHODIMP
  534. CTSRDPRemoteDesktopClient::put_ChannelMgr(
  535. ISAFRemoteDesktopChannelMgr *newVal
  536. )
  537. /*++
  538. Routine Description:
  539. Assign the data channel manager interface.
  540. Arguments:
  541. newVal - Data Channel Manager
  542. Return Value:
  543. S_OK on success. Otherwise, an error code is returned.
  544. --*/
  545. {
  546. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::put_ChannelMgr");
  547. HRESULT hr = S_OK;
  548. //
  549. // We should get called one time.
  550. //
  551. ASSERT(m_ChannelMgr == NULL);
  552. m_ChannelMgr = newVal;
  553. //
  554. // Register the Remote Desktop control channel
  555. //
  556. hr = m_ChannelMgr->OpenDataChannel(
  557. REMOTEDESKTOP_RC_CONTROL_CHANNEL, &m_CtlChannel
  558. );
  559. if (!SUCCEEDED(hr)) {
  560. goto CLEANUPANDEXIT;
  561. }
  562. //
  563. // Register an event sink with the channel manager.
  564. //
  565. m_CtlChannelEventSink.m_Obj = this;
  566. //
  567. // Add the event sink.
  568. //
  569. hr = m_CtlChannelEventSink.DispEventAdvise(m_CtlChannel);
  570. if (!SUCCEEDED(hr)) {
  571. TRC_ERR((TB, L"DispEventAdvise: %08X", hr));
  572. }
  573. CLEANUPANDEXIT:
  574. return hr;
  575. }
  576. HRESULT
  577. CTSRDPRemoteDesktopClient::ConnectServerWithOpenedSocket()
  578. /*++
  579. Routine Description:
  580. Connects the client component to the server-side Remote Desktop Host COM
  581. Object with already opened socket.
  582. Arguments:
  583. None.
  584. Returns:
  585. S_OK or error code
  586. --*/
  587. {
  588. HRESULT hr = S_OK;
  589. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::ConnectServerWithSocket");
  590. IMsRdpClientAdvancedSettings* ptsAdvSettings = NULL;
  591. TRC_NRM((TB, L"ConnectServerWithOpenedSocket"));
  592. ASSERT( INVALID_SOCKET != m_TSConnectSocket );
  593. //
  594. // Direct the MSTSCAX control to connect.
  595. //
  596. hr = m_TSClient->put_Server( m_ConnectedServer );
  597. if (!SUCCEEDED(hr)) {
  598. TRC_ERR((TB, L"put_Server: %ld", hr));
  599. goto CLEANUPANDEXIT;
  600. }
  601. hr = m_TSClient->get_AdvancedSettings2( &ptsAdvSettings );
  602. if( SUCCEEDED(hr) && ptsAdvSettings ) {
  603. VARIANT var;
  604. VariantClear(&var);
  605. var.vt = VT_BYREF;
  606. var.byref = (PVOID)m_TSConnectSocket;
  607. hr = ptsAdvSettings->put_ConnectWithEndpoint( &var );
  608. if( FAILED(hr) ) {
  609. TRC_ERR((TB, _T("put_ConnectWithEndpoint failed - GLE:%x"), hr));
  610. }
  611. VariantClear(&var);
  612. ptsAdvSettings->Release();
  613. }
  614. if( FAILED(hr) ) {
  615. goto CLEANUPANDEXIT;
  616. }
  617. //
  618. // mstscax owns this socket and will close it
  619. //
  620. m_TSConnectSocket = INVALID_SOCKET;
  621. hr = m_TSClient->Connect();
  622. if( FAILED(hr) ) {
  623. TRC_ERR((TB, L"Connect: 0x%08x", hr));
  624. goto CLEANUPANDEXIT;
  625. }
  626. CLEANUPANDEXIT:
  627. DC_END_FN();
  628. return hr;
  629. }
  630. HRESULT
  631. CTSRDPRemoteDesktopClient::ConnectServerPort(
  632. BSTR bstrServer,
  633. LONG portNumber
  634. )
  635. /*++
  636. Routine Description:
  637. Connects the client component to the server-side Remote Desktop Host COM
  638. Object with specific port number
  639. Arguments:
  640. bstrServer : Name or IP address of server.
  641. portNumber : optional port number.
  642. Return Value:
  643. S_OK on success. Otherwise, an error code is returned.
  644. --*/
  645. {
  646. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::ConnectServerPort");
  647. HRESULT hr;
  648. IMsRdpClientAdvancedSettings* ptsAdvSettings = NULL;
  649. TRC_NRM((TB, L"ConnectServerPort %s %d", bstrServer, portNumber));
  650. //
  651. // Direct the MSTSCAX control to connect.
  652. //
  653. hr = m_TSClient->put_Server( bstrServer );
  654. if (!SUCCEEDED(hr)) {
  655. TRC_ERR((TB, L"put_Server: %ld", hr));
  656. goto CLEANUPANDEXIT;
  657. }
  658. hr = m_TSClient->get_AdvancedSettings2( &ptsAdvSettings );
  659. if( SUCCEEDED(hr) && ptsAdvSettings ) {
  660. //
  661. // Previous ConnectServerPort() might have set this port number
  662. // other than 3389
  663. //
  664. hr = ptsAdvSettings->put_RDPPort(
  665. (0 != portNumber) ? portNumber : TERMSRV_TCPPORT
  666. );
  667. if (FAILED(hr) ) {
  668. TRC_ERR((TB, L"put_RDPPort failed: 0x%08x", hr));
  669. }
  670. ptsAdvSettings->Release();
  671. }
  672. else {
  673. TRC_ERR((TB, L"get_AdvancedSettings2 failed: 0x%08x", hr));
  674. }
  675. //
  676. // Failed the connection if we can't set the port number
  677. //
  678. if( FAILED(hr) )
  679. {
  680. goto CLEANUPANDEXIT;
  681. }
  682. m_ConnectedServer = bstrServer;
  683. m_ConnectedPort = (0 != portNumber) ? portNumber : TERMSRV_TCPPORT;
  684. hr = m_TSClient->Connect();
  685. if( FAILED(hr) ) {
  686. TRC_ERR((TB, L"Connect: 0x%08x", hr));
  687. }
  688. CLEANUPANDEXIT:
  689. DC_END_FN();
  690. return hr;
  691. }
  692. HRESULT
  693. CTSRDPRemoteDesktopClient::SetupConnectionInfo(
  694. BOOL bListenConnectInfo,
  695. BSTR bstrExpertBlob
  696. )
  697. /*++
  698. Routine Description:
  699. Connects the client component to the server-side Remote Desktop Host COM
  700. Object.
  701. Arguments:
  702. bstrExpertBlob : Optional parameter to be transmitted to SAF resolver.
  703. Return Value:
  704. S_OK on success. Otherwise, an error code is returned.
  705. --*/
  706. {
  707. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::SetupConnectionInfo");
  708. HRESULT hr = S_OK;
  709. DWORD result;
  710. DWORD protocolType;
  711. IMsTscNonScriptable* ptsns = NULL;
  712. IMsRdpClientAdvancedSettings* ptsAdvSettings = NULL;
  713. IMsRdpClientSecuredSettings* ptsSecuredSettings = NULL;
  714. CComBSTR bstrAssistantAccount;
  715. CComBSTR bstrAccountDomainName;
  716. CComBSTR machineAddressList;
  717. //
  718. // Parse the connection parameters.
  719. //
  720. result = ParseConnectParmsString(
  721. m_ConnectParms,
  722. &m_ConnectParmVersion,
  723. &protocolType,
  724. machineAddressList,
  725. bstrAssistantAccount,
  726. m_AssistantAccountPwd,
  727. m_HelpSessionID,
  728. m_HelpSessionName,
  729. m_HelpSessionPwd,
  730. m_TSSecurityBlob
  731. );
  732. if (result != ERROR_SUCCESS) {
  733. hr = HRESULT_FROM_WIN32(result);
  734. goto CLEANUPANDEXIT;
  735. }
  736. //
  737. // If the protocol type doesn't match, then fail.
  738. //
  739. if (protocolType != REMOTEDESKTOP_TSRDP_PROTOCOL) {
  740. TRC_ERR((TB, L"Invalid connection protocol %ld", protocolType));
  741. hr = HRESULT_FROM_WIN32(ERROR_INVALID_USER_BUFFER);
  742. goto CLEANUPANDEXIT;
  743. }
  744. if (bListenConnectInfo) {
  745. m_ServerAddressList.clear();
  746. }
  747. else {
  748. //
  749. // Parse address list in connect parm.
  750. //
  751. result = ParseAddressList( machineAddressList, m_ServerAddressList );
  752. if( ERROR_SUCCESS != result ) {
  753. TRC_ERR((TB, L"Invalid address list 0x%08x", result));
  754. hr = HRESULT_FROM_WIN32(result);
  755. goto CLEANUPANDEXIT;
  756. }
  757. if( 0 == m_ServerAddressList.size() ) {
  758. TRC_ERR((TB, L"Invalid connection address list"));
  759. hr = HRESULT_FROM_WIN32(ERROR_INVALID_USER_BUFFER);
  760. goto CLEANUPANDEXIT;
  761. }
  762. }
  763. hr = m_TSClient->put_UserName(SALEMHELPASSISTANTACCOUNT_NAME);
  764. if (!SUCCEEDED(hr)) {
  765. TRC_ERR((TB, L"put_UserName: %ld", hr));
  766. goto CLEANUPANDEXIT;
  767. }
  768. hr = m_TSClient->get_AdvancedSettings2( &ptsAdvSettings );
  769. if( SUCCEEDED(hr) && ptsAdvSettings ) {
  770. hr = ptsAdvSettings->put_DisableRdpdr( TRUE );
  771. if (FAILED(hr) ) {
  772. TRC_ERR((TB, L"put_DisableRdpdr failed: 0x%08x", hr));
  773. }
  774. // Security: Always have activex control to notify us of receiving
  775. // TS public key, pre-XP ticket is no longer supported.
  776. // tell activeX control to notify us TS public key
  777. hr = ptsAdvSettings->put_NotifyTSPublicKey(VARIANT_TRUE);
  778. if (FAILED(hr) ) {
  779. TRC_ERR((TB, L"put_NotifyTSPublicKey failed: 0x%08x", hr));
  780. goto CLEANUPANDEXIT;
  781. }
  782. //
  783. // Setting connection timeout, ICS might take sometime to routine
  784. // opened port to actual TS server, neither is critical error.
  785. //
  786. hr = ptsAdvSettings->put_singleConnectionTimeout( 60 * 2 ); // try two mins timeout
  787. if( FAILED(hr) ) {
  788. TRC_ERR((TB, L"put_singleConnectionTimeout : 0x%x", hr));
  789. }
  790. hr = ptsAdvSettings->put_overallConnectionTimeout( 60 * 2 );
  791. if( FAILED(hr) ) {
  792. TRC_ERR((TB, L"put_overallConnectionTimeout : 0x%x", hr));
  793. }
  794. }
  795. else {
  796. TRC_ERR((TB, L"QueryInterface IID_IMsRdpClientAdvancedSettings: %ld", hr));
  797. }
  798. // Password encryption is based on encyption cycle key + help session ID
  799. hr = m_TSClient->get_SecuredSettings2( &ptsSecuredSettings );
  800. if( FAILED(hr) || !ptsSecuredSettings ) {
  801. TRC_ERR((TB, L"get_IMsTscSecuredSettings : 0x%08x", hr));
  802. goto CLEANUPANDEXIT;
  803. }
  804. //
  805. // TermSrv invoke sessmgr to check if help session is valid
  806. // before kicking off rdsaddin.exe, we need to send over
  807. // help session ID and password, only place available and big
  808. // enough is on WorkDir and StartProgram property, TermSrv will
  809. // ignore these and fill appropriate value for it
  810. //
  811. hr = ptsSecuredSettings->put_WorkDir( m_HelpSessionID );
  812. if( FAILED(hr) ) {
  813. TRC_ERR((TB, L"put_WorkDir: 0x%08x", hr));
  814. goto CLEANUPANDEXIT;
  815. }
  816. hr = ptsSecuredSettings->put_StartProgram( m_HelpSessionPwd );
  817. if( FAILED(hr) ) {
  818. TRC_ERR((TB, L"put_StartProgram: 0x%08x", hr));
  819. goto CLEANUPANDEXIT;
  820. }
  821. ptsSecuredSettings->Release();
  822. // we only use this to disable redirection, not a critical
  823. // error, just ugly
  824. hr = m_TSClient->QueryInterface(IID_IMsTscNonScriptable,
  825. (void**)&ptsns);
  826. if(!SUCCEEDED(hr) || !ptsns){
  827. TRC_ERR((TB, L"QueryInterface IID_IMsTscNonScriptable: %ld", hr));
  828. goto CLEANUPANDEXIT;
  829. }
  830. // Whistler XP client, password is just a junk
  831. hr = ptsns->put_ClearTextPassword( m_AssistantAccountPwd );
  832. if (!SUCCEEDED(hr)) {
  833. TRC_ERR((TB, L"put_ClearTextPassword: 0x%08x", hr));
  834. goto CLEANUPANDEXIT;
  835. }
  836. m_ExpertBlob = bstrExpertBlob;
  837. //
  838. // Instruct mstscax to connect with certain screen resolution,
  839. // mstscax will default to 200x20 (???), min. is VGA size.
  840. //
  841. {
  842. RECT rect;
  843. LONG cx;
  844. LONG cy;
  845. GetClientRect(&rect);
  846. cx = rect.right - rect.left;
  847. cy = rect.bottom - rect.top;
  848. if( cx < 640 || cy < 480 )
  849. {
  850. cx = 640;
  851. cy = 480;
  852. }
  853. m_TSClient->put_DesktopWidth(cx);
  854. m_TSClient->put_DesktopHeight(cy);
  855. }
  856. CLEANUPANDEXIT:
  857. if( ptsAdvSettings ) {
  858. ptsAdvSettings->Release();
  859. }
  860. if(ptsns) {
  861. ptsns->Release();
  862. ptsns = NULL;
  863. }
  864. DC_END_FN();
  865. return hr;
  866. }
  867. STDMETHODIMP
  868. CTSRDPRemoteDesktopClient::AcceptListenConnection(
  869. BSTR bstrExpertBlob
  870. )
  871. /*++
  872. Routine Description:
  873. Establish reverse connection with TS server, TS server must be connected
  874. wia reverse connection.
  875. Parameters:
  876. bstrExpertBlob : Same as ConnectToServer().
  877. Returns:
  878. S_OK or error code.
  879. --*/
  880. {
  881. HRESULT hr = S_OK;
  882. LPTSTR pszUserName = NULL;
  883. LPTSTR eventString[2];
  884. TCHAR buffer[125]; // this is enough for port number
  885. int numChars;
  886. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::AcceptListenConnection");
  887. //
  888. // If we are already connected or not valid, then just
  889. // return.
  890. //
  891. if (!IsValid()) {
  892. ASSERT(FALSE);
  893. hr = E_FAIL;
  894. goto CLEANUPANDEXIT;
  895. }
  896. if (m_ConnectedToServer || m_ConnectionInProgress) {
  897. TRC_ERR((TB, L"Connection active"));
  898. hr = HRESULT_FROM_WIN32(ERROR_CONNECTION_ACTIVE);
  899. goto CLEANUPANDEXIT;
  900. }
  901. if( !ListenConnectInProgress() ) {
  902. TRC_ERR((TB, L"Connection in-active"));
  903. hr = HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID);
  904. goto CLEANUPANDEXIT;
  905. }
  906. if( INVALID_SOCKET == m_TSConnectSocket ) {
  907. TRC_ERR((TB, L"Socket is not connected"));
  908. hr = HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID);
  909. goto CLEANUPANDEXIT;
  910. }
  911. hr = SetupConnectionInfo(TRUE, bstrExpertBlob);
  912. if( FAILED(hr) ) {
  913. TRC_ERR((TB, L"SetupConnectionInfo() failed with 0x%08x", hr));
  914. goto CLEANUPANDEXIT;
  915. }
  916. //
  917. // Log SESSMGR_I_ACCEPTLISTENREVERSECONNECT Event
  918. //
  919. hr = GetCurrentUser( &pszUserName );
  920. if( FAILED(hr) ) {
  921. TRC_ERR((TB, L"GetCurrentUser() failed with 0x%08x", hr));
  922. goto CLEANUPANDEXIT;
  923. }
  924. numChars = _sntprintf( buffer, sizeof(buffer)/sizeof(buffer[0]), _TEXT("%d"), m_ConnectedPort );
  925. if( numChars <= 0 ) {
  926. // 125 chars is way too big for a port number.
  927. TRC_ERR((TB, L"_sntprintf() return failure"));
  928. hr = HRESULT_FROM_WIN32( ERROR_INTERNAL_ERROR );
  929. goto CLEANUPANDEXIT;
  930. }
  931. eventString[0] = pszUserName;
  932. eventString[1] = buffer;
  933. LogRemoteAssistanceEventString(
  934. EVENTLOG_INFORMATION_TYPE,
  935. SESSMGR_I_ACCEPTLISTENREVERSECONNECT,
  936. 2,
  937. eventString
  938. );
  939. hr = ConnectServerWithOpenedSocket();
  940. CLEANUPANDEXIT:
  941. if( pszUserName != NULL ) {
  942. LocalFree(pszUserName);
  943. }
  944. m_ConnectionInProgress = SUCCEEDED(hr);
  945. DC_END_FN();
  946. return hr;
  947. }
  948. STDMETHODIMP
  949. CTSRDPRemoteDesktopClient::ConnectToServer(BSTR bstrExpertBlob)
  950. /*++
  951. Routine Description:
  952. Connects the client component to the server-side Remote Desktop Host COM
  953. Object.
  954. Arguments:
  955. bstrExpertBlob : Optional parameter to be transmitted to SAF resolver.
  956. Return Value:
  957. S_OK on success. Otherwise, an error code is returned.
  958. Params--*/
  959. {
  960. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::ConnectToServer");
  961. HRESULT hr = S_OK;
  962. ServerAddress address;
  963. LPTSTR pszUserName = NULL;
  964. LPTSTR eventString[2];
  965. //
  966. // If we are already connected or not valid, then just
  967. // return.
  968. //
  969. if (!IsValid()) {
  970. ASSERT(FALSE);
  971. hr = E_FAIL;
  972. goto CLEANUPANDEXIT;
  973. }
  974. if (m_ConnectedToServer || m_ConnectionInProgress) {
  975. TRC_ERR((TB, L"Connection active"));
  976. hr = HRESULT_FROM_WIN32(ERROR_CONNECTION_ACTIVE);
  977. goto CLEANUPANDEXIT;
  978. }
  979. hr = SetupConnectionInfo(FALSE, bstrExpertBlob);
  980. if( FAILED(hr) ) {
  981. TRC_ERR((TB, L"SetupConnectionInfo() failed with 0x%08x", hr));
  982. goto CLEANUPANDEXIT;
  983. }
  984. address = m_ServerAddressList.front();
  985. m_ServerAddressList.pop_front();
  986. hr = ConnectServerPort(address.ServerName, address.portNumber);
  987. if (FAILED(hr)) {
  988. TRC_ERR((TB, L"ConnectServerPort: %08X", hr));
  989. goto CLEANUPANDEXIT;
  990. }
  991. //
  992. // Log SESSMGR_I_ACCEPTLISTENREVERSECONNECT Event
  993. //
  994. hr = GetCurrentUser( &pszUserName );
  995. if( FAILED(hr) ) {
  996. TRC_ERR((TB, L"GetCurrentUser() failed with 0x%08x", hr));
  997. goto CLEANUPANDEXIT;
  998. }
  999. eventString[0] = pszUserName;
  1000. eventString[1] = (LPTSTR)m_ConnectParms;
  1001. LogRemoteAssistanceEventString(
  1002. EVENTLOG_INFORMATION_TYPE,
  1003. SESSMGR_I_EXPERTUSETICKET,
  1004. 2,
  1005. eventString
  1006. );
  1007. CLEANUPANDEXIT:
  1008. if( pszUserName != NULL ) {
  1009. LocalFree(pszUserName);
  1010. }
  1011. //
  1012. // If we succeeded, remember that we are in a state of connecting.
  1013. //
  1014. m_ConnectionInProgress = SUCCEEDED(hr);
  1015. DC_END_FN();
  1016. return hr;
  1017. }
  1018. STDMETHODIMP
  1019. CTSRDPRemoteDesktopClient::DisconnectFromServer()
  1020. /*++
  1021. Routine Description:
  1022. Disconnects the client from the server to which we are currently
  1023. connected.
  1024. Arguments:
  1025. Return Value:
  1026. S_OK on success. Otherwise, an error code is returned.
  1027. --*/
  1028. {
  1029. return DisconnectFromServerInternal(
  1030. SAFERROR_LOCALNOTERROR
  1031. );
  1032. }
  1033. STDMETHODIMP
  1034. CTSRDPRemoteDesktopClient::DisconnectFromServerInternal(
  1035. LONG errorCode
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. Disconnects the client from the server to which we are currently
  1040. connected.
  1041. Arguments:
  1042. reason - Reason for disconnect.
  1043. Return Value:
  1044. S_OK on success. Otherwise, an error code is returned.
  1045. --*/
  1046. {
  1047. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::DisconnectFromServerInternal");
  1048. HRESULT hr;
  1049. //
  1050. // Make sure our window is hidden.
  1051. //
  1052. //ShowWindow(SW_HIDE);
  1053. ListenConnectCleanup();
  1054. if (m_ConnectedToServer || m_ConnectionInProgress) {
  1055. hr = m_TSClient->Disconnect();
  1056. if (SUCCEEDED(hr)) {
  1057. m_ConnectionInProgress = FALSE;
  1058. m_ConnectedToServer = FALSE;
  1059. if (m_RemoteControlRequestInProgress) {
  1060. m_RemoteControlRequestInProgress = FALSE;
  1061. Fire_RemoteControlRequestComplete(SAFERROR_SHADOWEND_UNKNOWN);
  1062. }
  1063. //
  1064. // Fire the server disconnect event.
  1065. //
  1066. Fire_Disconnected(errorCode);
  1067. }
  1068. }
  1069. else {
  1070. TRC_NRM((TB, L"Not connected."));
  1071. hr = S_OK;
  1072. }
  1073. DC_END_FN();
  1074. return hr;
  1075. }
  1076. STDMETHODIMP
  1077. CTSRDPRemoteDesktopClient::ConnectRemoteDesktop()
  1078. /*++
  1079. Routine Description:
  1080. Once "remote desktop mode" has been enabled for the server-side Remote
  1081. Desktop Host COM Object and we are connected to the server, the
  1082. ConnectRemoteDesktop method can be invoked to take control of the remote
  1083. user's desktop.
  1084. Arguments:
  1085. Return Value:
  1086. S_OK on success. Otherwise, an error code is returned.
  1087. --*/
  1088. {
  1089. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::ConnectRemoteDesktop");
  1090. HRESULT hr = S_OK;
  1091. DWORD result;
  1092. BSTR rcRequest = NULL;
  1093. //
  1094. // Fail if we are not valid or not connected to the server.
  1095. //
  1096. if (!IsValid()) {
  1097. ASSERT(FALSE);
  1098. hr = E_FAIL;
  1099. goto CLEANUPANDEXIT;
  1100. }
  1101. if (!m_ConnectedToServer) {
  1102. hr = HRESULT_FROM_WIN32(ERROR_DEVICE_NOT_CONNECTED);
  1103. goto CLEANUPANDEXIT;
  1104. }
  1105. //
  1106. // Succeed if a remote control request is already in progress.
  1107. //
  1108. if (m_RemoteControlRequestInProgress) {
  1109. hr = S_OK;
  1110. goto CLEANUPANDEXIT;
  1111. }
  1112. //
  1113. // Generate the remote control connect request message.
  1114. //
  1115. hr = GenerateRCRequest(&rcRequest);
  1116. if (!SUCCEEDED(hr)) {
  1117. goto CLEANUPANDEXIT;
  1118. }
  1119. //
  1120. // Send it.
  1121. //
  1122. hr = m_CtlChannel->SendChannelData(rcRequest);
  1123. if (!SUCCEEDED(hr)) {
  1124. goto CLEANUPANDEXIT;
  1125. }
  1126. //
  1127. // A request is in progress, if we successfully sent the request.
  1128. //
  1129. m_RemoteControlRequestInProgress = TRUE;
  1130. CLEANUPANDEXIT:
  1131. if (rcRequest != NULL) {
  1132. SysFreeString(rcRequest);
  1133. }
  1134. DC_END_FN();
  1135. return hr;
  1136. }
  1137. STDMETHODIMP
  1138. CTSRDPRemoteDesktopClient::DisconnectRemoteDesktop()
  1139. /*++
  1140. Routine Description:
  1141. Once "remote desktop mode" has been enabled for the server-side Remote
  1142. Desktop Host COM Object and we are connected to the server, the
  1143. ConnectRemoteDesktop method can be invoked to take control of the remote
  1144. user's desktop.
  1145. Arguments:
  1146. Return Value:
  1147. S_OK on success. Otherwise, an error code is returned.
  1148. --*/
  1149. {
  1150. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::DisconnectRemoteDesktop");
  1151. HRESULT hr = S_OK;
  1152. CComBSTR rcRequest;
  1153. //
  1154. // Fail if we are not valid or not connected.
  1155. //
  1156. if (!IsValid()) {
  1157. ASSERT(FALSE);
  1158. hr = E_FAIL;
  1159. goto CLEANUPANDEXIT;
  1160. }
  1161. if (!m_ConnectedToServer) {
  1162. hr = HRESULT_FROM_WIN32(ERROR_DEVICE_NOT_CONNECTED);
  1163. goto CLEANUPANDEXIT;
  1164. }
  1165. //
  1166. // Generate the terminate remote control key sequence and sent it to the
  1167. // server.
  1168. //
  1169. if (m_RemoteControlRequestInProgress) {
  1170. hr = SendTerminateRCKeysToServer();
  1171. }
  1172. CLEANUPANDEXIT:
  1173. DC_END_FN();
  1174. return hr;
  1175. }
  1176. //
  1177. // ISAFRemoteDesktopTestExtension
  1178. //
  1179. STDMETHODIMP
  1180. CTSRDPRemoteDesktopClient::put_TestExtDllName(/*[in]*/ BSTR newVal)
  1181. {
  1182. HRESULT hr = E_NOTIMPL;
  1183. IMsTscAdvancedSettings *pMstscAdvSettings = NULL;
  1184. IMsTscDebug *pMstscDebug = NULL;
  1185. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::put_TestExtDllName" );
  1186. if ( NULL == m_TSClient )
  1187. {
  1188. TRC_ERR((TB, L"m_TSClient is NULL" ));
  1189. hr = E_NOINTERFACE;
  1190. goto CLEANUPANDEXIT;
  1191. }
  1192. hr = m_TSClient->get_AdvancedSettings( &pMstscAdvSettings );
  1193. if (FAILED( hr ))
  1194. {
  1195. TRC_ERR((TB, L"m_TSClient->get_AdvancedSettings failed %08X", hr ));
  1196. goto CLEANUPANDEXIT;
  1197. }
  1198. hr = m_TSClient->get_Debugger( &pMstscDebug );
  1199. if ( FAILED( hr ))
  1200. {
  1201. TRC_ERR((TB, L"m_TSClient->get_Debugger failed %08X", hr ));
  1202. goto CLEANUPANDEXIT;
  1203. }
  1204. hr = pMstscAdvSettings->put_allowBackgroundInput( 1 );
  1205. if (FAILED( hr ))
  1206. {
  1207. TRC_ERR((TB, L"put_allowBackgroundInput failed %08X", hr ));
  1208. }
  1209. pMstscDebug->put_CLXDll( newVal );
  1210. CLEANUPANDEXIT:
  1211. if ( NULL != pMstscAdvSettings )
  1212. pMstscAdvSettings->Release();
  1213. if ( NULL != pMstscDebug )
  1214. pMstscDebug->Release();
  1215. DC_END_FN();
  1216. return hr;
  1217. }
  1218. STDMETHODIMP
  1219. CTSRDPRemoteDesktopClient::put_TestExtParams(/*[in]*/ BSTR newVal)
  1220. {
  1221. HRESULT hr = E_NOTIMPL;
  1222. IMsTscDebug *pMstscDebug = NULL;
  1223. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::put_TestExtParams" );
  1224. if ( NULL == m_TSClient )
  1225. {
  1226. TRC_ERR((TB, L"m_TSClient is NULL" ));
  1227. hr = E_NOINTERFACE;
  1228. goto CLEANUPANDEXIT;
  1229. }
  1230. hr = m_TSClient->get_Debugger( &pMstscDebug );
  1231. if (FAILED( hr ))
  1232. {
  1233. TRC_ERR((TB, L"m_TSClient->get_Debugger failed %08X", hr ));
  1234. goto CLEANUPANDEXIT;
  1235. }
  1236. hr = pMstscDebug->put_CLXCmdLine( newVal );
  1237. CLEANUPANDEXIT:
  1238. if ( NULL != pMstscDebug )
  1239. pMstscDebug->Release();
  1240. DC_END_FN();
  1241. return hr;
  1242. }
  1243. VOID
  1244. CTSRDPRemoteDesktopClient::OnMSTSCReceiveData(
  1245. BSTR data
  1246. )
  1247. /*++
  1248. Routine Description:
  1249. Handle Remote Control Control Channel messages.
  1250. Arguments:
  1251. Return Value:
  1252. --*/
  1253. {
  1254. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::OnMSTSCReceiveData");
  1255. //
  1256. //we got some data, so we must be connected, update timer
  1257. //
  1258. m_PrevTimer = GetTickCount();
  1259. //
  1260. // Fire the data ready event.
  1261. //
  1262. Fire_DataReady(data);
  1263. DC_END_FN();
  1264. }
  1265. VOID
  1266. CTSRDPRemoteDesktopClient::HandleControlChannelMsg()
  1267. /*++
  1268. Routine Description:
  1269. Handle Remote Control Control Channel messages.
  1270. Arguments:
  1271. Return Value:
  1272. --*/
  1273. {
  1274. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::HandleControlChannelMsg");
  1275. PREMOTEDESKTOP_CTL_BUFHEADER msgHeader;
  1276. BSTR msg = NULL;
  1277. LONG *pResult;
  1278. BSTR authenticateReq = NULL;
  1279. BSTR versionInfoPacket = NULL;
  1280. HRESULT hr;
  1281. DWORD result;
  1282. ASSERT(IsValid());
  1283. //
  1284. // Read the next message.
  1285. //
  1286. result = m_CtlChannel->ReceiveChannelData(&msg);
  1287. if (result != ERROR_SUCCESS) {
  1288. goto CLEANUPANDEXIT;
  1289. }
  1290. //
  1291. // Dispatch, based on the message type.
  1292. //
  1293. msgHeader = (PREMOTEDESKTOP_CTL_BUFHEADER)msg;
  1294. //
  1295. // If the server-side of the VC link is alive.
  1296. //
  1297. //
  1298. if ((msgHeader->msgType == REMOTEDESKTOP_CTL_SERVER_ANNOUNCE) &&
  1299. m_ConnectionInProgress) {
  1300. //
  1301. // Send version information to the server.
  1302. //
  1303. hr = GenerateVersionInfoPacket(
  1304. &versionInfoPacket
  1305. );
  1306. if (!SUCCEEDED(hr)) {
  1307. goto CLEANUPANDEXIT;
  1308. }
  1309. hr = m_CtlChannel->SendChannelData(versionInfoPacket);
  1310. if (!SUCCEEDED(hr)) {
  1311. goto CLEANUPANDEXIT;
  1312. }
  1313. //
  1314. // Request client authentication.
  1315. //
  1316. hr = GenerateClientAuthenticateRequest(
  1317. &authenticateReq
  1318. );
  1319. if (!SUCCEEDED(hr)) {
  1320. goto CLEANUPANDEXIT;
  1321. }
  1322. hr = m_CtlChannel->SendChannelData(authenticateReq);
  1323. }
  1324. //
  1325. // If the message is from the server, indicating that it is
  1326. // disconnecting. This can happen if the RDSRemoteDesktopServer
  1327. // is directed to exit listening mode.
  1328. //
  1329. else if (msgHeader->msgType == REMOTEDESKTOP_CTL_DISCONNECT) {
  1330. TRC_NRM((TB, L"Server indicated a disconnect."));
  1331. DisconnectFromServerInternal(SAFERROR_BYSERVER);
  1332. }
  1333. //
  1334. // If the message is a message result.
  1335. //
  1336. else if (msgHeader->msgType == REMOTEDESKTOP_CTL_RESULT) {
  1337. pResult = (LONG *)(msgHeader+1);
  1338. //
  1339. // If a remote control request is in progress, then we should check
  1340. // for a remote control complete status.
  1341. //
  1342. if (m_RemoteControlRequestInProgress && ISRCSTATUSCODE(*pResult)) {
  1343. TRC_ERR((TB, L"Received RC terminate status code."));
  1344. m_RemoteControlRequestInProgress = FALSE;
  1345. Fire_RemoteControlRequestComplete(*pResult);
  1346. }
  1347. //
  1348. // Otherwise, if a connection is in progress, then the client
  1349. // authentication request must have succeeded.
  1350. //
  1351. else if (m_ConnectionInProgress) {
  1352. //
  1353. // Should not be getting a remote control status here.
  1354. //
  1355. ASSERT(!ISRCSTATUSCODE(*pResult));
  1356. //
  1357. // Fire connect request succeeded message.
  1358. //
  1359. if (*pResult == SAFERROR_NOERROR ) {
  1360. m_ConnectedToServer = TRUE;
  1361. m_ConnectionInProgress = FALSE;
  1362. //
  1363. //set the timer to check if the user is still connected
  1364. //ignore errors, worst case - the ui is up even after the user disconnects
  1365. //
  1366. if( m_RdcConnCheckTimeInterval )
  1367. m_TimerId = SetTimer(WM_CONNECTCHECK_TIMER, m_RdcConnCheckTimeInterval);
  1368. //
  1369. // Not in progress once connected
  1370. //
  1371. m_ListenConnectInProgress = FALSE;
  1372. m_TSConnectSocket = INVALID_SOCKET;
  1373. Fire_Connected();
  1374. }
  1375. //
  1376. // Otherwise, fire a disconnected event.
  1377. //
  1378. else {
  1379. DisconnectFromServerInternal(*pResult);
  1380. m_ConnectionInProgress = FALSE;
  1381. }
  1382. }
  1383. }
  1384. //
  1385. // We will ignore other packets to support forward compatibility.
  1386. //
  1387. CLEANUPANDEXIT:
  1388. //
  1389. // Release the message.
  1390. //
  1391. if (msg != NULL) {
  1392. SysFreeString(msg);
  1393. }
  1394. if (versionInfoPacket != NULL) {
  1395. SysFreeString(versionInfoPacket);
  1396. }
  1397. if (authenticateReq != NULL) {
  1398. SysFreeString(authenticateReq);
  1399. }
  1400. DC_END_FN();
  1401. }
  1402. HRESULT
  1403. CTSRDPRemoteDesktopClient::GenerateRCRequest(
  1404. BSTR *rcRequest
  1405. )
  1406. /*++
  1407. Routine Description:
  1408. Generate a remote control request message for the
  1409. server.
  1410. TODO: We might need to be able to push this up
  1411. to the parent class, if it makes sense for
  1412. NetMeeting.
  1413. Arguments:
  1414. rcRequest - Returned request message.
  1415. Return Value:
  1416. S_OK on success. Otherwise, an error code is returned.
  1417. --*/
  1418. {
  1419. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::GenerateRCRequest");
  1420. PREMOTEDESKTOP_CTL_BUFHEADER msgHeader;
  1421. PBYTE ptr;
  1422. HRESULT hr;
  1423. DWORD len;
  1424. len = sizeof(REMOTEDESKTOP_CTL_BUFHEADER) + ((m_ConnectParms.Length()+1) * sizeof(WCHAR));
  1425. msgHeader = (PREMOTEDESKTOP_CTL_BUFHEADER)SysAllocStringByteLen(NULL, len);
  1426. if (msgHeader != NULL) {
  1427. msgHeader->msgType = REMOTEDESKTOP_CTL_REMOTE_CONTROL_DESKTOP;
  1428. ptr = (PBYTE)(msgHeader + 1);
  1429. memcpy(ptr, (BSTR)m_ConnectParms,
  1430. ((m_ConnectParms.Length()+1) * sizeof(WCHAR)));
  1431. *rcRequest = (BSTR)msgHeader;
  1432. hr = S_OK;
  1433. }
  1434. else {
  1435. TRC_ERR((TB, L"SysAllocStringByteLen failed for %ld bytes", len));
  1436. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  1437. }
  1438. DC_END_FN();
  1439. return hr;
  1440. }
  1441. HRESULT
  1442. CTSRDPRemoteDesktopClient::GenerateClientAuthenticateRequest(
  1443. BSTR *authenticateReq
  1444. )
  1445. /*++
  1446. Routine Description:
  1447. Generate a 'client authenticate' request.
  1448. TODO: We might need to be able to push this up
  1449. to the parent class, if it makes sense for
  1450. NetMeeting.
  1451. Arguments:
  1452. rcRequest - Returned request message.
  1453. Return Value:
  1454. S_OK on success. Otherwise, an error code is returned.
  1455. --*/
  1456. {
  1457. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::GenerateClientAuthenticateRequest");
  1458. PREMOTEDESKTOP_CTL_BUFHEADER msgHeader;
  1459. PBYTE ptr;
  1460. HRESULT hr;
  1461. DWORD len;
  1462. len = sizeof(REMOTEDESKTOP_CTL_BUFHEADER) + ((m_ConnectParms.Length()+1) * sizeof(WCHAR));
  1463. #if FEATURE_USERBLOBS
  1464. if( m_ExpertBlob.Length() > 0 ) {
  1465. len += ((m_ExpertBlob.Length() + 1) * sizeof(WCHAR));
  1466. }
  1467. #endif
  1468. msgHeader = (PREMOTEDESKTOP_CTL_BUFHEADER)SysAllocStringByteLen(NULL, len);
  1469. if (msgHeader != NULL) {
  1470. msgHeader->msgType = REMOTEDESKTOP_CTL_AUTHENTICATE;
  1471. ptr = (PBYTE)(msgHeader + 1);
  1472. memcpy(ptr, (BSTR)m_ConnectParms,
  1473. ((m_ConnectParms.Length()+1) * sizeof(WCHAR)));
  1474. #if FEATURE_USERBLOBS
  1475. if( m_ExpertBlob.Length() > 0 ) {
  1476. ptr += ((m_ConnectParms.Length()+1) * sizeof(WCHAR));
  1477. memcpy(ptr, (BSTR)m_ExpertBlob,
  1478. ((m_ExpertBlob.Length()+1) * sizeof(WCHAR)));
  1479. }
  1480. #endif
  1481. *authenticateReq = (BSTR)msgHeader;
  1482. hr = S_OK;
  1483. }
  1484. else {
  1485. TRC_ERR((TB, L"SysAllocStringByteLen failed for %ld bytes", len));
  1486. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  1487. }
  1488. DC_END_FN();
  1489. return hr;
  1490. }
  1491. HRESULT
  1492. CTSRDPRemoteDesktopClient::GenerateVersionInfoPacket(
  1493. BSTR *versionInfoPacket
  1494. )
  1495. /*++
  1496. Routine Description:
  1497. Generate a version information packet.
  1498. Arguments:
  1499. versionInfoPacket - Version Information Returned Packet
  1500. Return Value:
  1501. S_OK on success. Otherwise, an error code is returned.
  1502. --*/
  1503. {
  1504. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::GenerateVersionInfoPacket");
  1505. PREMOTEDESKTOP_CTL_BUFHEADER msgHeader;
  1506. PDWORD ptr;
  1507. HRESULT hr;
  1508. DWORD len;
  1509. len = sizeof(REMOTEDESKTOP_CTL_BUFHEADER) + (sizeof(DWORD) * 2);
  1510. msgHeader = (PREMOTEDESKTOP_CTL_BUFHEADER)SysAllocStringByteLen(NULL, len);
  1511. if (msgHeader != NULL) {
  1512. msgHeader->msgType = REMOTEDESKTOP_CTL_VERSIONINFO;
  1513. ptr = (PDWORD)(msgHeader + 1);
  1514. *ptr = REMOTEDESKTOP_VERSION_MAJOR; ptr++;
  1515. *ptr = REMOTEDESKTOP_VERSION_MINOR;
  1516. *versionInfoPacket = (BSTR)msgHeader;
  1517. hr = S_OK;
  1518. }
  1519. else {
  1520. TRC_ERR((TB, L"SysAllocStringByteLen failed for %ld bytes", len));
  1521. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  1522. }
  1523. DC_END_FN();
  1524. return hr;
  1525. }
  1526. VOID
  1527. CTSRDPRemoteDesktopClient::OnReceivedTSPublicKey(BSTR bstrPublicKey, VARIANT_BOOL* pfContinue)
  1528. {
  1529. DWORD dwStatus;
  1530. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::OnReceivedPublicKey");
  1531. CComBSTR bstrTSPublicKey;
  1532. if( m_ConnectParmVersion >= SALEM_CONNECTPARM_SECURITYBLOB_VERSION ) {
  1533. //
  1534. // hash TS public key send from client activeX control, reverse
  1535. // hashing from what we got in connect parm might not give us
  1536. // back the original value.
  1537. //
  1538. dwStatus = HashSecurityData(
  1539. (PBYTE) bstrPublicKey,
  1540. ::SysStringByteLen(bstrPublicKey),
  1541. bstrTSPublicKey
  1542. );
  1543. if( ERROR_SUCCESS != dwStatus )
  1544. {
  1545. TRC_ERR((TB, L"Hashed Public Key Send from TS %s", bstrPublicKey));
  1546. TRC_ERR((TB, L"Hashed public Key in parm %s", m_TSSecurityBlob));
  1547. TRC_ERR((TB, L"HashSecurityData() failed with %d", dwStatus));
  1548. *pfContinue = FALSE;
  1549. }
  1550. else if( !(bstrTSPublicKey == m_TSSecurityBlob) )
  1551. {
  1552. TRC_ERR((TB, L"Hashed Public Key Send from TS %s", bstrPublicKey));
  1553. TRC_ERR((TB, L"Hashed public Key in parm %s", m_TSSecurityBlob));
  1554. *pfContinue = VARIANT_FALSE;
  1555. }
  1556. else
  1557. {
  1558. *pfContinue = VARIANT_TRUE;
  1559. }
  1560. }
  1561. else {
  1562. // SECURITY : Disconnect if TS public key not present on Salem ticket,
  1563. *pfContinue = VARIANT_FALSE;
  1564. }
  1565. DC_END_FN();
  1566. }
  1567. VOID
  1568. CTSRDPRemoteDesktopClient::OnRDPConnected()
  1569. {
  1570. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::OnRDPConnected");
  1571. Fire_BeginConnect();
  1572. DC_END_FN();
  1573. }
  1574. VOID
  1575. CTSRDPRemoteDesktopClient::OnLoginComplete()
  1576. /*++
  1577. Routine Description:
  1578. Arguments:
  1579. Return Value:
  1580. --*/
  1581. {
  1582. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::OnLoginComplete");
  1583. //
  1584. // Clear server address list
  1585. //
  1586. m_ServerAddressList.clear();
  1587. //
  1588. // We got some event from the mstsc, so we must be connected, update timer
  1589. //
  1590. m_PrevTimer = GetTickCount();
  1591. CLEANUPANDEXIT:
  1592. DC_END_FN();
  1593. }
  1594. LONG
  1595. CTSRDPRemoteDesktopClient::TranslateMSTSCDisconnectCode(
  1596. DisconnectReasonCode disconReason,
  1597. ExtendedDisconnectReasonCode extendedReasonCode
  1598. )
  1599. /*++
  1600. Routine Description:
  1601. Translate an MSTSC disconnect code into a Salem disconnect
  1602. code.
  1603. Arguments:
  1604. disconReason - Disconnect Reason
  1605. extendedReasonCode - MSTSCAX Extended Reason Code
  1606. Return Value:
  1607. Salem disconnect code.
  1608. --*/
  1609. {
  1610. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::TranslateMSTSCDisconnectCode");
  1611. LONG ret;
  1612. BOOL handled;
  1613. //
  1614. // First check the extended error information.
  1615. // TODO: Need to keep track of additional values added by NadimA
  1616. // and company, here, before we ship.
  1617. //
  1618. if (extendedReasonCode != exDiscReasonNoInfo) {
  1619. //
  1620. // Record the extended error code, if given. Note that this may be
  1621. // overridden below if we have better information.
  1622. //
  1623. m_LastExtendedErrorInfo = extendedReasonCode;
  1624. //
  1625. // Check for a protocol error.
  1626. //
  1627. if ((extendedReasonCode >= exDiscReasonProtocolRangeStart) &&
  1628. (extendedReasonCode <= exDiscReasonProtocolRangeEnd)) {
  1629. ret = SAFERROR_RCPROTOCOLERROR;
  1630. goto CLEANUPANDEXIT;
  1631. }
  1632. }
  1633. //
  1634. // If the extended error information didn't help us.
  1635. //
  1636. switch(disconReason)
  1637. {
  1638. case disconnectReasonNoInfo : ret = SAFERROR_NOINFO;
  1639. break;
  1640. case disconnectReasonLocalNotError : ret = SAFERROR_LOCALNOTERROR;
  1641. break;
  1642. case disconnectReasonRemoteByUser : ret = SAFERROR_REMOTEBYUSER;
  1643. break;
  1644. case disconnectReasonByServer : ret = SAFERROR_BYSERVER;
  1645. break;
  1646. case disconnectReasonDNSLookupFailed2 : m_LastExtendedErrorInfo = disconReason;
  1647. case disconnectReasonDNSLookupFailed : ret = SAFERROR_DNSLOOKUPFAILED;
  1648. break;
  1649. case disconnectReasonOutOfMemory3 :
  1650. case disconnectReasonOutOfMemory2 : m_LastExtendedErrorInfo = disconReason;
  1651. case disconnectReasonOutOfMemory : ret = SAFERROR_OUTOFMEMORY;
  1652. break;
  1653. case disconnectReasonConnectionTimedOut : ret = SAFERROR_CONNECTIONTIMEDOUT;
  1654. break;
  1655. case disconnectReasonSocketConnectFailed : ret = SAFERROR_SOCKETCONNECTFAILED;
  1656. break;
  1657. case disconnectReasonHostNotFound : ret = SAFERROR_HOSTNOTFOUND;
  1658. break;
  1659. case disconnectReasonWinsockSendFailed : ret = SAFERROR_WINSOCKSENDFAILED;
  1660. break;
  1661. case disconnectReasonInvalidIP : m_LastExtendedErrorInfo = disconReason;
  1662. case disconnectReasonInvalidIPAddr : ret = SAFERROR_INVALIDIPADDR;
  1663. break;
  1664. case disconnectReasonSocketRecvFailed : ret = SAFERROR_SOCKETRECVFAILED;
  1665. break;
  1666. case disconnectReasonInvalidEncryption : ret = SAFERROR_INVALIDENCRYPTION;
  1667. break;
  1668. case disconnectReasonGetHostByNameFailed : ret = SAFERROR_GETHOSTBYNAMEFAILED;
  1669. break;
  1670. case disconnectReasonLicensingFailed : m_LastExtendedErrorInfo = disconReason;
  1671. case disconnectReasonLicensingTimeout : ret = SAFERROR_LICENSINGFAILED;
  1672. break;
  1673. case disconnectReasonDecryptionError : ret = SAFERROR_DECRYPTIONERROR;
  1674. break;
  1675. case disconnectReasonServerCertificateUnpackErr : ret = SAFERROR_MISMATCHPARMS;
  1676. break;
  1677. //
  1678. // Following are list of error code that is not defined in active X control IDL file
  1679. //
  1680. // NL_ERR_TDFDCLOSE
  1681. case 0x904 : ret = SAFERROR_SOCKETCONNECTFAILED;
  1682. m_LastExtendedErrorInfo = disconReason;
  1683. break;
  1684. // UI_ERR_NORMAL_DISCONNECT
  1685. case 0xb08 : ret = SAFERROR_LOCALNOTERROR;
  1686. m_LastExtendedErrorInfo = disconReason;
  1687. break;
  1688. // UI_ERR_LOOPBACK_CONSOLE_CONNECT
  1689. case 0x708 : ret = SAFERROR_SELFHELPNOTSUPPORTED;
  1690. m_LastExtendedErrorInfo = disconReason;
  1691. break;
  1692. // NL_ERR_TDTIMEOUT
  1693. case 0x704 : ret = SAFERROR_CONNECTIONTIMEDOUT;
  1694. m_LastExtendedErrorInfo = disconReason;
  1695. break;
  1696. // UI_ERR_UNEXPECTED_DISCONNECT
  1697. case 0xa08 : ret = SAFERROR_BYSERVER;
  1698. m_LastExtendedErrorInfo = disconReason;
  1699. break;
  1700. // SL_ERR_ENCRYPTFAILED
  1701. case 0xB06 : m_LastExtendedErrorInfo = disconReason;
  1702. ret = SAFERROR_ENCRYPTIONERROR;
  1703. break;
  1704. case 0x406 : // SL_ERR_NOSECURITYUSERDATA
  1705. case 0x606 : // SL_ERR_INVALIDSRVRAND
  1706. case 0x806 : // SL_ERR_GENSRVRANDFAILED
  1707. case 0x906 : // SL_ERR_ENCCLNTRANDFAILED
  1708. case 0xA06 : // SL_ERR_MKSESSKEYFAILED
  1709. case 0xA04 : // NL_ERR_TDANSICONVERT
  1710. case 0x1104 : // NL_ERR_XTBADPKTVERSION
  1711. case 0x1204 : // NL_ERR_XTBADHEADER
  1712. case 0x1304 : // NL_ERR_XTUNEXPECTEDDATA
  1713. case 0x2104 : // NL_ERR_MCSUNEXPECTEDPDU
  1714. case 0x2204 : // NL_ERR_MCSNOTCRPDU
  1715. case 0x2304 : // NL_ERR_MCSBADCRLENGTH
  1716. case 0x2404 : // NL_ERR_MCSBADCRFIELDS
  1717. case 0x2604 : // NL_ERR_MCSBADMCSREASON
  1718. case 0x2704 : // NL_ERR_MCSNOUSERIDINAUC
  1719. case 0x2804 : // NL_ERR_MCSNOCHANNELIDINCJC
  1720. case 0x3104 : // NL_ERR_NCBADMCSRESULT
  1721. case 0x3304 : // NL_ERR_NCNOUSERDATA
  1722. case 0x3404 : // NL_ERR_NCINVALIDH221KEY
  1723. case 0x3504 : // NL_ERR_NCNONETDATA
  1724. case 0x3604 : // NL_ERR_NCATTACHUSERFAILED
  1725. case 0x3704 : // NL_ERR_NCCHANNELJOINFAILED
  1726. case 0x3804 : // NL_ERR_NCJOINBADCHANNEL
  1727. case 0x3904 : // NL_ERR_NCNOCOREDATA
  1728. case 0x3a04 : // NL_ERR_NCVERSIONMISMATCH
  1729. case 0x408 : // UI_ERR_ANSICONVERT
  1730. case 0x608 : // UI_ERR_NOTIMER
  1731. m_LastExtendedErrorInfo = disconReason;
  1732. ret = SAFERROR_RCPROTOCOLERROR;
  1733. break;
  1734. //
  1735. // New active X control disconnect code, assert to track this
  1736. //
  1737. default: ret = SAFERROR_RCUNKNOWNERROR;
  1738. m_LastExtendedErrorInfo = disconReason;
  1739. ASSERT(FALSE);
  1740. }
  1741. CLEANUPANDEXIT:
  1742. DC_END_FN();
  1743. return ret;
  1744. }
  1745. VOID
  1746. CTSRDPRemoteDesktopClient::OnDisconnected(
  1747. long disconReason
  1748. )
  1749. /*++
  1750. Routine Description:
  1751. Arguments:
  1752. Return Value:
  1753. --*/
  1754. {
  1755. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::OnDisconnected");
  1756. HRESULT hr = E_HANDLE; // initialize an error code.
  1757. long clientReturnCode;
  1758. ExtendedDisconnectReasonCode extendedClientCode;
  1759. TRC_ERR((TB, L"Disconnected because %ld", disconReason));
  1760. m_TSClient->get_ExtendedDisconnectReason(&extendedClientCode);
  1761. clientReturnCode = TranslateMSTSCDisconnectCode(
  1762. (DisconnectReasonCode)disconReason,
  1763. extendedClientCode
  1764. );
  1765. // Go thru all remaining server:port, mstscax might return some
  1766. // error code that we don't understand.
  1767. if( m_ServerAddressList.size() > 0 ) {
  1768. ServerAddress address;
  1769. address = m_ServerAddressList.front();
  1770. m_ServerAddressList.pop_front();
  1771. hr = ConnectServerPort( address.ServerName, address.portNumber );
  1772. if (FAILED(hr)) {
  1773. TRC_ERR((TB, L"ConnectServerPort: %08X", hr));
  1774. }
  1775. }
  1776. //
  1777. // Return the error code from connecting to 'last' server to client
  1778. //
  1779. if( FAILED(hr) ) {
  1780. m_ServerAddressList.clear();
  1781. //
  1782. // Always fire remote control request before disconnect event
  1783. //
  1784. //
  1785. // Fire the remote control request failure event, if appropriate.
  1786. //
  1787. if (m_RemoteControlRequestInProgress) {
  1788. ASSERT(clientReturnCode != SAFERROR_NOERROR);
  1789. Fire_RemoteControlRequestComplete(SAFERROR_SHADOWEND_UNKNOWN);
  1790. m_RemoteControlRequestInProgress = FALSE;
  1791. }
  1792. //
  1793. // Fire the server disconnect event, if we are really connected or
  1794. // we have a connection in progress.
  1795. //
  1796. if (m_ConnectedToServer || m_ConnectionInProgress) {
  1797. Fire_Disconnected(clientReturnCode);
  1798. }
  1799. m_ConnectedToServer = FALSE;
  1800. m_ConnectionInProgress = FALSE;
  1801. ListenConnectCleanup();
  1802. }
  1803. DC_END_FN();
  1804. }
  1805. HRESULT
  1806. CTSRDPRemoteDesktopClient::SendTerminateRCKeysToServer()
  1807. /*++
  1808. Routine Description:
  1809. Send the terminate shadowing key sequence to the server.
  1810. Arguments:
  1811. Return Value:
  1812. S_OK on success. Otherwise, an error status is returned.
  1813. --*/
  1814. {
  1815. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::SendTerminateRCKeysToServer");
  1816. HRESULT hr = S_OK;
  1817. IMsRdpClientNonScriptable* pTscNonScript = NULL;
  1818. VARIANT_BOOL keyUp[] = {
  1819. VARIANT_FALSE, VARIANT_FALSE, VARIANT_TRUE, VARIANT_TRUE
  1820. };
  1821. LONG keyData[] = {
  1822. MapVirtualKey(VK_CONTROL, 0), // these are SCANCODES.
  1823. MapVirtualKey(VK_MULTIPLY, 0),
  1824. MapVirtualKey(VK_MULTIPLY, 0),
  1825. MapVirtualKey(VK_CONTROL, 0),
  1826. };
  1827. //
  1828. // Send the terminate keys to the server.
  1829. //
  1830. hr = m_TSClient->QueryInterface(
  1831. IID_IMsRdpClientNonScriptable,
  1832. (void**)&pTscNonScript
  1833. );
  1834. if (hr != S_OK) {
  1835. TRC_ERR((TB, L"QI: %08X", hr));
  1836. goto CLEANUPANDEXIT;
  1837. }
  1838. pTscNonScript->NotifyRedirectDeviceChange(0, 0);
  1839. pTscNonScript->SendKeys(4, keyUp, keyData);
  1840. if (hr != S_OK) {
  1841. TRC_ERR((TB, L"SendKeys, QI: %08X", hr));
  1842. }
  1843. pTscNonScript->Release();
  1844. CLEANUPANDEXIT:
  1845. DC_END_FN();
  1846. return hr;
  1847. }
  1848. HWND CTSRDPRemoteDesktopClient::SearchForWindow(
  1849. HWND hwndParent,
  1850. LPTSTR srchCaption,
  1851. LPTSTR srchClass
  1852. )
  1853. /*++
  1854. Routine Description:
  1855. Search for a child window of the specified parent window.
  1856. Arguments:
  1857. srchCaption - Window caption for which to search. NULL is
  1858. considered a wildcard.
  1859. srchClass - Window class for which to search. NULL is
  1860. considred a wildcard.
  1861. Return Value:
  1862. S_OK on success. Otherwise, an error status is returned.
  1863. --*/
  1864. {
  1865. WINSEARCH srch;
  1866. srch.foundWindow = NULL;
  1867. srch.srchCaption = srchCaption;
  1868. srch.srchClass = srchClass;
  1869. BOOL result = EnumChildWindows(
  1870. hwndParent,
  1871. (WNDENUMPROC)_WindowSrchProc,
  1872. (LPARAM)&srch
  1873. );
  1874. return srch.foundWindow;
  1875. }
  1876. BOOL CALLBACK
  1877. CTSRDPRemoteDesktopClient::_WindowSrchProc(HWND hwnd, PWINSEARCH srch)
  1878. {
  1879. TCHAR classname[128];
  1880. TCHAR caption[128];
  1881. if (srch->srchClass && !GetClassName(hwnd, classname, sizeof(classname) / sizeof(TCHAR)))
  1882. {
  1883. return TRUE;
  1884. }
  1885. if (srch->srchCaption && !::GetWindowText(hwnd, caption, sizeof(caption)/sizeof(TCHAR)))
  1886. {
  1887. return TRUE;
  1888. }
  1889. if ((!srch->srchClass || !_tcscmp(classname, srch->srchClass)
  1890. &&
  1891. (!srch->srchCaption || !_tcscmp(caption, srch->srchCaption)))
  1892. )
  1893. {
  1894. srch->foundWindow = hwnd;
  1895. return FALSE;
  1896. }
  1897. return TRUE;
  1898. }
  1899. HRESULT
  1900. CTSRDPRemoteDesktopClient::GenerateNullData( BSTR* pbstrData )
  1901. {
  1902. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::GenerateNullData");
  1903. HRESULT hr;
  1904. DWORD len;
  1905. PREMOTEDESKTOP_CTL_BUFHEADER msgHeader = NULL;
  1906. len = sizeof( REMOTEDESKTOP_CTL_BUFHEADER );
  1907. msgHeader = (PREMOTEDESKTOP_CTL_BUFHEADER)SysAllocStringByteLen(NULL, len);
  1908. if (msgHeader != NULL) {
  1909. msgHeader->msgType = REMOTEDESKTOP_CTL_ISCONNECTED;
  1910. //nothing else other than the message
  1911. *pbstrData = (BSTR)msgHeader;
  1912. hr = S_OK;
  1913. }
  1914. else {
  1915. TRC_ERR((TB, L"SysAllocStringByteLen failed for %ld bytes", len));
  1916. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  1917. }
  1918. DC_END_FN();
  1919. return hr;
  1920. }
  1921. LRESULT CTSRDPRemoteDesktopClient::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1922. {
  1923. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::OnCheckConnectTimer");
  1924. BSTR bstrMsg = NULL;
  1925. if( WM_LISTENTIMEOUT_TIMER == wParam ) {
  1926. bHandled = TRUE;
  1927. if( TRUE == ListenConnectInProgress() ) {
  1928. //
  1929. // This function will fire the listen connect callback for us.
  1930. //
  1931. StopListenInternal(SAFERROR_CONNECTIONTIMEDOUT);
  1932. }
  1933. }
  1934. else if ( WM_CONNECTCHECK_TIMER == wParam ) {
  1935. DWORD dwCurTimer = GetTickCount();
  1936. bHandled = TRUE;
  1937. if(m_ConnectedToServer) {
  1938. //
  1939. //see if the timer wrapped around to zero (does so if the system was up 49.7 days or something)
  1940. //if so reset it
  1941. //
  1942. if( dwCurTimer > m_PrevTimer && ( dwCurTimer - m_PrevTimer >= m_RdcConnCheckTimeInterval )) {
  1943. //
  1944. //time to send a null data
  1945. //
  1946. if(SUCCEEDED(GenerateNullData(&bstrMsg))) {
  1947. if(!SUCCEEDED(m_CtlChannel->SendChannelData(bstrMsg))) {
  1948. //
  1949. //could not send data, assume disconnected
  1950. //
  1951. DisconnectFromServer();
  1952. //
  1953. //don't need the timer anymore, kill it
  1954. //
  1955. KillTimer( m_TimerId );
  1956. m_TimerId = 0;
  1957. }
  1958. }
  1959. }
  1960. } //m_ConnectedToServer
  1961. //
  1962. //update the timer
  1963. //
  1964. m_PrevTimer = dwCurTimer;
  1965. if( NULL != bstrMsg ) {
  1966. SysFreeString(bstrMsg);
  1967. }
  1968. }
  1969. DC_END_FN();
  1970. return 0;
  1971. }
  1972. STDMETHODIMP
  1973. CTSRDPRemoteDesktopClient::CreateListenEndpoint(
  1974. IN LONG port,
  1975. OUT BSTR* pConnectParm
  1976. )
  1977. /*++
  1978. Description:
  1979. Routine to create a listening socket and return connection parameter to this 'listen' socket.
  1980. Parameters:
  1981. port : Port that socket should listen on.
  1982. pConnectParm : Return connection parameter to this listening socket.
  1983. returns:
  1984. S_OK or error code.
  1985. Notes:
  1986. Function is async, return code, if error, is for listening thread set up, caller is notified of
  1987. successful or error in network connection via ListenConnect event.
  1988. --*/
  1989. {
  1990. HRESULT hr = S_OK;
  1991. LPTSTR pszUserName = NULL;
  1992. LPTSTR eventString[2];
  1993. SOCKET hListenSocket = INVALID_SOCKET;
  1994. IMsRdpClientAdvancedSettings* pAdvSettings;
  1995. LONG rdpPort = 0;
  1996. int intRC;
  1997. int lastError;
  1998. SOCKADDR_IN sockAddr;
  1999. int sockAddrSize;
  2000. int optvalue;
  2001. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::CreateListenEndpoint");
  2002. if( NULL == pConnectParm )
  2003. {
  2004. hr = E_POINTER;
  2005. return hr;
  2006. }
  2007. if (!IsValid()) {
  2008. ASSERT(FALSE);
  2009. hr = E_FAIL;
  2010. return hr;
  2011. }
  2012. //
  2013. // Return error if we are in progress of connect or connected.
  2014. //
  2015. if( TRUE == ListenConnectInProgress() || // Listen already started.
  2016. TRUE == m_ConnectionInProgress || // Connection already in progress
  2017. TRUE == m_ConnectedToServer ) { // Already connected to server
  2018. hr = HRESULT_FROM_WIN32( ERROR_SHARING_VIOLATION );
  2019. TRC_ERR((TB, L"StartListen() already in listen"));
  2020. goto CLEANUPANDEXIT;
  2021. }
  2022. //
  2023. // Initialize Winsock and ICS library if not yet initialized.
  2024. // InitListeningLibrary() will only add ref. count
  2025. // if library already initialized by other instance.
  2026. //
  2027. if( FALSE == m_InitListeningLibrary ) {
  2028. hr = InitListeningLibrary();
  2029. if( FAILED(hr) ) {
  2030. TRC_ERR((TB, L"InitListeningLibrary() failed : %08X", hr));
  2031. goto CLEANUPANDEXIT;
  2032. }
  2033. m_InitListeningLibrary = TRUE;
  2034. }
  2035. //
  2036. // mstscax will close the socket once connection is ended.
  2037. //
  2038. m_TSConnectSocket = INVALID_SOCKET;
  2039. //
  2040. // Create a listening socket
  2041. //
  2042. m_ListenSocket = socket(AF_INET, SOCK_STREAM, 0);
  2043. if( INVALID_SOCKET == m_ListenSocket ) {
  2044. intRC = WSAGetLastError();
  2045. TRC_ERR((TB, _T("socket failed %d"), intRC));
  2046. hr = HRESULT_FROM_WIN32(intRC);
  2047. goto CLEANUPANDEXIT;
  2048. }
  2049. //
  2050. // Disable NAGLE algorithm and enable don't linger option.
  2051. //
  2052. optvalue = 1;
  2053. setsockopt( m_ListenSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&optvalue, sizeof(optvalue) );
  2054. optvalue = 1;
  2055. setsockopt( m_ListenSocket, SOL_SOCKET, SO_DONTLINGER, (char *)&optvalue, sizeof(optvalue) );
  2056. //
  2057. // Request async notifications to send to our window
  2058. //
  2059. intRC = WSAAsyncSelect(
  2060. m_ListenSocket,
  2061. m_hWnd,
  2062. WM_TSCONNECT,
  2063. FD_ACCEPT
  2064. );
  2065. if(SOCKET_ERROR == intRC) {
  2066. intRC = WSAGetLastError();
  2067. TRC_ERR((TB, _T("WSAAsyncSelect failed %d"), intRC));
  2068. hr = HRESULT_FROM_WIN32(intRC);
  2069. goto CLEANUPANDEXIT;
  2070. }
  2071. sockAddr.sin_family = AF_INET;
  2072. sockAddr.sin_port = htons(port);
  2073. sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);;
  2074. intRC = bind( m_ListenSocket, (struct sockaddr *) &sockAddr, sizeof(sockAddr) );
  2075. if( SOCKET_ERROR == intRC ) {
  2076. lastError = WSAGetLastError();
  2077. TRC_ERR((TB, _T("bind failed - %d"), lastError));
  2078. hr = HRESULT_FROM_WIN32( lastError );
  2079. goto CLEANUPANDEXIT;
  2080. }
  2081. if( 0 == port ) {
  2082. //
  2083. // Retrieve which port we are listening
  2084. //
  2085. sockAddrSize = sizeof( sockAddr );
  2086. intRC = getsockname(
  2087. m_ListenSocket,
  2088. (struct sockaddr *)&sockAddr,
  2089. &sockAddrSize
  2090. );
  2091. if( SOCKET_ERROR == intRC )
  2092. {
  2093. lastError = WSAGetLastError();
  2094. TRC_ERR((TB, _T("getsockname failed - GLE:%d"),lastError));
  2095. hr = HRESULT_FROM_WIN32( lastError );
  2096. goto CLEANUPANDEXIT;
  2097. }
  2098. m_ConnectedPort = ntohs(sockAddr.sin_port);
  2099. }
  2100. else {
  2101. m_ConnectedPort = port;
  2102. }
  2103. TRC_ERR((TB, _T("Listenin on port %d"),m_ConnectedPort));
  2104. //
  2105. // Tell ICS library to punch a hole thru ICS, no-op
  2106. // if not ICS configuration.
  2107. //
  2108. m_ICSPort = OpenPort( m_ConnectedPort );
  2109. //
  2110. // Retrieve connection parameters for this client (expert).
  2111. //
  2112. hr = RetrieveUserConnectParm( pConnectParm );
  2113. if( FAILED(hr) ) {
  2114. TRC_ERR((TB, _T("RetrieveUserConnectParm failed - 0x%08x"),hr));
  2115. }
  2116. //
  2117. // Log SESSMGR_I_CREATEXPERTTICKET Event, if we can't current user,
  2118. // stoplisten and return error
  2119. //
  2120. hr = GetCurrentUser( &pszUserName );
  2121. if( SUCCEEDED(hr) ) {
  2122. eventString[0] = pszUserName;
  2123. eventString[1] = *pConnectParm;
  2124. LogRemoteAssistanceEventString(
  2125. EVENTLOG_INFORMATION_TYPE,
  2126. SESSMGR_I_CREATEXPERTTICKET,
  2127. 2,
  2128. eventString
  2129. );
  2130. }
  2131. CLEANUPANDEXIT:
  2132. if( pszUserName != NULL ) {
  2133. LocalFree(pszUserName);
  2134. }
  2135. if( FAILED(hr) ) {
  2136. StopListen();
  2137. }
  2138. DC_END_FN();
  2139. return hr;
  2140. }
  2141. HRESULT
  2142. CTSRDPRemoteDesktopClient::StopListenInternal(
  2143. LONG returnCode
  2144. )
  2145. /*++
  2146. Description:
  2147. Stop listening waiting for TS server (helpee, user) to connect.
  2148. This is an internal version for dealing with calls from external
  2149. and internal contexts.
  2150. Parameters:
  2151. returnCode - If non-zero then we return it back to the client
  2152. in the ListenConnect event callback. Otherwise, we will
  2153. return SAFERROR_STOPLISTENBYUSER.
  2154. Returns:
  2155. S_OK or error code.
  2156. --*/
  2157. {
  2158. HRESULT hr = S_OK;
  2159. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::StopListenInternal");
  2160. if (!IsValid()) {
  2161. ASSERT(FALSE);
  2162. hr = E_FAIL;
  2163. return hr;
  2164. }
  2165. // End listening, either we are actually issued a listen() to socket
  2166. // or we just created the listen socket but not yet start listening
  2167. if( TRUE == ListenConnectInProgress() || INVALID_SOCKET != m_ListenSocket ) {
  2168. ListenConnectCleanup();
  2169. Fire_ListenConnect((returnCode != 0) ? returnCode : SAFERROR_STOPLISTENBYUSER);
  2170. }
  2171. else {
  2172. TRC_ERR((TB, _T("StopListen called while not in listen mode")));
  2173. hr = HRESULT_FROM_WIN32( WSANOTINITIALISED );
  2174. }
  2175. DC_END_FN();
  2176. return hr;
  2177. }
  2178. LRESULT
  2179. CTSRDPRemoteDesktopClient::OnTSConnect(
  2180. UINT uMsg,
  2181. WPARAM wParam,
  2182. LPARAM lParam,
  2183. BOOL& bHandled
  2184. )
  2185. /*++
  2186. Routine Description:
  2187. Window Message Handler FD_ACCEPT from async. winsock.
  2188. Parameters:
  2189. Refer to async. winsock FD_ACCEPT.
  2190. Returns:
  2191. --*/
  2192. {
  2193. WORD eventWSA;
  2194. WORD errorWSA;
  2195. HRESULT hr = S_OK;
  2196. SOCKADDR_IN inSockAddr;
  2197. int inSockAddrSize;
  2198. SOCKET s;
  2199. DWORD dwStatus;
  2200. DWORD SafErrorCode = SAFERROR_NOERROR;
  2201. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::OnTSConnect");
  2202. eventWSA = WSAGETSELECTEVENT(lParam);
  2203. errorWSA = WSAGETSELECTERROR(lParam);
  2204. //
  2205. // MSDN : Message might already in our queue before we stop listen.
  2206. //
  2207. if( INVALID_SOCKET == m_ListenSocket || FALSE == ListenConnectInProgress() ) {
  2208. bHandled = TRUE;
  2209. return 0;
  2210. }
  2211. //
  2212. // we are not expecting event other than FD_CONNECT
  2213. //
  2214. if( eventWSA != FD_ACCEPT ) {
  2215. TRC_ERR((TB, _T("Expecting event %d got got %d"), FD_CONNECT, eventWSA));
  2216. return 0;
  2217. }
  2218. //
  2219. // Make sure we don't do anything other than our own socket
  2220. //
  2221. if( (SOCKET)wParam != m_ListenSocket ) {
  2222. TRC_ERR((TB, _T("Expecting listening socket %d got %d"), m_ListenSocket, wParam));
  2223. return 0;
  2224. }
  2225. //
  2226. // We handle the message
  2227. //
  2228. bHandled = TRUE;
  2229. //
  2230. // Error occurred, fire a error event.
  2231. //
  2232. if( 0 != errorWSA ) {
  2233. TRC_ERR((TB, _T("WSA socket listen failed : %d"), errorWSA));
  2234. hr = HRESULT_FROM_WIN32( errorWSA );
  2235. SafErrorCode = SAFERROR_SOCKETCONNECTFAILED;
  2236. goto CLEANUPANDEXIT;
  2237. }
  2238. inSockAddrSize = sizeof(inSockAddr);
  2239. m_TSConnectSocket = accept( m_ListenSocket,
  2240. (struct sockaddr DCPTR)&inSockAddr,
  2241. &inSockAddrSize
  2242. );
  2243. if( INVALID_SOCKET == m_TSConnectSocket ) {
  2244. dwStatus = WSAGetLastError();
  2245. hr = HRESULT_FROM_WIN32(dwStatus);
  2246. TRC_ERR((TB, _T("accept failed : %d"), dwStatus));
  2247. SafErrorCode = SAFERROR_SOCKETCONNECTFAILED;
  2248. goto CLEANUPANDEXIT;
  2249. }
  2250. //
  2251. // Cached connecting TS server IP address.
  2252. // m_ConnectPort is set at the time we bind socket
  2253. //
  2254. m_ConnectedServer = inet_ntoa(inSockAddr.sin_addr);
  2255. //
  2256. // Stop async. event notification now, accepted socket
  2257. // has same properties as original listening socket.
  2258. //
  2259. dwStatus = WSAAsyncSelect(
  2260. m_TSConnectSocket,
  2261. m_hWnd,
  2262. 0,
  2263. 0
  2264. );
  2265. //
  2266. // Not critical,
  2267. // listening socket.
  2268. //
  2269. if((DWORD)SOCKET_ERROR == dwStatus) {
  2270. TRC_ERR((TB, _T("WSAAsyncSelect resetting notification failed : %d"), dwStatus));
  2271. }
  2272. CLEANUPANDEXIT:
  2273. //
  2274. // Close listening socket and kill timer.
  2275. //
  2276. if( (UINT_PTR)0 != m_ListenTimeoutTimerID )
  2277. {
  2278. KillTimer( m_ListenTimeoutTimerID );
  2279. m_ListenTimeoutTimerID = (UINT_PTR)0;
  2280. }
  2281. if( INVALID_SOCKET != m_ListenSocket )
  2282. {
  2283. closesocket( m_ListenSocket );
  2284. m_ListenSocket = INVALID_SOCKET;
  2285. }
  2286. //
  2287. // Successfully established connection, terminate listening socket
  2288. //
  2289. Fire_ListenConnect( SafErrorCode );
  2290. DC_END_FN();
  2291. return 0;
  2292. }
  2293. STDMETHODIMP
  2294. CTSRDPRemoteDesktopClient::StartListen(
  2295. /*[in]*/ LONG timeout
  2296. )
  2297. /*++
  2298. Routine Description:
  2299. Put client into listen mode with optionally timeout.
  2300. Parameters:
  2301. timeout : Listen wait timeout, 0 for infinite.
  2302. Returns:
  2303. S_OK or error code.
  2304. --*/
  2305. {
  2306. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::OnTSConnect");
  2307. HRESULT hr = S_OK;
  2308. int intRC;
  2309. int lastError;
  2310. if( FALSE == IsValid() ) {
  2311. hr = E_FAIL;
  2312. goto CLEANUPANDEXIT;
  2313. }
  2314. if( INVALID_SOCKET == m_ListenSocket ) {
  2315. hr = E_FAIL;
  2316. goto CLEANUPANDEXIT;
  2317. }
  2318. //
  2319. // Start listening on the port
  2320. //
  2321. intRC = listen( m_ListenSocket, SOMAXCONN );
  2322. if( SOCKET_ERROR == intRC )
  2323. {
  2324. lastError = WSAGetLastError();
  2325. TRC_ERR((TB, _T("listen failed - GLE:%d"), lastError));
  2326. hr = HRESULT_FROM_WIN32( lastError );
  2327. goto CLEANUPANDEXIT;
  2328. }
  2329. //
  2330. // we are in listening now.
  2331. //
  2332. m_ListenConnectInProgress = TRUE;
  2333. //
  2334. // Start listening timer
  2335. //
  2336. if( 0 != timeout )
  2337. {
  2338. m_ListenTimeoutTimerID = SetTimer( (UINT_PTR)WM_LISTENTIMEOUT_TIMER, (UINT)(timeout * 1000) );
  2339. if( (UINT_PTR)0 == m_ListenTimeoutTimerID )
  2340. {
  2341. DWORD dwStatus;
  2342. // Failed to create a timer
  2343. dwStatus = GetLastError();
  2344. TRC_ERR((TB, _T("SetTimer failed - %d"),dwStatus));
  2345. hr = HRESULT_FROM_WIN32( dwStatus );
  2346. }
  2347. }
  2348. else
  2349. {
  2350. m_ListenTimeoutTimerID = (UINT_PTR)0;
  2351. }
  2352. CLEANUPANDEXIT:
  2353. if( FAILED(hr) ) {
  2354. StopListen();
  2355. }
  2356. DC_END_FN();
  2357. return hr;
  2358. }
  2359. HRESULT
  2360. CTSRDPRemoteDesktopClient::RetrieveUserConnectParm(
  2361. BSTR* pConnectParm
  2362. )
  2363. /*++
  2364. Routine Description:
  2365. Retrieve Salem connection parameter to this expert.
  2366. Parameters:
  2367. pConnectParm : Pointer to BSTR to receive connect parm.
  2368. Returns:
  2369. S_OK or error code.
  2370. --*/
  2371. {
  2372. LPTSTR pszAddress = NULL;
  2373. int BufSize = 0;
  2374. CComBSTR bstrConnParm;
  2375. DWORD dwRetry;
  2376. HRESULT hRes;
  2377. DWORD dwBufferRequire;
  2378. DWORD dwNumChars;
  2379. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::RetrieveUserConnectParm");
  2380. if( NULL == pConnectParm )
  2381. {
  2382. hRes = E_POINTER;
  2383. goto CLEANUPANDEXIT;
  2384. }
  2385. //
  2386. // Address might have change which might require bigger buffer, retry
  2387. //
  2388. //
  2389. for(dwRetry=0; dwRetry < MAX_FETCHIPADDRESSRETRY; dwRetry++) {
  2390. if( NULL != pszAddress ) {
  2391. LocalFree( pszAddress );
  2392. }
  2393. //
  2394. // Fetch all address on local machine.
  2395. //
  2396. dwBufferRequire = FetchAllAddresses( NULL, 0 );
  2397. if( 0 == dwBufferRequire ) {
  2398. hRes = E_UNEXPECTED;
  2399. ASSERT(FALSE);
  2400. goto CLEANUPANDEXIT;
  2401. }
  2402. pszAddress = (LPTSTR) LocalAlloc( LPTR, sizeof(TCHAR)*(dwBufferRequire+1) );
  2403. if( NULL == pszAddress ) {
  2404. hRes = E_OUTOFMEMORY;
  2405. goto CLEANUPANDEXIT;
  2406. }
  2407. dwNumChars = FetchAllAddresses( pszAddress, dwBufferRequire );
  2408. ASSERT( dwNumChars <= dwBufferRequire );
  2409. if( dwNumChars <= dwBufferRequire ) {
  2410. break;
  2411. }
  2412. }
  2413. if( NULL == pszAddress ) {
  2414. hRes = E_UNEXPECTED;
  2415. goto CLEANUPANDEXIT;
  2416. }
  2417. bstrConnParm = pszAddress;
  2418. *pConnectParm = bstrConnParm.Copy();
  2419. if( NULL == *pConnectParm ) {
  2420. hRes = E_OUTOFMEMORY;
  2421. }
  2422. CLEANUPANDEXIT:
  2423. if( NULL != pszAddress ) {
  2424. LocalFree(pszAddress);
  2425. }
  2426. DC_END_FN();
  2427. return hRes;
  2428. }
  2429. STDMETHODIMP
  2430. CTSRDPRemoteDesktopClient::put_ColorDepth(
  2431. LONG val
  2432. )
  2433. /*++
  2434. Routine Description:
  2435. Set Color depth
  2436. Arguments:
  2437. val - Value in bits perpel to set
  2438. Return Value:
  2439. S_OK on success. Otherwise, an error code is returned.
  2440. --*/
  2441. {
  2442. HRESULT hr;
  2443. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::put_ColorDepth");
  2444. if (!IsValid()) {
  2445. ASSERT(FALSE);
  2446. hr = E_FAIL;
  2447. goto CLEANUPANDEXIT;
  2448. }
  2449. hr = m_TSClient->put_ColorDepth(val);
  2450. if (hr != S_OK) {
  2451. TRC_ERR((TB, L"put_ColorDepth: %08X", hr));
  2452. goto CLEANUPANDEXIT;
  2453. }
  2454. CLEANUPANDEXIT:
  2455. DC_END_FN();
  2456. return hr;
  2457. }
  2458. STDMETHODIMP
  2459. CTSRDPRemoteDesktopClient::get_ColorDepth(
  2460. LONG *pVal
  2461. )
  2462. /*++
  2463. Routine Description:
  2464. Get Color depth
  2465. Arguments:
  2466. pVal - address to place the colordepth value in
  2467. Return Value:
  2468. S_OK on success. Otherwise, an error code is returned.
  2469. --*/
  2470. {
  2471. HRESULT hr;
  2472. IMsRdpClientAdvancedSettings *pAdvSettings = NULL;
  2473. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::get_ColorDepth");
  2474. if (!IsValid()) {
  2475. ASSERT(FALSE);
  2476. hr = E_FAIL;
  2477. goto CLEANUPANDEXIT;
  2478. }
  2479. hr = m_TSClient->get_ColorDepth(pVal);
  2480. if (hr != S_OK) {
  2481. TRC_ERR((TB, L"get_ColorDepth: %08X", hr));
  2482. goto CLEANUPANDEXIT;
  2483. }
  2484. CLEANUPANDEXIT:
  2485. DC_END_FN();
  2486. return hr;
  2487. }
  2488. HRESULT
  2489. CTSRDPRemoteDesktopClient::GetCurrentUser(
  2490. LPTSTR* ppszUserName
  2491. )
  2492. /*++
  2493. Routine Description:
  2494. Return currently logon user name in the form of
  2495. Windows NT 4.0 account name (for example, Engineering\JSmith).
  2496. Parameters:
  2497. ppszUserName : Pointer to pointer to receive currently logon user name, use LocalFree()
  2498. to free memory.
  2499. Returns:
  2500. S_OK or error code.
  2501. --*/
  2502. {
  2503. DWORD status;
  2504. LPTSTR pszUserNameBuf = NULL;
  2505. DWORD userNameBufSize = 0;
  2506. BOOLEAN succeeded;
  2507. DC_BEGIN_FN("CTSRDPRemoteDesktopClient::GetCurrentUser");
  2508. succeeded = GetUserNameEx( NameSamCompatible, pszUserNameBuf, &userNameBufSize );
  2509. if( FALSE == succeeded ) {
  2510. status = GetLastError();
  2511. if( ERROR_MORE_DATA != status ) {
  2512. TRC_ERR((TB, _T("GetUserNameEx failed - 0x%08x"), status));
  2513. goto CLEANUPANDEXIT;
  2514. }
  2515. }
  2516. pszUserNameBuf = (LPTSTR)LocalAlloc( LPTR, sizeof(TCHAR)*(userNameBufSize+1) );
  2517. if( NULL == pszUserNameBuf ) {
  2518. // out of memory
  2519. status = GetLastError();
  2520. goto CLEANUPANDEXIT;
  2521. }
  2522. succeeded = GetUserNameEx( NameSamCompatible, pszUserNameBuf, &userNameBufSize );
  2523. if( FALSE == succeeded ) {
  2524. status = GetLastError();
  2525. TRC_ERR((TB, _T("GetUserNameEx failed - 0x%08x"),status));
  2526. goto CLEANUPANDEXIT;
  2527. }
  2528. status = ERROR_SUCCESS;
  2529. *ppszUserName = pszUserNameBuf;
  2530. pszUserNameBuf = NULL;
  2531. CLEANUPANDEXIT:
  2532. if( NULL != pszUserNameBuf ) {
  2533. LocalFree(pszUserNameBuf);
  2534. }
  2535. DC_END_FN();
  2536. return HRESULT_FROM_WIN32(status);
  2537. }