Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

962 lines
25 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. RDPRemoteDesktopServerHost
  5. Abstract:
  6. This module contains the CRemoteDesktopServerHost implementation
  7. of RDS session objects.
  8. It manages a collection of open ISAFRemoteDesktopSession objects.
  9. New RDS session objects instances are created using the CreateRemoteDesktopSession
  10. method. Existing RDS session objects are opened using the OpenRemoteDesktopSession
  11. method. RDS session objects are closed using the CloseRemoteDesktopSession method.
  12. When an RDS object is opened or created, the CRemoteDesktopServerHost
  13. object adds a reference of its own to the object so that the object will
  14. stay around, even if the opening application exits. This reference
  15. is retracted when the application calls the CloseRemoteDesktopSession method.
  16. In addition to the reference count the CRemoteDesktopServerHost adds to
  17. the RDS session object, a reference count is also added to itself so that
  18. the associated exe continues to run while RDS session objects are active.
  19. Author:
  20. Tad Brockway 02/00
  21. Revision History:
  22. --*/
  23. #include <RemoteDesktop.h>
  24. #include "stdafx.h"
  25. #ifdef TRC_FILE
  26. #undef TRC_FILE
  27. #endif
  28. #define TRC_FILE "_svrhst"
  29. #include "RemoteDesktopUtils.h"
  30. #include "parseaddr.h"
  31. #include "RDSHost.h"
  32. #include "RemoteDesktopServerHost.h"
  33. #include "TSRDPRemoteDesktopSession.h"
  34. #include "rderror.h"
  35. ///////////////////////////////////////////////////////
  36. //
  37. // CRemoteDesktopServerHost Methods
  38. //
  39. HRESULT
  40. CRemoteDesktopServerHost::FinalConstruct()
  41. /*++
  42. Routine Description:
  43. Arguments:
  44. Return Value:
  45. S_OK on success. Otherwise, an error code is returned.
  46. --*/
  47. {
  48. DC_BEGIN_FN("CRemoteDesktopServerHost::FinalConstruct");
  49. HRESULT hr = S_OK;
  50. CLEANUPANDEXIT:
  51. DC_END_FN();
  52. return hr;
  53. }
  54. CRemoteDesktopServerHost::~CRemoteDesktopServerHost()
  55. /*++
  56. Routine Description:
  57. Destructor
  58. Arguments:
  59. Return Value:
  60. S_OK on success. Otherwise, an error code is returned.
  61. --*/
  62. {
  63. DC_BEGIN_FN("CRemoteDesktopServerHost::~CRemoteDesktopServerHost");
  64. //
  65. // We shouldn't be shutting down, unless our session map is empty.
  66. //
  67. ASSERT(m_SessionMap.empty());
  68. //
  69. // Clean up the local system SID.
  70. //
  71. if (m_LocalSystemSID == NULL) {
  72. FreeSid(m_LocalSystemSID);
  73. }
  74. DC_END_FN();
  75. }
  76. STDMETHODIMP
  77. CRemoteDesktopServerHost::CreateRemoteDesktopSession(
  78. REMOTE_DESKTOP_SHARING_CLASS sharingClass,
  79. BOOL fEnableCallback,
  80. LONG timeOut,
  81. BSTR userHelpBlob,
  82. ISAFRemoteDesktopSession **session
  83. )
  84. /*++
  85. Routine Description:
  86. Create a new RDS session
  87. Arguments:
  88. Return Value:
  89. S_OK on success. Otherwise, an error code is returned.
  90. --*/
  91. {
  92. DC_BEGIN_FN("CRemoteDesktopServerHost::CreateRemoteDesktopSession");
  93. HRESULT hr;
  94. CComBSTR bstr; bstr = "";
  95. hr = CreateRemoteDesktopSessionEx(
  96. sharingClass,
  97. fEnableCallback,
  98. timeOut,
  99. userHelpBlob,
  100. -1,
  101. bstr,
  102. session
  103. );
  104. DC_END_FN();
  105. return hr;
  106. }
  107. STDMETHODIMP
  108. CRemoteDesktopServerHost::CreateRemoteDesktopSessionEx(
  109. REMOTE_DESKTOP_SHARING_CLASS sharingClass,
  110. BOOL bEnableCallback,
  111. LONG timeout,
  112. BSTR userHelpCreateBlob,
  113. LONG tsSessionID,
  114. BSTR userSID,
  115. ISAFRemoteDesktopSession **session
  116. )
  117. /*++
  118. Routine Description:
  119. Create a new RDS session
  120. Note that the caller MUST call OpenRemoteDesktopSession() subsequent to
  121. a successful completion of this call.
  122. The connection does NOT happen until OpenRemoteDesktopSession() is called.
  123. This call just initializes certain data, it does not open a connection
  124. Arguments:
  125. sharingClass - Desktop Sharing Class
  126. fEnableCallback - TRUE if the Resolver is Enabled
  127. timeOut - Lifespan of Remote Desktop Session
  128. userHelpBlob - Optional User Blob to be Passed
  129. to Resolver.
  130. tsSessionID - Terminal Services Session ID or -1 if
  131. undefined.
  132. userSID - User SID or "" if undefined.
  133. session - Returned Remote Desktop Session Interface.
  134. Return Value:
  135. S_OK on success. Otherwise, an error code is returned.
  136. --*/
  137. {
  138. DC_BEGIN_FN("CRemoteDesktopServerHost::CreateRemoteDesktopSessionEx");
  139. HRESULT hr = S_OK;
  140. CComObject<CRemoteDesktopSession> *obj = NULL;
  141. PSESSIONMAPENTRY mapEntry;
  142. PSID psid;
  143. TRC_NRM((TB, L"***Ref count is: %ld", m_dwRef));
  144. //
  145. // Get the local system SID.
  146. //
  147. psid = GetLocalSystemSID();
  148. if (psid == NULL) {
  149. hr = HRESULT_FROM_WIN32(GetLastError());
  150. goto CLEANUPANDEXIT;
  151. }
  152. //
  153. // Need to impersonate the caller in order to determine if it is
  154. // running in SYSTEM context.
  155. //
  156. hr = CoImpersonateClient();
  157. if (hr != S_OK) {
  158. TRC_ERR((TB, L"CoImpersonateClient: %08X", hr));
  159. goto CLEANUPANDEXIT;
  160. }
  161. //
  162. // For Whistler, instances of a Remote Desktop Session are only
  163. // "openable" from SYSTEM context, for security reasons.
  164. //
  165. #ifndef DISABLESECURITYCHECKS
  166. if (!IsCallerSystem(psid)) {
  167. TRC_ERR((TB, L"Caller is not SYSTEM."));
  168. ASSERT(FALSE);
  169. CoRevertToSelf();
  170. hr = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  171. goto CLEANUPANDEXIT;
  172. }
  173. #endif
  174. hr = CoRevertToSelf();
  175. if (hr != S_OK) {
  176. TRC_ERR((TB, L"CoRevertToSelf: %08X", hr));
  177. goto CLEANUPANDEXIT;
  178. }
  179. if( sharingClass != DESKTOPSHARING_DEFAULT &&
  180. sharingClass != NO_DESKTOP_SHARING &&
  181. sharingClass != VIEWDESKTOP_PERMISSION_REQUIRE &&
  182. sharingClass != VIEWDESKTOP_PERMISSION_NOT_REQUIRE &&
  183. sharingClass != CONTROLDESKTOP_PERMISSION_REQUIRE &&
  184. sharingClass != CONTROLDESKTOP_PERMISSION_NOT_REQUIRE ) {
  185. // invalid parameter.
  186. hr = E_INVALIDARG;
  187. goto CLEANUPANDEXIT;
  188. }
  189. if( timeout < 0 ) {
  190. hr = E_INVALIDARG;
  191. goto CLEANUPANDEXIT;
  192. }
  193. if( NULL == session ) {
  194. hr = E_POINTER;
  195. goto CLEANUPANDEXIT;
  196. }
  197. //
  198. // Instantiate the desktop server. Currently, we only support
  199. // TSRDP.
  200. //
  201. obj = new CComObject<CTSRDPRemoteDesktopSession>();
  202. if (obj != NULL) {
  203. //
  204. // ATL would normally take care of this for us.
  205. //
  206. obj->InternalFinalConstructAddRef();
  207. hr = obj->FinalConstruct();
  208. obj->InternalFinalConstructRelease();
  209. }
  210. else {
  211. TRC_ERR((TB, L"Can't instantiate CTSRDPRemoteDesktopServer"));
  212. hr = E_OUTOFMEMORY;
  213. goto CLEANUPANDEXIT;
  214. }
  215. //
  216. // Initialize the object.
  217. //
  218. hr = obj->Initialize(
  219. NULL, this, sharingClass, bEnableCallback,
  220. timeout, userHelpCreateBlob, tsSessionID, userSID
  221. );
  222. if (!SUCCEEDED(hr)) {
  223. goto CLEANUPANDEXIT;
  224. }
  225. //
  226. // Add it to the session map.
  227. //
  228. mapEntry = new SESSIONMAPENTRY();
  229. if (mapEntry == NULL) {
  230. goto CLEANUPANDEXIT;
  231. }
  232. mapEntry->obj = obj;
  233. try {
  234. m_SessionMap.insert(
  235. SessionMap::value_type(obj->GetHelpSessionID(), mapEntry)
  236. );
  237. }
  238. catch(CRemoteDesktopException x) {
  239. hr = HRESULT_FROM_WIN32(x.m_ErrorCode);
  240. delete mapEntry;
  241. goto CLEANUPANDEXIT;
  242. }
  243. //
  244. // Get the ISAFRemoteDesktopSession interface pointer.
  245. //
  246. hr = obj->QueryInterface(
  247. IID_ISAFRemoteDesktopSession,
  248. (void**)session
  249. );
  250. if (!SUCCEEDED(hr)) {
  251. TRC_ERR((TB, L"m_RemoteDesktopSession->QueryInterface: %08X", hr));
  252. goto CLEANUPANDEXIT;
  253. }
  254. //
  255. // Add a reference to the object and to ourself so we can both
  256. // stick around, even if the app goes away. The app needs to explicitly
  257. // call CloseRemoteDesktopSession for the object to go away.
  258. //
  259. obj->AddRef();
  260. this->AddRef();
  261. CLEANUPANDEXIT:
  262. //
  263. // Delete the object on error.
  264. //
  265. if (!SUCCEEDED(hr)) {
  266. if (obj != NULL) delete obj;
  267. }
  268. DC_END_FN();
  269. return hr;
  270. }
  271. /*++
  272. Routine Description:
  273. Open an existing RDS session
  274. This call should ALWAYS be made in order to connect to the client
  275. Once this is called and connection is complete, the caller
  276. MUST call DisConnect() to make another connection to the client
  277. Otherwise, the connection does not happen
  278. Arguments:
  279. Return Value:
  280. S_OK on success. Otherwise, an error code is returned.
  281. --*/
  282. STDMETHODIMP
  283. CRemoteDesktopServerHost::OpenRemoteDesktopSession(
  284. BSTR parms,
  285. ISAFRemoteDesktopSession **session
  286. )
  287. {
  288. DC_BEGIN_FN("CRemoteDesktopServerHost::OpenRemoteDesktopSession");
  289. CComObject<CRemoteDesktopSession> *obj = NULL;
  290. CComBSTR hostname;
  291. CComBSTR tmp("");
  292. HRESULT hr = S_OK;
  293. SessionMap::iterator iter;
  294. CComBSTR parmsHelpSessionId;
  295. DWORD protocolType;
  296. PSESSIONMAPENTRY mapEntry;
  297. PSID psid;
  298. //
  299. // Get the local system SID.
  300. //
  301. psid = GetLocalSystemSID();
  302. if (psid == NULL) {
  303. hr = HRESULT_FROM_WIN32(GetLastError());
  304. goto CLEANUPANDEXIT;
  305. }
  306. //
  307. // Need to impersonate the caller in order to determine if it is
  308. // running in SYSTEM context.
  309. //
  310. hr = CoImpersonateClient();
  311. if (hr != S_OK) {
  312. TRC_ERR((TB, L"CoImpersonateClient: %08X", hr));
  313. goto CLEANUPANDEXIT;
  314. }
  315. //
  316. // For Whistler, instances of a Remote Desktop Session are only
  317. // "openable" from SYSTEM context, for security reasons.
  318. //
  319. #ifndef DISABLESECURITYCHECKS
  320. if (!IsCallerSystem(psid)) {
  321. TRC_ERR((TB, L"Caller is not SYSTEM."));
  322. ASSERT(FALSE);
  323. CoRevertToSelf();
  324. hr = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  325. goto CLEANUPANDEXIT;
  326. }
  327. #endif
  328. hr = CoRevertToSelf();
  329. if (hr != S_OK) {
  330. TRC_ERR((TB, L"CoRevertToSelf: %08X", hr));
  331. goto CLEANUPANDEXIT;
  332. }
  333. //
  334. // Parse out the help session ID.
  335. // TODO: Need to modify this so some of the parms are
  336. // optional.
  337. //
  338. DWORD dwVersion;
  339. DWORD result = ParseConnectParmsString(
  340. parms, &dwVersion, &protocolType, hostname, tmp, tmp,
  341. parmsHelpSessionId, tmp, tmp, tmp
  342. );
  343. if (result != ERROR_SUCCESS) {
  344. hr = HRESULT_FROM_WIN32(result);
  345. goto CLEANUPANDEXIT;
  346. }
  347. //
  348. // If we already have the session open then just return a
  349. // reference.
  350. //
  351. iter = m_SessionMap.find(parmsHelpSessionId);
  352. if (iter != m_SessionMap.end()) {
  353. mapEntry = (*iter).second;
  354. hr = mapEntry->obj->QueryInterface(
  355. IID_ISAFRemoteDesktopSession,
  356. (void**)session
  357. );
  358. //
  359. //Start listening if we succeeded
  360. //
  361. if (SUCCEEDED(hr)) {
  362. hr = mapEntry->obj->StartListening();
  363. //
  364. //release the interface pointer if we didn't succeed
  365. //
  366. if (!SUCCEEDED(hr)) {
  367. (*session)->Release();
  368. *session = NULL;
  369. }
  370. }
  371. goto CLEANUPANDEXIT;
  372. }
  373. //
  374. // Instantiate the desktop server. Currently, we only support
  375. // TSRDP.
  376. //
  377. obj = new CComObject<CTSRDPRemoteDesktopSession>();
  378. if (obj != NULL) {
  379. //
  380. // ATL would normally take care of this for us.
  381. //
  382. obj->InternalFinalConstructAddRef();
  383. hr = obj->FinalConstruct();
  384. obj->InternalFinalConstructRelease();
  385. }
  386. else {
  387. TRC_ERR((TB, L"Can't instantiate CTSRDPRemoteDesktopServer"));
  388. hr = E_OUTOFMEMORY;
  389. goto CLEANUPANDEXIT;
  390. }
  391. //
  392. // Initialize the object.
  393. //
  394. // The desktop sharing parameter (NO_DESKTOP_SHARING) is ignored for
  395. // an existing session.
  396. // bEnableCallback and timeout parameter is ignored for existing session
  397. //
  398. hr = obj->Initialize(parms, this, NO_DESKTOP_SHARING, TRUE, 0, CComBSTR(L""), -1, CComBSTR(L""));
  399. if (!SUCCEEDED(hr)) {
  400. goto CLEANUPANDEXIT;
  401. }
  402. hr = obj->StartListening();
  403. if (!SUCCEEDED(hr)) {
  404. goto CLEANUPANDEXIT;
  405. }
  406. hr = obj->UseHostName( hostname );
  407. if( FAILED(hr) ) {
  408. goto CLEANUPANDEXIT;
  409. }
  410. //
  411. // Add it to the session map.
  412. //
  413. mapEntry = new SESSIONMAPENTRY();
  414. if (mapEntry == NULL) {
  415. goto CLEANUPANDEXIT;
  416. }
  417. mapEntry->obj = obj;
  418. try {
  419. m_SessionMap.insert(
  420. SessionMap::value_type(obj->GetHelpSessionID(), mapEntry)
  421. );
  422. }
  423. catch(CRemoteDesktopException x) {
  424. hr = HRESULT_FROM_WIN32(x.m_ErrorCode);
  425. delete mapEntry;
  426. goto CLEANUPANDEXIT;
  427. }
  428. //
  429. // Get the ISAFRemoteDesktopSession interface pointer.
  430. //
  431. hr = obj->QueryInterface(
  432. IID_ISAFRemoteDesktopSession,
  433. (void**)session
  434. );
  435. if (!SUCCEEDED(hr)) {
  436. TRC_ERR((TB, L"m_RemoteDesktopSession->QueryInterface: %08X", hr));
  437. goto CLEANUPANDEXIT;
  438. }
  439. //
  440. // Add a reference to the object and to ourself so we can both
  441. // stick around, even if the app goes away. The app needs to explicitly
  442. // call CloseRemoteDesktopSession for the object to go away.
  443. //
  444. obj->AddRef();
  445. this->AddRef();
  446. CLEANUPANDEXIT:
  447. //
  448. // Delete the object on error.
  449. //
  450. if (!SUCCEEDED(hr)) {
  451. if (obj != NULL) delete obj;
  452. }
  453. DC_END_FN();
  454. return hr;
  455. }
  456. /*++
  457. Routine Description:
  458. Close an existing RDS session
  459. Arguments:
  460. Return Value:
  461. S_OK on success. Otherwise, an error code is returned.
  462. --*/
  463. STDMETHODIMP
  464. CRemoteDesktopServerHost::CloseRemoteDesktopSession(
  465. ISAFRemoteDesktopSession *session
  466. )
  467. {
  468. DC_BEGIN_FN("CRemoteDesktopServerHost::CloseRemoteDesktopSession");
  469. HRESULT hr;
  470. DWORD result;
  471. CComBSTR tmp;
  472. CComBSTR parmsHelpSessionId;
  473. CComBSTR parms;
  474. DWORD protocolType;
  475. SessionMap::iterator iter;
  476. DWORD dwVersion;
  477. //
  478. // Get the connection parameters.
  479. //
  480. hr = session->get_ConnectParms(&parms);
  481. if (!SUCCEEDED(hr)) {
  482. goto CLEANUPANDEXIT;
  483. }
  484. //
  485. // Parse them for the help session ID.
  486. // TODO: I should make some of the args to this function, optional.
  487. //
  488. result = ParseConnectParmsString(
  489. parms, &dwVersion, &protocolType, tmp, tmp, tmp,
  490. parmsHelpSessionId, tmp, tmp, tmp
  491. );
  492. if (result != ERROR_SUCCESS) {
  493. hr = HRESULT_FROM_WIN32(result);
  494. goto CLEANUPANDEXIT;
  495. }
  496. //
  497. // Delete the entry from the session map.
  498. //
  499. iter = m_SessionMap.find(parmsHelpSessionId);
  500. if (iter != m_SessionMap.end()) {
  501. m_SessionMap.erase(iter);
  502. }
  503. else {
  504. ASSERT(FALSE);
  505. }
  506. //
  507. // Remove our reference to the session object. This way it can
  508. // go away when the application releases it.
  509. //
  510. session->Release();
  511. //
  512. // Remove the reference to ourself that we added when we opened
  513. // the session object.
  514. //
  515. this->Release();
  516. //
  517. // Get the session manager interface, if we don't already have one.
  518. //
  519. //
  520. // Open an instance of the Remote Desktop Help Session Manager service.
  521. //
  522. if (m_HelpSessionManager == NULL) {
  523. hr = m_HelpSessionManager.CoCreateInstance(CLSID_RemoteDesktopHelpSessionMgr);
  524. if (!SUCCEEDED(hr)) {
  525. TRC_ERR((TB, TEXT("Can't create help session manager: %08X"), hr));
  526. goto CLEANUPANDEXIT;
  527. }
  528. //
  529. // Set the security level to impersonate. This is required by
  530. // the session manager.
  531. //
  532. hr = CoSetProxyBlanket(
  533. (IUnknown *)m_HelpSessionManager,
  534. RPC_C_AUTHN_DEFAULT,
  535. RPC_C_AUTHZ_DEFAULT,
  536. NULL,
  537. RPC_C_AUTHN_LEVEL_DEFAULT,
  538. RPC_C_IMP_LEVEL_IMPERSONATE,
  539. NULL,
  540. EOAC_NONE
  541. );
  542. if (!SUCCEEDED(hr)) {
  543. TRC_ERR((TB, TEXT("CoSetProxyBlanket: %08X"), hr));
  544. goto CLEANUPANDEXIT;
  545. }
  546. }
  547. //
  548. // Remove the help session with the session manager.
  549. //
  550. hr = m_HelpSessionManager->DeleteHelpSession(parmsHelpSessionId);
  551. if (!SUCCEEDED(hr)) {
  552. TRC_ERR((TB, L"DeleteHelpSession: %08X", hr));
  553. goto CLEANUPANDEXIT;
  554. }
  555. CLEANUPANDEXIT:
  556. DC_END_FN();
  557. return hr;
  558. }
  559. STDMETHODIMP
  560. CRemoteDesktopServerHost::ConnectToExpert(
  561. /*[in]*/ BSTR connectParmToExpert,
  562. /*[in]*/ LONG timeout,
  563. /*[out, retval]*/ LONG* pSafErrCode
  564. )
  565. /*++
  566. Description:
  567. Given connection parameters to expert machine, routine invoke TermSrv winsta API to
  568. initiate connection from TS server to TS client ActiveX control on the expert side.
  569. Parameters:
  570. connectParmToExpert : connection parameter to connect to expert machine.
  571. timeout : Connection timeout, this timeout is per ip address listed in connection parameter
  572. not total connection timeout for the routine.
  573. pSafErrCode : Pointer to LONG to receive detail error code.
  574. Returns:
  575. S_OK or E_FAIL
  576. --*/
  577. {
  578. HRESULT hr = S_OK;
  579. ServerAddress expertAddress;
  580. ServerAddressList expertAddressList;
  581. LONG SafErrCode = SAFERROR_NOERROR;
  582. TDI_ADDRESS_IP expertTDIAddress;
  583. ULONG netaddr;
  584. WSADATA wsaData;
  585. PSID psid;
  586. DC_BEGIN_FN("CRemoteDesktopServerHost::ConnectToExpert");
  587. //
  588. // Get the local system SID.
  589. //
  590. psid = GetLocalSystemSID();
  591. if (psid == NULL) {
  592. hr = HRESULT_FROM_WIN32(GetLastError());
  593. goto CLEANUPANDEXIT;
  594. }
  595. //
  596. // Need to impersonate the caller in order to determine if it is
  597. // running in SYSTEM context.
  598. //
  599. hr = CoImpersonateClient();
  600. if (hr != S_OK) {
  601. TRC_ERR((TB, L"CoImpersonateClient: %08X", hr));
  602. goto CLEANUPANDEXIT;
  603. }
  604. //
  605. // For Whistler, instances of a Remote Desktop Session are only
  606. // "openable" from SYSTEM context, for security reasons.
  607. //
  608. #ifndef DISABLESECURITYCHECKS
  609. if (!IsCallerSystem(psid)) {
  610. TRC_ERR((TB, L"Caller is not SYSTEM."));
  611. ASSERT(FALSE);
  612. CoRevertToSelf();
  613. hr = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  614. goto CLEANUPANDEXIT;
  615. }
  616. #endif
  617. hr = CoRevertToSelf();
  618. if (hr != S_OK) {
  619. TRC_ERR((TB, L"CoRevertToSelf: %08X", hr));
  620. goto CLEANUPANDEXIT;
  621. }
  622. //
  623. // Parse address list in connection parameter.
  624. //
  625. hr = ParseAddressList( connectParmToExpert, expertAddressList );
  626. if( FAILED(hr) ) {
  627. TRC_ERR((TB, TEXT("ParseAddressList: %08X"), hr));
  628. hr = E_INVALIDARG;
  629. SafErrCode = SAFERROR_INVALIDPARAMETERSTRING;
  630. goto CLEANUPANDEXIT;
  631. }
  632. if( 0 == expertAddressList.size() ) {
  633. TRC_ERR((TB, L"Invalid connection address list"));
  634. SafErrCode = SAFERROR_INVALIDPARAMETERSTRING;
  635. hr = E_INVALIDARG;
  636. goto CLEANUPANDEXIT;
  637. }
  638. //
  639. // Loop thru all address in parm and try connection one
  640. // at a time, bail out if system is shutting down or
  641. // some critical error
  642. //
  643. while( expertAddressList.size() > 0 ) {
  644. expertAddress = expertAddressList.front();
  645. expertAddressList.pop_front();
  646. //
  647. // Invalid connect parameters, we must have port number at least.
  648. //
  649. if( 0 == expertAddress.portNumber ||
  650. 0 == lstrlen(expertAddress.ServerName) ) {
  651. TRC_ERR((TB, L"Invalid address/port %s %d", expertAddress.ServerName, expertAddress.portNumber));
  652. SafErrCode = SAFERROR_INVALIDPARAMETERSTRING;
  653. continue;
  654. }
  655. hr = TranslateStringAddress( expertAddress.ServerName, &netaddr );
  656. if( FAILED(hr) ) {
  657. TRC_ERR((TB, L"TranslateStringAddress() on %s failed with 0x%08x", expertAddress.ServerName, hr));
  658. SafErrCode = SAFERROR_INVALIDPARAMETERSTRING;
  659. continue;
  660. }
  661. ZeroMemory(&expertTDIAddress, TDI_ADDRESS_LENGTH_IP);
  662. expertTDIAddress.in_addr = netaddr;
  663. expertTDIAddress.sin_port = htons(expertAddress.portNumber);
  664. if( FALSE == WinStationConnectCallback(
  665. SERVERNAME_CURRENT,
  666. timeout,
  667. TDI_ADDRESS_TYPE_IP,
  668. (PBYTE)&expertTDIAddress,
  669. TDI_ADDRESS_LENGTH_IP
  670. ) ) {
  671. //
  672. // TransferConnectionToIdleWinstation() in TermSrv might just return -1
  673. // few of them we need to bail out.
  674. DWORD dwStatus;
  675. dwStatus = GetLastError();
  676. if( ERROR_SHUTDOWN_IN_PROGRESS == dwStatus ) {
  677. // system or termsrv is shuting down.
  678. hr = HRESULT_FROM_WIN32( ERROR_SHUTDOWN_IN_PROGRESS );
  679. SafErrCode = SAFERROR_SYSTEMSHUTDOWN;
  680. break;
  681. }
  682. else if( ERROR_ACCESS_DENIED == dwStatus ) {
  683. // security check failed
  684. hr = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  685. SafErrCode = SAFERROR_BYSERVER;
  686. ASSERT(FALSE);
  687. break;
  688. }
  689. else if( ERROR_INVALID_PARAMETER == dwStatus ) {
  690. // internal error in rdshost.
  691. hr = HRESULT_FROM_WIN32( ERROR_INTERNAL_ERROR );
  692. SafErrCode = SAFERROR_INTERNALERROR;
  693. ASSERT(FALSE);
  694. break;
  695. }
  696. SafErrCode = SAFERROR_WINSOCK_FAILED;
  697. }
  698. else {
  699. //
  700. // successful connection
  701. //
  702. SafErrCode = SAFERROR_NOERROR;
  703. break;
  704. }
  705. //
  706. // Try next connection.
  707. //
  708. }
  709. CLEANUPANDEXIT:
  710. *pSafErrCode = SafErrCode;
  711. DC_END_FN();
  712. return hr;
  713. }
  714. HRESULT
  715. CRemoteDesktopServerHost::TranslateStringAddress(
  716. IN LPTSTR pszAddress,
  717. OUT ULONG* pNetAddr
  718. )
  719. /*++
  720. Routine Description:
  721. Translate IP Address or machine name to network address.
  722. Parameters:
  723. pszAddress : Pointer to IP address or machine name.
  724. pNetAddr : Point to ULONG to receive address in IPV4.
  725. Returns:
  726. S_OK or error code
  727. --*/
  728. {
  729. HRESULT hr = S_OK;
  730. unsigned long addr;
  731. LPSTR pszAnsiAddress = NULL;
  732. DWORD dwAddressBufSize;
  733. DWORD dwStatus;
  734. DC_BEGIN_FN("CRemoteDesktopServerHost::TranslateStringAddress");
  735. dwAddressBufSize = lstrlen(pszAddress) + 1;
  736. pszAnsiAddress = (LPSTR)LocalAlloc(LPTR, dwAddressBufSize); // converting from WCHAR to CHAR.
  737. if( NULL == pszAnsiAddress ) {
  738. hr = E_OUTOFMEMORY;
  739. goto CLEANUPANDEXIT;
  740. }
  741. //
  742. // Convert wide char to ANSI string
  743. //
  744. dwStatus = WideCharToMultiByte(
  745. GetACP(),
  746. 0,
  747. pszAddress,
  748. -1,
  749. pszAnsiAddress,
  750. dwAddressBufSize,
  751. NULL,
  752. NULL
  753. );
  754. if( 0 == dwStatus ) {
  755. dwStatus = GetLastError();
  756. hr = HRESULT_FROM_WIN32(dwStatus);
  757. TRC_ERR((TB, L"WideCharToMultiByte() failed with %d", dwStatus));
  758. goto CLEANUPANDEXIT;
  759. }
  760. addr = inet_addr( pszAnsiAddress );
  761. if( INADDR_NONE == addr ) {
  762. struct hostent* pHostEnt = NULL;
  763. pHostEnt = gethostbyname( pszAnsiAddress );
  764. if( NULL != pHostEnt ) {
  765. addr = ((struct sockaddr_in *)(pHostEnt->h_addr))->sin_addr.S_un.S_addr;
  766. }
  767. }
  768. if( INADDR_NONE == addr ) {
  769. dwStatus = GetLastError();
  770. hr = HRESULT_FROM_WIN32(dwStatus);
  771. TRC_ERR((TB, L"Can't translate address %w", pszAddress));
  772. goto CLEANUPANDEXIT;
  773. }
  774. *pNetAddr = addr;
  775. CLEANUPANDEXIT:
  776. if( NULL != pszAnsiAddress ) {
  777. LocalFree(pszAnsiAddress);
  778. }
  779. DC_END_FN();
  780. return hr;
  781. }