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.

3175 lines
75 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. HelpMgr.cpp
  5. Abstract:
  6. HelpMgr.cpp : Implementation of CRemoteDesktopHelpSessionMgr
  7. Author:
  8. HueiWang 2/17/2000
  9. --*/
  10. #include "stdafx.h"
  11. #include "global.h"
  12. #include "policy.h"
  13. #include "RemoteDesktopUtils.h"
  14. //
  15. // CRemoteDesktopHelpSessionMgr Static member variable
  16. //
  17. #define DEFAULT_UNSOLICATED_HELP_TIMEOUT IDLE_SHUTDOWN_PERIOD
  18. CCriticalSection CRemoteDesktopHelpSessionMgr::gm_AccRefCountCS;
  19. // Help Session ID to help session instance cache map
  20. IDToSessionMap CRemoteDesktopHelpSessionMgr::gm_HelpIdToHelpSession;
  21. // Pointer to GIT
  22. LPGLOBALINTERFACETABLE g_GIT = NULL;
  23. DWORD g_ResolverCookie = 0;
  24. CCriticalSection g_GITLock;
  25. //
  26. // Expert logoff monitor list, this is used for cleanup at
  27. // the shutdown time so we don't have any opened handle.
  28. //
  29. EXPERTLOGOFFMONITORLIST g_ExpertLogoffMonitorList;
  30. VOID CALLBACK
  31. ExpertLogoffCallback(
  32. PVOID pContext,
  33. BOOLEAN bTimerOrWaitFired
  34. )
  35. /*++
  36. Routine Description:
  37. This routine is invoked by thread pool when handle to rdsaddin is signal.
  38. Parameters:
  39. pContext : Pointer to user data.
  40. bTimerOrWaitFired : TRUE if wait timeout, FALSE otherwise.
  41. Return:
  42. None.
  43. Note :
  44. Refer to MSDN RegisterWaitForSingleObject() for function parameters.
  45. --*/
  46. {
  47. PEXPERTLOGOFFSTRUCT pExpertLogoffStruct = (PEXPERTLOGOFFSTRUCT)pContext;
  48. BSTR bstrHelpedTicketId = NULL;
  49. WINSTATIONINFORMATION ExpertWinStation;
  50. DWORD ReturnLength;
  51. DWORD dwStatus;
  52. BOOL bSuccess;
  53. MYASSERT( FALSE == bTimerOrWaitFired );
  54. MYASSERT( NULL != pContext );
  55. DebugPrintf(
  56. _TEXT("ExpertLogoffCallback()...\n")
  57. );
  58. // Our wait is forever so can't be timeout.
  59. if( FALSE == bTimerOrWaitFired )
  60. {
  61. if( NULL != pExpertLogoffStruct )
  62. {
  63. DebugPrintf(
  64. _TEXT("Expert %d has logoff\n"),
  65. pExpertLogoffStruct->ExpertSessionId
  66. );
  67. MYASSERT( NULL != pExpertLogoffStruct->hWaitObject );
  68. MYASSERT( NULL != pExpertLogoffStruct->hWaitProcess );
  69. MYASSERT( pExpertLogoffStruct->bstrHelpedTicketId.Length() > 0 );
  70. MYASSERT( pExpertLogoffStruct->bstrWinStationName.Length() > 0 );
  71. if( pExpertLogoffStruct->bstrWinStationName.Length() > 0 )
  72. {
  73. //
  74. // Reset the winstation asap since rdsaddin might get kill
  75. // and termsrv stuck on waiting for winlogon to exit and
  76. // shadow won't terminate until termsrv reset the winstation
  77. //
  78. ZeroMemory( &ExpertWinStation, sizeof(ExpertWinStation) );
  79. bSuccess = WinStationQueryInformation(
  80. SERVERNAME_CURRENT,
  81. pExpertLogoffStruct->ExpertSessionId,
  82. WinStationInformation,
  83. (PVOID)&ExpertWinStation,
  84. sizeof(WINSTATIONINFORMATION),
  85. &ReturnLength
  86. );
  87. if( TRUE == bSuccess || ERROR_CTX_CLOSE_PENDING == GetLastError() )
  88. {
  89. //
  90. // Cases:
  91. // 1) Termsrv mark Helper session as close pending and
  92. // function will return FALSE.
  93. // 2) If somehow, session ID is re-use, session name
  94. // will change then we compare cached name.
  95. // Both cases, we will force a reset, however, only hope
  96. // shadow ended and if mobsync still up, session will
  97. // take a long time to terminate.
  98. //
  99. if( FALSE == bSuccess || pExpertLogoffStruct->bstrWinStationName == CComBSTR(ExpertWinStation.WinStationName) )
  100. {
  101. DebugPrintf(
  102. _TEXT("Resetting winstation name %s, id %d\n"),
  103. pExpertLogoffStruct->bstrWinStationName,
  104. pExpertLogoffStruct->ExpertSessionId
  105. );
  106. // don't wait for it to return, can't do much if this fail
  107. WinStationReset(
  108. SERVERNAME_CURRENT,
  109. pExpertLogoffStruct->ExpertSessionId,
  110. FALSE
  111. );
  112. DebugPrintf(
  113. _TEXT("WinStationReset return %d\n"),
  114. GetLastError()
  115. );
  116. }
  117. }
  118. else
  119. {
  120. DebugPrintf(
  121. _TEXT("Expert logoff failed to get winstation name %d\n"),
  122. GetLastError()
  123. );
  124. }
  125. }
  126. if( pExpertLogoffStruct->bstrHelpedTicketId.Length() > 0 )
  127. {
  128. //
  129. // detach pointer from CComBSTR, we will free it after handling
  130. // WM_HELPERRDSADDINEXIT, purpose of this is not to duplicate
  131. // string again.
  132. //
  133. bstrHelpedTicketId = pExpertLogoffStruct->bstrHelpedTicketId.Detach();
  134. DebugPrintf(
  135. _TEXT("Posting WM_HELPERRDSADDINEXIT...\n")
  136. );
  137. PostThreadMessage(
  138. _Module.dwThreadID,
  139. WM_HELPERRDSADDINEXIT,
  140. pExpertLogoffStruct->ExpertSessionId,
  141. (LPARAM) bstrHelpedTicketId
  142. );
  143. }
  144. //
  145. // Remove from monitor list.
  146. //
  147. {
  148. EXPERTLOGOFFMONITORLIST::LOCK_ITERATOR it = g_ExpertLogoffMonitorList.find(pExpertLogoffStruct);
  149. if( it != g_ExpertLogoffMonitorList.end() )
  150. {
  151. g_ExpertLogoffMonitorList.erase(it);
  152. }
  153. else
  154. {
  155. MYASSERT(FALSE);
  156. }
  157. }
  158. // Destructor will take care of closing handle
  159. delete pExpertLogoffStruct;
  160. }
  161. }
  162. return;
  163. }
  164. /////////////////////////////////////////////////////////////////////////////
  165. DWORD
  166. MonitorExpertLogoff(
  167. IN LONG pidToWaitFor,
  168. IN LONG expertSessionId,
  169. IN BSTR bstrHelpedTicketId
  170. )
  171. /*++
  172. Routine Description:
  173. Monitor expert logoff, specifically, we wait on rdsaddin process handle, once
  174. signal, we immediately notify resolver that expert has logoff.
  175. Parameters:
  176. pidToWaitFor : RDSADDIN PID
  177. expertSessionId : TS session ID that rdsaddin is running.
  178. bstrHelpedTickerId : Help ticket ID that expert is helping.
  179. Returns:
  180. ERROR_SUCCESS or error code.
  181. --*/
  182. {
  183. HANDLE hRdsaddin = NULL;
  184. DWORD dwStatus = ERROR_SUCCESS;
  185. BOOL bSuccess;
  186. PEXPERTLOGOFFSTRUCT pExpertLogoffStruct = NULL;
  187. WINSTATIONINFORMATION ExpertWinStation;
  188. DWORD ReturnLength;
  189. DebugPrintf(
  190. _TEXT("CServiceModule::RegisterWaitForExpertLogoff...\n")
  191. );
  192. pExpertLogoffStruct = new EXPERTLOGOFFSTRUCT;
  193. if( NULL == pExpertLogoffStruct )
  194. {
  195. dwStatus = GetLastError();
  196. goto CLEANUPANDEXIT;
  197. }
  198. ZeroMemory( &ExpertWinStation, sizeof(ExpertWinStation) );
  199. bSuccess = WinStationQueryInformation(
  200. SERVERNAME_CURRENT,
  201. expertSessionId,
  202. WinStationInformation,
  203. (PVOID)&ExpertWinStation,
  204. sizeof(WINSTATIONINFORMATION),
  205. &ReturnLength
  206. );
  207. if( FALSE == bSuccess )
  208. {
  209. //
  210. // what do we do, we still need to inform resolver of disconnect,
  211. // but we will not be able to reset winstation
  212. //
  213. dwStatus = GetLastError();
  214. DebugPrintf(
  215. _TEXT("WinStationQueryInformation() failed with %d...\n"),
  216. dwStatus
  217. );
  218. MYASSERT(FALSE);
  219. }
  220. else
  221. {
  222. pExpertLogoffStruct->bstrWinStationName = ExpertWinStation.WinStationName;
  223. DebugPrintf(
  224. _TEXT("Helper winstation name %s...\n"),
  225. pExpertLogoffStruct->bstrWinStationName
  226. );
  227. }
  228. //
  229. // Open rdsaddin.exe, if failed, bail out and don't continue
  230. // help.
  231. //
  232. pExpertLogoffStruct->hWaitProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pidToWaitFor );
  233. if( NULL == pExpertLogoffStruct->hWaitProcess )
  234. {
  235. dwStatus = GetLastError();
  236. DebugPrintf(
  237. _TEXT( "OpenProcess() on rdsaddin %d failed with %d\n"),
  238. pidToWaitFor,
  239. dwStatus
  240. );
  241. goto CLEANUPANDEXIT;
  242. }
  243. pExpertLogoffStruct->ExpertSessionId = expertSessionId;
  244. pExpertLogoffStruct->bstrHelpedTicketId = bstrHelpedTicketId;
  245. //
  246. // Register wait on rdsaddin process handle.
  247. //
  248. bSuccess = RegisterWaitForSingleObject(
  249. &(pExpertLogoffStruct->hWaitObject),
  250. pExpertLogoffStruct->hWaitProcess,
  251. (WAITORTIMERCALLBACK) ExpertLogoffCallback,
  252. pExpertLogoffStruct,
  253. INFINITE,
  254. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE
  255. );
  256. if( FALSE == bSuccess )
  257. {
  258. dwStatus = GetLastError();
  259. DebugPrintf(
  260. _TEXT("RegisterWaitForSingleObject() failed with %d\n"),
  261. dwStatus
  262. );
  263. }
  264. else
  265. {
  266. // store this into monitor list
  267. try {
  268. g_ExpertLogoffMonitorList[pExpertLogoffStruct] = pExpertLogoffStruct;
  269. }
  270. catch(...) {
  271. // Memory allocation failed
  272. dwStatus = GetLastError();
  273. }
  274. }
  275. CLEANUPANDEXIT:
  276. if( ERROR_SUCCESS != dwStatus )
  277. {
  278. if( NULL != pExpertLogoffStruct )
  279. {
  280. // destructor will take care of closing handle
  281. delete pExpertLogoffStruct;
  282. }
  283. }
  284. DebugPrintf(
  285. _TEXT( "MonitorExpertLogoff() return %d\n"),
  286. dwStatus
  287. );
  288. return dwStatus;
  289. }
  290. VOID
  291. CleanupMonitorExpertList()
  292. /*++
  293. Routine Description:
  294. Routine to clean up all remaining expert logoff monitor list, this
  295. should be done right before we shutdown so we don't have any handle
  296. leak.
  297. Parameters:
  298. None.
  299. Returns:
  300. None.
  301. --*/
  302. {
  303. EXPERTLOGOFFMONITORLIST::LOCK_ITERATOR it =
  304. g_ExpertLogoffMonitorList.begin();
  305. DebugPrintf(
  306. _TEXT("CleanupMonitorExpertList() has %d left\n"),
  307. g_ExpertLogoffMonitorList.size()
  308. );
  309. for(; it != g_ExpertLogoffMonitorList.end(); it++ )
  310. {
  311. if( NULL != (*it).second )
  312. {
  313. // destructor will take care of closing handle
  314. delete (*it).second;
  315. (*it).second = NULL;
  316. }
  317. }
  318. g_ExpertLogoffMonitorList.erase_all();
  319. return;
  320. }
  321. HRESULT
  322. InitializeGlobalInterfaceTable()
  323. /*++
  324. Routine Description:
  325. Initialize GIT interface.
  326. Parameters:
  327. None.
  328. Returns.
  329. --*/
  330. {
  331. CCriticalSectionLocker l(g_GITLock);
  332. HRESULT hRes = S_OK;
  333. if( NULL == g_GIT )
  334. {
  335. //
  336. // Create global interface table
  337. //
  338. hRes = CoCreateInstance(
  339. CLSID_StdGlobalInterfaceTable,
  340. NULL,
  341. CLSCTX_INPROC_SERVER,
  342. IID_IGlobalInterfaceTable,
  343. (LPVOID*)&g_GIT
  344. );
  345. }
  346. return hRes;
  347. }
  348. HRESULT
  349. UnInitializeGlobalInterfaceTable()
  350. /*++
  351. Routine Description:
  352. Initialize GIT interface.
  353. Parameters:
  354. None.
  355. Returns.
  356. --*/
  357. {
  358. CCriticalSectionLocker l(g_GITLock);
  359. if( NULL != g_GIT )
  360. {
  361. g_GIT->Release();
  362. g_GIT = NULL;
  363. }
  364. return S_OK;
  365. }
  366. HRESULT
  367. RegisterResolverWithGIT(
  368. ISAFRemoteDesktopCallback* pResolver
  369. )
  370. /*++
  371. Routine Description:
  372. Register Resolver interface with GIT.
  373. Parameter:
  374. pResolver : Pointer to resolver.
  375. Returns:
  376. --*/
  377. {
  378. HRESULT hRes;
  379. CCriticalSectionLocker l(g_GITLock);
  380. MYASSERT(NULL != g_GIT);
  381. //
  382. // register resolver interface with GIT, resolver has some
  383. // data structure that depends on single instance.
  384. //
  385. IUnknown* pResolveIUnknown = NULL;
  386. hRes = pResolver->QueryInterface(
  387. IID_IUnknown,
  388. (void **)&pResolveIUnknown
  389. );
  390. if( SUCCEEDED(hRes) )
  391. {
  392. hRes = g_GIT->RegisterInterfaceInGlobal(
  393. pResolveIUnknown,
  394. IID_ISAFRemoteDesktopCallback,
  395. &g_ResolverCookie
  396. );
  397. pResolveIUnknown->Release();
  398. }
  399. return hRes;
  400. }
  401. HRESULT
  402. LoadResolverFromGIT(
  403. OUT ISAFRemoteDesktopCallback** ppResolver
  404. )
  405. /*++
  406. Routine Description:
  407. Load resolver interface from Global Interface Table, Resolver has data that depends
  408. on single instance.
  409. Parameters:
  410. ppResolver : Pointer to ISAFRemoteDesktopCallback* to receive Resolver pointer
  411. Returns:
  412. S_OK or error code.
  413. --*/
  414. {
  415. HRESULT hr;
  416. CCriticalSectionLocker l(g_GITLock);
  417. if( g_GIT != NULL )
  418. {
  419. hr = g_GIT->GetInterfaceFromGlobal(
  420. g_ResolverCookie,
  421. IID_ISAFRemoteDesktopCallback,
  422. (LPVOID *)ppResolver
  423. );
  424. }
  425. else
  426. {
  427. hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  428. MYASSERT(FALSE);
  429. }
  430. return hr;
  431. }
  432. //-----------------------------------------------------------
  433. HRESULT
  434. ImpersonateClient()
  435. /*
  436. Routine Description:
  437. Impersonate client
  438. Parameter:
  439. None.
  440. Returns:
  441. S_OK or return code from CoImpersonateClient
  442. --*/
  443. {
  444. HRESULT hRes;
  445. #if __WIN9XBUILD__
  446. // CoImpersonateClient() on Win9x is not supported.
  447. hRes = S_OK;
  448. #else
  449. hRes = CoImpersonateClient();
  450. #endif
  451. return hRes;
  452. }
  453. //-----------------------------------------------------------
  454. void
  455. EndImpersonateClient()
  456. /*
  457. Routine Description:
  458. End impersonating client
  459. Parameter:
  460. None.
  461. Returns:
  462. S_OK or return code from CoRevertToSelf
  463. --*/
  464. {
  465. #if __WIN9XBUILD__
  466. #else
  467. HRESULT hRes;
  468. hRes = CoRevertToSelf();
  469. MYASSERT( SUCCEEDED(hRes) );
  470. #endif
  471. return;
  472. }
  473. HRESULT
  474. CRemoteDesktopHelpSessionMgr::AddHelpSessionToCache(
  475. IN BSTR bstrHelpId,
  476. IN CComObject<CRemoteDesktopHelpSession>* pIHelpSession
  477. )
  478. /*++
  479. Routine Description:
  480. Add help session object to global cache.
  481. Parameters:
  482. bstrHelpId : Help Session ID.
  483. pIHelpSession : Pointer to help session object.
  484. Returns:
  485. S_OK.
  486. E_UNEXPECTED
  487. HRESULT_FROM_WIN32( ERROR_FILE_EXITS )
  488. --*/
  489. {
  490. HRESULT hRes = S_OK;
  491. IDToSessionMap::LOCK_ITERATOR it = gm_HelpIdToHelpSession.find( bstrHelpId );
  492. if( it == gm_HelpIdToHelpSession.end() )
  493. {
  494. try {
  495. DebugPrintf(
  496. _TEXT("Adding Help Session %s to cache\n"),
  497. bstrHelpId
  498. );
  499. gm_HelpIdToHelpSession[ bstrHelpId ] = pIHelpSession;
  500. }
  501. catch(...) {
  502. hRes = E_UNEXPECTED;
  503. MYASSERT( SUCCEEDED(hRes) );
  504. throw;
  505. }
  506. }
  507. else
  508. {
  509. hRes = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS );
  510. }
  511. return hRes;
  512. }
  513. HRESULT
  514. CRemoteDesktopHelpSessionMgr::ExpireUserHelpSessionCallback(
  515. IN CComBSTR& bstrHelpId,
  516. IN HANDLE userData
  517. )
  518. /*++
  519. Routine Description:
  520. Expire help session call back routine, refer to EnumHelpEntry()
  521. Parameters:
  522. bstrHelpId : ID of help session.
  523. userData : Handle to user data.
  524. Returns:
  525. S_OK.
  526. --*/
  527. {
  528. HRESULT hRes = S_OK;
  529. DebugPrintf(
  530. _TEXT("ExpireUserHelpSessionCallback() on %s...\n"),
  531. (LPCTSTR)bstrHelpId
  532. );
  533. // Load Help Entry.
  534. RemoteDesktopHelpSessionObj* pObj = LoadHelpSessionObj( NULL, bstrHelpId );
  535. if( NULL != pObj )
  536. {
  537. //
  538. // LoadHelpSessionObj() will release expired help session.
  539. //
  540. pObj->Release();
  541. }
  542. return hRes;
  543. }
  544. HRESULT
  545. CRemoteDesktopHelpSessionMgr::LogoffUserHelpSessionCallback(
  546. IN CComBSTR& bstrHelpId,
  547. IN HANDLE userData
  548. )
  549. /*++
  550. Routine Description:
  551. Expire help session call back routine, refer to EnumHelpEntry()
  552. Parameters:
  553. bstrHelpId : ID of help session.
  554. userData : Handle to user data.
  555. Returns:
  556. S_OK.
  557. --*/
  558. {
  559. HRESULT hRes = S_OK;
  560. DWORD dwLogoffSessionId = PtrToUlong(userData);
  561. long lHelpSessionUserSessionId;
  562. DebugPrintf(
  563. _TEXT("LogoffUserHelpSessionCallback() on %s %d...\n"),
  564. bstrHelpId,
  565. dwLogoffSessionId
  566. );
  567. // Load Help Entry.
  568. RemoteDesktopHelpSessionObj* pObj = LoadHelpSessionObj( NULL, bstrHelpId );
  569. if( NULL != pObj )
  570. {
  571. //
  572. // LoadHelpSessionObj() will release expired help session.
  573. //
  574. hRes = pObj->get_UserLogonId( &lHelpSessionUserSessionId );
  575. if( SUCCEEDED(hRes) && (DWORD)lHelpSessionUserSessionId == dwLogoffSessionId )
  576. {
  577. DebugPrintf(
  578. _TEXT("User Session has log off...\n")
  579. );
  580. // rely on helpassistant session logoff to notify
  581. // resolver.
  582. hRes = pObj->put_UserLogonId(UNKNOWN_LOGONID);
  583. }
  584. else if( pObj->GetHelperSessionId() == dwLogoffSessionId )
  585. {
  586. DebugPrintf(
  587. _TEXT("Helper has log off...\n")
  588. );
  589. // Helper has logoff, invoke disconnect to clean up
  590. // resolver state.
  591. hRes = pObj->NotifyDisconnect();
  592. }
  593. DebugPrintf(
  594. _TEXT("hRes = 0x%08x, lHelpSessionUserSessionId=%d\n"),
  595. hRes,
  596. lHelpSessionUserSessionId
  597. );
  598. pObj->Release();
  599. }
  600. // Always return success to continue on next help session
  601. return S_OK;
  602. }
  603. HRESULT
  604. CRemoteDesktopHelpSessionMgr::NotifyPendingHelpServiceStartCallback(
  605. IN CComBSTR& bstrHelpId,
  606. IN HANDLE userData
  607. )
  608. /*++
  609. Routine Description:
  610. Call back for NotifyPendingHelpServiceStartup, refer to EnumHelpEntry()
  611. Parameters:
  612. bstrHelpId : ID of help session.
  613. userData : Handle to user data.
  614. Returns:
  615. S_OK.
  616. -*/
  617. {
  618. HRESULT hRes = S_OK;
  619. // DeleteHelp() will try to close the port and since we just startup,
  620. // port is either invalid or not open, so we need manually delete
  621. // expired help
  622. RemoteDesktopHelpSessionObj* pObj = LoadHelpSessionObj( NULL, bstrHelpId, TRUE );
  623. if( NULL != pObj )
  624. {
  625. if( TRUE == pObj->IsHelpSessionExpired() )
  626. {
  627. pObj->put_ICSPort( 0 );
  628. pObj->DeleteHelp();
  629. ReleaseAssistantAccount();
  630. }
  631. else
  632. {
  633. DWORD dwICSPort;
  634. //
  635. // re-open the port so connection can come in
  636. //
  637. dwICSPort = OpenPort( TERMSRV_TCPPORT );
  638. //dwICSPort = OpenPort( htons(TERMSRV_TCPPORT) );
  639. pObj->put_ICSPort( dwICSPort );
  640. // We don't close the port until we are deleted.
  641. }
  642. pObj->Release();
  643. }
  644. return hRes;
  645. }
  646. void
  647. CRemoteDesktopHelpSessionMgr::NotifyPendingHelpServiceStartup()
  648. /*++
  649. Description:
  650. Go thru all pending help and notify pending help about
  651. service startup.
  652. Parameters:
  653. None.
  654. Returns:
  655. None
  656. --*/
  657. {
  658. try {
  659. g_HelpSessTable.EnumHelpEntry(
  660. NotifyPendingHelpServiceStartCallback,
  661. NULL
  662. );
  663. }
  664. catch(...) {
  665. MYASSERT(FALSE);
  666. throw;
  667. }
  668. return;
  669. }
  670. void
  671. CRemoteDesktopHelpSessionMgr::TimeoutHelpSesion()
  672. /*++
  673. Routine Description:
  674. Expire help session that has exceed its valid period.
  675. Parameters:
  676. None.
  677. Returns:
  678. None.
  679. --*/
  680. {
  681. DebugPrintf(
  682. _TEXT("TimeoutHelpSesion()...\n")
  683. );
  684. try {
  685. g_HelpSessTable.EnumHelpEntry(
  686. ExpireUserHelpSessionCallback,
  687. (HANDLE)NULL
  688. );
  689. }
  690. catch(...) {
  691. MYASSERT(FALSE);
  692. throw;
  693. }
  694. return;
  695. }
  696. void
  697. CRemoteDesktopHelpSessionMgr::NotifyHelpSesionLogoff(
  698. DWORD dwLogonId
  699. )
  700. /*++
  701. Routine Description:
  702. Parameters:
  703. Returns:
  704. --*/
  705. {
  706. DebugPrintf(
  707. _TEXT("NotifyHelpSesionLogoff() %d...\n"),
  708. dwLogonId
  709. );
  710. try {
  711. g_HelpSessTable.EnumHelpEntry(
  712. LogoffUserHelpSessionCallback,
  713. UlongToPtr(dwLogonId)
  714. );
  715. }
  716. catch(...) {
  717. MYASSERT(FALSE);
  718. throw;
  719. }
  720. return;
  721. }
  722. HRESULT
  723. CRemoteDesktopHelpSessionMgr::DeleteHelpSessionFromCache(
  724. IN BSTR bstrHelpId
  725. )
  726. /*++
  727. Routine Descritpion:
  728. Delete help session from global cache.
  729. Parameters:
  730. bstrHelpId : Help session ID to be deleted.
  731. Returns:
  732. S_OK.
  733. HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND )
  734. --*/
  735. {
  736. HRESULT hRes = S_OK;
  737. DebugPrintf(
  738. _TEXT("DeleteHelpSessionFromCache() - %s\n"),
  739. bstrHelpId
  740. );
  741. IDToSessionMap::LOCK_ITERATOR it = gm_HelpIdToHelpSession.find( bstrHelpId );
  742. if( it != gm_HelpIdToHelpSession.end() )
  743. {
  744. gm_HelpIdToHelpSession.erase( it );
  745. }
  746. else
  747. {
  748. hRes = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  749. }
  750. return hRes;
  751. }
  752. RemoteDesktopHelpSessionObj*
  753. CRemoteDesktopHelpSessionMgr::LoadHelpSessionObj(
  754. IN CRemoteDesktopHelpSessionMgr* pMgr,
  755. IN BSTR bstrHelpSession,
  756. IN BOOL bLoadExpiredHelp /* = FALSE */
  757. )
  758. /*++
  759. Routine Description:
  760. Find a pending help entry, routine will load from DB if not
  761. yet loaded.
  762. Parameters:
  763. pMgr : Pointer to CRemoteDesktopHelpSessionMgr object that wants to
  764. load this help session.
  765. bstrHelpSession : Help entry ID interested.
  766. Returns:
  767. --*/
  768. {
  769. HRESULT hRes = S_OK;
  770. PHELPENTRY pHelp = NULL;
  771. RemoteDesktopHelpSessionObj* pHelpSessionObj = NULL;
  772. IDToSessionMap::LOCK_ITERATOR it = gm_HelpIdToHelpSession.find( bstrHelpSession );
  773. if( it != gm_HelpIdToHelpSession.end() )
  774. {
  775. DebugPrintf(
  776. _TEXT("LoadHelpSessionObj() %s is in cache ...\n"),
  777. bstrHelpSession
  778. );
  779. pHelpSessionObj = (*it).second;
  780. // One more reference to this object.
  781. pHelpSessionObj->AddRef();
  782. }
  783. else
  784. {
  785. DebugPrintf(
  786. _TEXT("Loading Help Session %s\n"),
  787. bstrHelpSession
  788. );
  789. // load from table
  790. hRes = g_HelpSessTable.OpenHelpEntry(
  791. bstrHelpSession,
  792. &pHelp
  793. );
  794. if( SUCCEEDED(hRes) )
  795. {
  796. //
  797. // Object return from CreateInstance() has ref. count of 1
  798. //
  799. hRes = CRemoteDesktopHelpSession::CreateInstance(
  800. pMgr,
  801. (pMgr) ? pMgr->m_bstrUserSid : NULL,
  802. pHelp,
  803. &pHelpSessionObj
  804. );
  805. if( SUCCEEDED(hRes) )
  806. {
  807. if( NULL != pHelpSessionObj )
  808. {
  809. hRes = AddHelpSessionToCache(
  810. bstrHelpSession,
  811. pHelpSessionObj
  812. );
  813. if( SUCCEEDED(hRes) )
  814. {
  815. //m_HelpListByLocal.push_back( bstrHelpSession );
  816. it = gm_HelpIdToHelpSession.find( bstrHelpSession );
  817. MYASSERT( it != gm_HelpIdToHelpSession.end() );
  818. if( it == gm_HelpIdToHelpSession.end() )
  819. {
  820. hRes = E_UNEXPECTED;
  821. MYASSERT( FALSE );
  822. }
  823. }
  824. if( FAILED(hRes) )
  825. {
  826. // we have big problem here...
  827. pHelpSessionObj->Release();
  828. pHelpSessionObj = NULL;
  829. }
  830. else
  831. {
  832. // ignore error here, it is possible that owner account
  833. // got deleted even session is still active, we will let
  834. // resolver to fail.
  835. pHelpSessionObj->ResolveTicketOwner();
  836. }
  837. }
  838. else
  839. {
  840. MYASSERT(FALSE);
  841. hRes = E_UNEXPECTED;
  842. }
  843. }
  844. if( FAILED(hRes) )
  845. {
  846. MYASSERT( FALSE );
  847. pHelp->Close();
  848. }
  849. }
  850. }
  851. //
  852. // If automatically delete expired help, check and delete expired help
  853. //
  854. if( FALSE == bLoadExpiredHelp && pHelpSessionObj &&
  855. TRUE == pHelpSessionObj->IsHelpSessionExpired() )
  856. {
  857. // If session is in help or pending user response,
  858. // don't expire it, let next load to delete it.
  859. if( UNKNOWN_LOGONID == pHelpSessionObj->GetHelperSessionId() )
  860. {
  861. // Delete it from data base and in memory cache
  862. pHelpSessionObj->DeleteHelp();
  863. ReleaseAssistantAccount();
  864. pHelpSessionObj->Release();
  865. pHelpSessionObj = NULL;
  866. }
  867. }
  868. return pHelpSessionObj;
  869. }
  870. /////////////////////////////////////////////////////////////////////////////
  871. //
  872. // CRemoteDesktopHelpSessionMgr
  873. //
  874. STDMETHODIMP
  875. CRemoteDesktopHelpSessionMgr::DeleteHelpSession(
  876. IN BSTR HelpSessionID
  877. )
  878. /*++
  879. Routine Description:
  880. Delete a user created Help Session from our cached list.
  881. Parameter:
  882. HelpSessionID : Help Session ID returned from CreateHelpSession() or
  883. CreateHelpSessionEx().
  884. Returns:
  885. S_OK Success.
  886. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) Help ID not found.
  887. HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) Help does not belong to user
  888. --*/
  889. {
  890. HRESULT hRes = S_OK;
  891. BOOL bInCache;
  892. if( FALSE == _Module.IsSuccessServiceStartup() )
  893. {
  894. // service startup problem, return error code.
  895. hRes = _Module.GetServiceStartupStatus();
  896. DebugPrintf(
  897. _TEXT("Service startup failed with 0x%x\n"),
  898. hRes
  899. );
  900. return hRes;
  901. }
  902. if( NULL == HelpSessionID )
  903. {
  904. hRes = E_POINTER;
  905. MYASSERT(FALSE);
  906. return hRes;
  907. }
  908. DebugPrintf(
  909. _TEXT("Delete Help Session %s\n"),
  910. HelpSessionID
  911. );
  912. hRes = LoadUserSid();
  913. MYASSERT( SUCCEEDED(hRes) );
  914. RemoteDesktopHelpSessionObj* pHelpObj;
  915. pHelpObj = LoadHelpSessionObj( this, HelpSessionID );
  916. if( NULL != pHelpObj )
  917. {
  918. // Only original creator can delete his/her help session
  919. //if( TRUE == pHelpObj->IsEqualSid(m_bstrUserSid) )
  920. //{
  921. // DeleteHelp will also delete entry in global cache.
  922. pHelpObj->DeleteHelp();
  923. ReleaseAssistantAccount();
  924. //}
  925. //else
  926. //{
  927. // hRes = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  928. //}
  929. // LoadHelpSessionObj() always AddRef().
  930. pHelpObj->Release();
  931. }
  932. else
  933. {
  934. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  935. }
  936. return hRes;
  937. }
  938. STDMETHODIMP
  939. CRemoteDesktopHelpSessionMgr::CreateHelpSession(
  940. IN BSTR bstrSessName,
  941. IN BSTR bstrSessPwd,
  942. IN BSTR bstrSessDesc,
  943. IN BSTR bstrSessBlob,
  944. OUT IRemoteDesktopHelpSession **ppIRemoteDesktopHelpSession
  945. )
  946. /*++
  947. --*/
  948. {
  949. // No one is using this routine.
  950. return E_NOTIMPL;
  951. }
  952. HRESULT
  953. CRemoteDesktopHelpSessionMgr::CreateHelpSession(
  954. IN BOOL bCacheEntry,
  955. IN BSTR bstrSessName,
  956. IN BSTR bstrSessPwd,
  957. IN BSTR bstrSessDesc,
  958. IN BSTR bstrSessBlob,
  959. IN LONG UserLogonId,
  960. IN BSTR bstrClientSid,
  961. OUT RemoteDesktopHelpSessionObj **ppIRemoteDesktopHelpSession
  962. )
  963. /*++
  964. Routine Description:
  965. Create an instantiation of IRemoteDesktopHelpSession object, each instantiation represent
  966. a RemoteDesktop Help Session.
  967. Parameters:
  968. bstrSessName : User defined Help Session Name, currently not used.
  969. bstrSessPwd : User defined Help Session password.
  970. bstrSessDesc : User defined Help Session Description, currently not used.
  971. ppIRemoteDesktopHelpSession : return an IRemoteDesktopHelpSession object representing a Help Session
  972. Returns:
  973. S_OK
  974. E_UNEXPECTED
  975. SESSMGR_E_GETHELPNOTALLOW User not allow to get help
  976. Other COM error.
  977. Note:
  978. Caller must check if client is allowed to get help
  979. --*/
  980. {
  981. HRESULT hRes = S_OK;
  982. DWORD dwStatus;
  983. CComBSTR bstrGenSessPwd;
  984. PHELPENTRY pHelp = NULL;
  985. CComBSTR bstrHelpSessionId;
  986. DWORD dwICSPort;
  987. LONG MaxTicketExpiry;
  988. CComObject<CRemoteDesktopHelpSession>* pInternalHelpSessionObj = NULL;
  989. if( NULL == ppIRemoteDesktopHelpSession )
  990. {
  991. hRes = E_POINTER;
  992. return hRes;
  993. }
  994. hRes = GenerateHelpSessionId( bstrHelpSessionId );
  995. if( FAILED(hRes) )
  996. {
  997. return hRes;
  998. }
  999. DebugPrintf(
  1000. _TEXT("CreateHelpSession %s\n"),
  1001. bstrHelpSessionId
  1002. );
  1003. //
  1004. // Setup assistant account rights and encryption parameters.
  1005. //
  1006. hRes = AcquireAssistantAccount();
  1007. if( FAILED(hRes) )
  1008. {
  1009. return hRes;
  1010. }
  1011. hRes = g_HelpSessTable.CreateInMemoryHelpEntry(
  1012. bstrHelpSessionId,
  1013. &pHelp
  1014. );
  1015. if( FAILED(hRes) )
  1016. {
  1017. goto CLEANUPANDEXIT;
  1018. }
  1019. MYASSERT( NULL != pHelp );
  1020. //
  1021. // Open ICS port.
  1022. //
  1023. dwICSPort = OpenPort( TERMSRV_TCPPORT );
  1024. //dwICSPort = OpenPort( htons(TERMSRV_TCPPORT) );
  1025. //
  1026. // CRemoteDesktopHelpSession::CreateInstance() will load
  1027. // TS session ID and default RDS settings.
  1028. //
  1029. hRes = CRemoteDesktopHelpSession::CreateInstance(
  1030. this,
  1031. CComBSTR(bstrClientSid), // client SID that open this instance
  1032. pHelp,
  1033. &pInternalHelpSessionObj
  1034. );
  1035. if( SUCCEEDED(hRes) )
  1036. {
  1037. //
  1038. // Check to see if user define a session password, if
  1039. // not, generate a random one.
  1040. //
  1041. bstrGenSessPwd.Attach( bstrSessPwd );
  1042. if( 0 == bstrGenSessPwd.Length() )
  1043. {
  1044. LPTSTR pszSessPwd = NULL;
  1045. //
  1046. // Always detach or CComBSTR will try to free it.
  1047. //
  1048. bstrGenSessPwd.Detach();
  1049. GenerateRandomString( MAX_HELPACCOUNT_PASSWORD * sizeof(TCHAR), &pszSessPwd );
  1050. bstrGenSessPwd = pszSessPwd;
  1051. if( NULL != pszSessPwd )
  1052. {
  1053. LocalFree( pszSessPwd );
  1054. }
  1055. }
  1056. else
  1057. {
  1058. //
  1059. // Detach input from CComBSTR and make a copy of it
  1060. // otherwise destructor will free it which will be
  1061. // the inpute BSTR.
  1062. //
  1063. bstrGenSessPwd.Detach();
  1064. bstrGenSessPwd = bstrSessPwd;
  1065. }
  1066. hRes = pInternalHelpSessionObj->BeginUpdate();
  1067. if( FAILED(hRes) )
  1068. {
  1069. goto CLEANUPANDEXIT;
  1070. }
  1071. //
  1072. // Get default timeout value from registry, not a critical
  1073. // error, if we failed, we just default to 30 days
  1074. //
  1075. hRes = PolicyGetMaxTicketExpiry( &MaxTicketExpiry );
  1076. if( SUCCEEDED(hRes) && MaxTicketExpiry > 0 )
  1077. {
  1078. pInternalHelpSessionObj->put_TimeOut( MaxTicketExpiry );
  1079. }
  1080. hRes = pInternalHelpSessionObj->put_ICSPort( dwICSPort );
  1081. if( SUCCEEDED(hRes) )
  1082. {
  1083. hRes = pInternalHelpSessionObj->put_UserLogonId(UserLogonId);
  1084. }
  1085. if( SUCCEEDED(hRes) )
  1086. {
  1087. // user SID that created this help session
  1088. hRes = pInternalHelpSessionObj->put_UserSID(bstrClientSid);
  1089. }
  1090. if( SUCCEEDED(hRes) )
  1091. {
  1092. hRes = pInternalHelpSessionObj->put_HelpSessionPassword(
  1093. bstrGenSessPwd
  1094. );
  1095. }
  1096. if( SUCCEEDED(hRes) )
  1097. {
  1098. hRes = pInternalHelpSessionObj->put_HelpSessionName(
  1099. bstrSessName
  1100. );
  1101. }
  1102. if( SUCCEEDED(hRes) )
  1103. {
  1104. hRes = pInternalHelpSessionObj->put_HelpSessionDescription(
  1105. bstrSessDesc
  1106. );
  1107. }
  1108. if( SUCCEEDED(hRes) )
  1109. {
  1110. hRes = pInternalHelpSessionObj->put_HelpSessionCreateBlob(
  1111. bstrSessBlob
  1112. );
  1113. }
  1114. if( SUCCEEDED(hRes) )
  1115. {
  1116. hRes = pInternalHelpSessionObj->CommitUpdate();
  1117. }
  1118. if( FAILED(hRes) )
  1119. {
  1120. // ignore error and exit
  1121. (VOID)pInternalHelpSessionObj->AbortUpdate();
  1122. goto CLEANUPANDEXIT;
  1123. }
  1124. //
  1125. // Ignore error, we will let resolver fail.
  1126. pInternalHelpSessionObj->ResolveTicketOwner();
  1127. //
  1128. // We are adding entry to table and also our global object
  1129. // cache, to prevent deadlock or timing problem, lock
  1130. // global cache and let MemEntryToStorageEntry() lock table.
  1131. //
  1132. LockIDToSessionMapCache();
  1133. try {
  1134. if( bCacheEntry )
  1135. {
  1136. // convert a in-memory help to persistant help
  1137. hRes = g_HelpSessTable.MemEntryToStorageEntry( pHelp );
  1138. }
  1139. if( SUCCEEDED(hRes) )
  1140. {
  1141. // Add help session to global cache
  1142. hRes = AddHelpSessionToCache(
  1143. bstrHelpSessionId,
  1144. pInternalHelpSessionObj
  1145. );
  1146. if( SUCCEEDED(hRes) )
  1147. {
  1148. *ppIRemoteDesktopHelpSession = pInternalHelpSessionObj;
  1149. }
  1150. else
  1151. {
  1152. MYASSERT( hRes != HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) );
  1153. }
  1154. }
  1155. }
  1156. catch(...) {
  1157. hRes = E_UNEXPECTED;
  1158. throw;
  1159. }
  1160. UnlockIDToSessionMapCache();
  1161. }
  1162. CLEANUPANDEXIT:
  1163. if( FAILED(hRes) )
  1164. {
  1165. ReleaseAssistantAccount();
  1166. ClosePort(dwICSPort);
  1167. if( NULL != pInternalHelpSessionObj )
  1168. {
  1169. // this will also release pHelp.
  1170. pInternalHelpSessionObj->Release();
  1171. }
  1172. }
  1173. return hRes;
  1174. }
  1175. BOOL
  1176. CRemoteDesktopHelpSessionMgr::CheckAccessRights(
  1177. CComObject<CRemoteDesktopHelpSession>* pIHelpSess
  1178. )
  1179. /*++
  1180. --*/
  1181. {
  1182. //
  1183. // NOTE: This function checks to make sure the caller is the user that
  1184. // created the Help Session. For Whistler, we enforce that Help
  1185. // Sessions only be created by apps running as SYSTEM. Once
  1186. // created, the creating app can pass the object to any other app
  1187. // running in any other context. This function will get in the
  1188. // way of this capability so it simply returns TRUE for now.
  1189. //
  1190. return TRUE;
  1191. BOOL bSuccess;
  1192. // only original creator or help assistant can
  1193. // access
  1194. bSuccess = pIHelpSess->IsEqualSid( m_bstrUserSid );
  1195. if( FALSE == bSuccess )
  1196. {
  1197. bSuccess = g_HelpAccount.IsAccountHelpAccount(
  1198. m_pbUserSid,
  1199. m_cbUserSid
  1200. );
  1201. if( FALSE == bSuccess )
  1202. {
  1203. bSuccess = pIHelpSess->IsEqualSid( g_LocalSystemSID );
  1204. }
  1205. }
  1206. #if DISABLESECURITYCHECKS
  1207. //
  1208. // This is for private testing without using pcHealth, flag is not define
  1209. // in build.
  1210. //
  1211. //
  1212. // For testing only, allow admin to invoke this call
  1213. //
  1214. if( FALSE == bSuccess )
  1215. {
  1216. DWORD dump;
  1217. if( SUCCEEDED(ImpersonateClient()) )
  1218. {
  1219. dump = IsUserAdmin(&bSuccess);
  1220. if( ERROR_SUCCESS != dump )
  1221. {
  1222. bSuccess = FALSE;
  1223. }
  1224. EndImpersonateClient();
  1225. }
  1226. }
  1227. #endif
  1228. return bSuccess;
  1229. }
  1230. STDMETHODIMP
  1231. CRemoteDesktopHelpSessionMgr::RetrieveHelpSession(
  1232. IN BSTR HelpSessionID,
  1233. OUT IRemoteDesktopHelpSession **ppIRemoteDesktopHelpSession
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. Retrieve a help session based on ID.
  1238. Parameters:
  1239. HelpSessionID : Help Session ID returned from CreateHelpSession().
  1240. ppIRemoteDesktopHelpSession : Return Help Session Object for the Help Session.
  1241. Paramters:
  1242. S_OK Success
  1243. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) Help Session not found
  1244. HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) Access Denied
  1245. E_POINTER Invalid argument
  1246. --*/
  1247. {
  1248. HRESULT hRes = S_OK;
  1249. if( FALSE == _Module.IsSuccessServiceStartup() )
  1250. {
  1251. // service startup problem, return error code.
  1252. hRes = _Module.GetServiceStartupStatus();
  1253. DebugPrintf(
  1254. _TEXT("Service startup failed with 0x%x\n"),
  1255. hRes
  1256. );
  1257. return hRes;
  1258. }
  1259. DebugPrintf(
  1260. _TEXT("RetrieveHelpSession %s\n"),
  1261. HelpSessionID
  1262. );
  1263. if( NULL != ppIRemoteDesktopHelpSession )
  1264. {
  1265. // only user sid when needed
  1266. hRes = LoadUserSid();
  1267. if( SUCCEEDED(hRes) )
  1268. {
  1269. RemoteDesktopHelpSessionObj* pObj = LoadHelpSessionObj( this, HelpSessionID );
  1270. if( NULL != pObj && !pObj->IsHelpSessionExpired() )
  1271. {
  1272. if( TRUE == CheckAccessRights(pObj) )
  1273. {
  1274. // LoadHelpSessionObj() AddRef() to object
  1275. *ppIRemoteDesktopHelpSession = pObj;
  1276. }
  1277. else
  1278. {
  1279. hRes = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  1280. // LoadHelpSessionObj() AddRef() to object
  1281. pObj->Release();
  1282. }
  1283. }
  1284. else
  1285. {
  1286. hRes = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1287. }
  1288. }
  1289. }
  1290. else
  1291. {
  1292. hRes = E_POINTER;
  1293. }
  1294. DebugPrintf(
  1295. _TEXT("RetrieveHelpSession %s returns 0x%08x\n"),
  1296. HelpSessionID,
  1297. hRes
  1298. );
  1299. return hRes;
  1300. }
  1301. STDMETHODIMP
  1302. CRemoteDesktopHelpSessionMgr::VerifyUserHelpSession(
  1303. IN BSTR HelpSessionId,
  1304. IN BSTR bstrSessPwd,
  1305. IN BSTR bstrResolverConnectBlob,
  1306. IN BSTR bstrExpertBlob,
  1307. IN LONG CallerProcessId,
  1308. OUT ULONG_PTR* phHelpCtr,
  1309. OUT LONG* pResolverErrCode,
  1310. OUT long* plUserTSSession
  1311. )
  1312. /*++
  1313. Routine Description:
  1314. Verify a user help session is valid and invoke resolver to find the correct
  1315. user help session to provide help.
  1316. Parameters:
  1317. HelpSessionId : Help Session ID.
  1318. bstrSessPwd : Password to be compare.
  1319. bstrResolverConnectBlob : Optional parameter to be passed to resolver.
  1320. bstrExpertBlob : Optional blob to be passed to resolver for security check.
  1321. pResolverErrCode : Return code from resolver.
  1322. plUserTSSession : Current logon session.
  1323. Returns:
  1324. S_OK
  1325. --*/
  1326. {
  1327. HRESULT hRes;
  1328. CComBSTR bstrUserSidString;
  1329. BOOL bMatch;
  1330. BOOL bInCache = FALSE;
  1331. if( FALSE == _Module.IsSuccessServiceStartup() )
  1332. {
  1333. // service startup problem, return error code.
  1334. hRes = _Module.GetServiceStartupStatus();
  1335. DebugPrintf(
  1336. _TEXT("Service startup failed with 0x%x\n"),
  1337. hRes
  1338. );
  1339. *plUserTSSession = SAFERROR_SESSMGRERRORNOTINIT;
  1340. return hRes;
  1341. }
  1342. DebugPrintf(
  1343. _TEXT("VerifyUserHelpSession %s\n"),
  1344. HelpSessionId
  1345. );
  1346. if( NULL != plUserTSSession && NULL != pResolverErrCode && NULL != phHelpCtr )
  1347. {
  1348. hRes = LoadUserSid();
  1349. if( SUCCEEDED(hRes) )
  1350. {
  1351. RemoteDesktopHelpSessionObj* pObj = LoadHelpSessionObj( this, HelpSessionId );
  1352. if( NULL != pObj )
  1353. {
  1354. // Allow all user to invoke this call.
  1355. bMatch = pObj->VerifyUserSession(
  1356. CComBSTR(),
  1357. CComBSTR(bstrSessPwd)
  1358. );
  1359. if( TRUE == bMatch )
  1360. {
  1361. hRes = pObj->ResolveUserSession(
  1362. bstrResolverConnectBlob,
  1363. bstrExpertBlob,
  1364. CallerProcessId,
  1365. phHelpCtr,
  1366. pResolverErrCode,
  1367. plUserTSSession
  1368. );
  1369. }
  1370. else
  1371. {
  1372. hRes = HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD);
  1373. *pResolverErrCode = SAFERROR_INVALIDPASSWORD;
  1374. }
  1375. // LoadHelpSessionObj() AddRef() to object
  1376. pObj->Release();
  1377. }
  1378. else
  1379. {
  1380. hRes = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1381. *pResolverErrCode = SAFERROR_HELPSESSIONNOTFOUND;
  1382. }
  1383. }
  1384. else
  1385. {
  1386. *pResolverErrCode = SAFERROR_INTERNALERROR;
  1387. }
  1388. }
  1389. else
  1390. {
  1391. hRes = E_POINTER;
  1392. *pResolverErrCode = SAFERROR_INVALIDPARAMETERSTRING;
  1393. }
  1394. return hRes;
  1395. }
  1396. STDMETHODIMP
  1397. CRemoteDesktopHelpSessionMgr::IsValidHelpSession(
  1398. /*[in]*/ BSTR HelpSessionId,
  1399. /*[in]*/ BSTR HelpSessionPwd
  1400. )
  1401. /*++
  1402. Description:
  1403. Verify if a help session exists and password match.
  1404. Parameters:
  1405. HelpSessionId : Help session ID.
  1406. HelpSessionPwd : Optional help session password
  1407. Returns:
  1408. Note:
  1409. Only allow system service and administrator to invoke this
  1410. call.
  1411. --*/
  1412. {
  1413. HRESULT hRes = S_OK;
  1414. BOOL bPasswordMatch;
  1415. RemoteDesktopHelpSessionObj* pObj;
  1416. if( FALSE == _Module.IsSuccessServiceStartup() )
  1417. {
  1418. // service startup problem, return error code.
  1419. hRes = _Module.GetServiceStartupStatus();
  1420. DebugPrintf(
  1421. _TEXT("Service startup failed with 0x%x\n"),
  1422. hRes
  1423. );
  1424. return hRes;
  1425. }
  1426. DebugPrintf(
  1427. _TEXT("IsValidHelpSession ID %s\n"),
  1428. HelpSessionId
  1429. );
  1430. hRes = LoadUserSid();
  1431. if( FAILED(hRes) )
  1432. {
  1433. goto CLEANUPANDEXIT;
  1434. }
  1435. hRes = ImpersonateClient();
  1436. if( FAILED(hRes) )
  1437. {
  1438. goto CLEANUPANDEXIT;
  1439. }
  1440. //
  1441. // Make sure only system service can invoke this call.
  1442. //
  1443. if( !g_pSidSystem || FALSE == IsCallerSystem(g_pSidSystem) )
  1444. {
  1445. #if DISABLESECURITYCHECKS
  1446. DWORD dump;
  1447. BOOL bStatus;
  1448. //
  1449. // For testing only, allow admin to invoke this call
  1450. //
  1451. dump = IsUserAdmin(&bStatus);
  1452. hRes = HRESULT_FROM_WIN32( dump );
  1453. if( FAILED(hRes) || FALSE == bStatus )
  1454. {
  1455. EndImpersonateClient();
  1456. hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  1457. goto CLEANUPANDEXIT;
  1458. }
  1459. #else
  1460. EndImpersonateClient();
  1461. hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  1462. goto CLEANUPANDEXIT;
  1463. #endif
  1464. }
  1465. // No need to run as client.
  1466. EndImpersonateClient();
  1467. pObj = LoadHelpSessionObj( this, HelpSessionId );
  1468. if( NULL != pObj )
  1469. {
  1470. CComBSTR bstrPassword;
  1471. bstrPassword.Attach(HelpSessionPwd);
  1472. if( bstrPassword.Length() > 0 )
  1473. {
  1474. bPasswordMatch = pObj->VerifyUserSession(
  1475. CComBSTR(),
  1476. CComBSTR(HelpSessionPwd)
  1477. );
  1478. if( FALSE == bPasswordMatch )
  1479. {
  1480. hRes = HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD);
  1481. }
  1482. }
  1483. bstrPassword.Detach();
  1484. pObj->Release();
  1485. }
  1486. else
  1487. {
  1488. hRes = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1489. }
  1490. CLEANUPANDEXIT:
  1491. return hRes;
  1492. }
  1493. /////////////////////////////////////////////////////////////////////////////
  1494. //
  1495. CRemoteDesktopHelpSessionMgr::CRemoteDesktopHelpSessionMgr() :
  1496. //m_lAccountAcquiredByLocal(0),
  1497. m_pbUserSid(NULL),
  1498. m_cbUserSid(0)
  1499. /*++
  1500. CRemoteDesktopHelpSessMgr Constructor
  1501. --*/
  1502. {
  1503. }
  1504. void
  1505. CRemoteDesktopHelpSessionMgr::Cleanup()
  1506. /*++
  1507. Routine Description:
  1508. Cleanup resource allocated in CRemoteDesktopHelpSessionMgr
  1509. Parameters:
  1510. None.
  1511. Returns:
  1512. None.
  1513. --*/
  1514. {
  1515. if( m_pbUserSid )
  1516. {
  1517. LocalFree(m_pbUserSid);
  1518. m_pbUserSid = NULL;
  1519. }
  1520. }
  1521. //--------------------------------------------------------------
  1522. HRESULT
  1523. CRemoteDesktopHelpSessionMgr::LoadUserSid()
  1524. /*++
  1525. Routine Description:
  1526. Load client's SID onto class member variable m_pbUserSid,
  1527. m_cbUserSid, and m_bstrUserSid. We can't load user SID
  1528. at class constructor as COM still haven't retrieve information
  1529. about client's credential yey.
  1530. Parameters:
  1531. None.
  1532. Returns:
  1533. S_OK
  1534. error code from ImpersonateClient()
  1535. error code from GetTextualSid()
  1536. Note:
  1537. On Win9x machine, user SID is 'hardcoded WIN9X_USER_SID
  1538. --*/
  1539. {
  1540. #ifndef __WIN9XBUILD__
  1541. HRESULT hRes = S_OK;
  1542. // check if SID already loaded, if not continue
  1543. // on loading SID
  1544. if( NULL == m_pbUserSid || 0 == m_cbUserSid )
  1545. {
  1546. DWORD dwStatus;
  1547. BOOL bSuccess = TRUE;
  1548. LPTSTR pszTextualSid = NULL;
  1549. DWORD dwTextualSid = 0;
  1550. hRes = ImpersonateClient();
  1551. if( SUCCEEDED(hRes) )
  1552. {
  1553. m_LogonId = GetUserTSLogonId();
  1554. // retrieve user SID.
  1555. dwStatus = GetUserSid( &m_pbUserSid, &m_cbUserSid );
  1556. if( ERROR_SUCCESS == dwStatus )
  1557. {
  1558. m_bstrUserSid.Empty();
  1559. // convert SID to string
  1560. bSuccess = GetTextualSid(
  1561. m_pbUserSid,
  1562. NULL,
  1563. &dwTextualSid
  1564. );
  1565. if( FALSE == bSuccess && ERROR_INSUFFICIENT_BUFFER == GetLastError() )
  1566. {
  1567. pszTextualSid = (LPTSTR)LocalAlloc(
  1568. LPTR,
  1569. (dwTextualSid + 1) * sizeof(TCHAR)
  1570. );
  1571. if( NULL != pszTextualSid )
  1572. {
  1573. bSuccess = GetTextualSid(
  1574. m_pbUserSid,
  1575. pszTextualSid,
  1576. &dwTextualSid
  1577. );
  1578. if( TRUE == bSuccess )
  1579. {
  1580. m_bstrUserSid = pszTextualSid;
  1581. }
  1582. }
  1583. }
  1584. if( 0 == m_bstrUserSid.Length() )
  1585. {
  1586. hRes = HRESULT_FROM_WIN32(GetLastError());
  1587. }
  1588. }
  1589. if( NULL != pszTextualSid )
  1590. {
  1591. LocalFree(pszTextualSid);
  1592. }
  1593. EndImpersonateClient();
  1594. }
  1595. }
  1596. return hRes;
  1597. #else
  1598. m_pbUserSid = NULL;
  1599. m_cbUserSid = 0;
  1600. m_bstrUserSid = WIN9X_USER_SID;
  1601. return S_OK;
  1602. #endif
  1603. }
  1604. //---------------------------------------------------------------
  1605. HRESULT
  1606. CRemoteDesktopHelpSessionMgr::IsUserAllowToGetHelp(
  1607. OUT BOOL* pbAllow
  1608. )
  1609. /*++
  1610. Routine Description:
  1611. Check if connected user is allowed to GetHelp.
  1612. Parameters:
  1613. pbAllow : Return TRUE if user is allowed to GetHelp, FALSE otherwise.
  1614. Returns:
  1615. S_OK or error code.
  1616. Note:
  1617. GetHelp's priviledge is via group membership.
  1618. --*/
  1619. {
  1620. HRESULT hRes;
  1621. hRes = ImpersonateClient();
  1622. if( SUCCEEDED(hRes) )
  1623. {
  1624. CComBSTRtoLPTSTR string( m_bstrUserSid );
  1625. *pbAllow = ::IsUserAllowToGetHelp( GetUserTSLogonId(), (LPCTSTR) string );
  1626. hRes = S_OK;
  1627. }
  1628. else
  1629. {
  1630. // can't get help if impersonate failed.
  1631. *pbAllow = FALSE;
  1632. }
  1633. EndImpersonateClient();
  1634. return hRes;
  1635. }
  1636. //---------------------------------------------------------
  1637. HRESULT
  1638. CRemoteDesktopHelpSessionMgr::AcquireAssistantAccount()
  1639. /*++
  1640. Routine Description:
  1641. "Acquire", increase the reference count of RemoteDesktop Assistant account.
  1642. Routine creates a 'well-known' assistant account If is not exist or
  1643. enables/change password if the account is disabled.
  1644. Help Account Manager will automatically release all reference count
  1645. acquire by a particular session when user log off to prevent this account
  1646. been 'locked'.
  1647. Parameters:
  1648. pvarAccountName
  1649. Pointer to BSTR to receive RemoteDesktop Assistant account name.
  1650. pvarAccountPwd
  1651. Pointer to BSTR to receive RemoteDesktop Assistant account password.
  1652. Returns:
  1653. Success or error code.
  1654. Note:
  1655. This is also the conference name and conference password
  1656. when NetMeeting is used to share user desktop.
  1657. --*/
  1658. {
  1659. HRESULT hRes = S_OK;
  1660. DWORD dwStatus;
  1661. CCriticalSectionLocker l( gm_AccRefCountCS );
  1662. #ifndef __WIN9xBUILD__
  1663. //
  1664. // Always enable interactive rights.
  1665. //
  1666. hRes = g_HelpAccount.EnableRemoteInteractiveRight(TRUE);
  1667. if( FAILED(hRes) )
  1668. {
  1669. DebugPrintf(
  1670. _TEXT("Failed in EnableRemoteInteractiveRight() - 0x%08x\n"),
  1671. hRes
  1672. );
  1673. goto CLEANUPANDEXIT;
  1674. }
  1675. //
  1676. // Always enable the account in case user disable it.
  1677. //
  1678. hRes = g_HelpAccount.EnableHelpAssistantAccount( TRUE );
  1679. if( FAILED(hRes) )
  1680. {
  1681. DebugPrintf( _TEXT("Can't enable help assistant account 0x%x\n"), hRes );
  1682. goto CLEANUPANDEXIT;
  1683. }
  1684. if( g_HelpSessTable.NumEntries() == 0 )
  1685. {
  1686. DebugPrintf(
  1687. _TEXT("Setting encryption parameters...\n")
  1688. );
  1689. dwStatus = TSHelpAssistantBeginEncryptionCycle();
  1690. hRes = HRESULT_FROM_WIN32( dwStatus );
  1691. MYASSERT( SUCCEEDED(hRes) );
  1692. //
  1693. // Setup account TS setting via WTSAPI
  1694. //
  1695. hRes = g_HelpAccount.SetupHelpAccountTSSettings();
  1696. if( SUCCEEDED(hRes) )
  1697. {
  1698. DebugPrintf(
  1699. _TEXT("SetupHelpAccountTSSettings return 0x%08x\n"),
  1700. hRes
  1701. );
  1702. }
  1703. else
  1704. {
  1705. DebugPrintf( _TEXT("SetupHelpAccountTSSettings failed with 0x%08x\n"), hRes );
  1706. }
  1707. }
  1708. #endif
  1709. CLEANUPANDEXIT:
  1710. return hRes;
  1711. }
  1712. //----------------------------------------------------------
  1713. HRESULT
  1714. CRemoteDesktopHelpSessionMgr::ReleaseAssistantAccount()
  1715. /*++
  1716. Routine Description:
  1717. Release RemoteDesktop assistant account previously
  1718. acquired with AcquireAssistantAccount(),
  1719. account will be disabled if the account reference
  1720. count is 0.
  1721. Help Account Manager will automatically release all
  1722. reference count acquire by a particular session when
  1723. user log off to prevent this account been 'locked'.
  1724. Parameters:
  1725. None
  1726. Returns:
  1727. Success or error code.
  1728. --*/
  1729. {
  1730. HRESULT hRes = S_OK;
  1731. DWORD dwStatus;
  1732. CCriticalSectionLocker l( gm_AccRefCountCS );
  1733. #ifndef __WIN9XBUILD__
  1734. if( g_HelpSessTable.NumEntries() == 0 )
  1735. {
  1736. // ignore error if we can't reset account password
  1737. (void)g_HelpAccount.ResetHelpAccountPassword();
  1738. dwStatus = TSHelpAssisantEndEncryptionCycle();
  1739. hRes = HRESULT_FROM_WIN32( dwStatus );
  1740. MYASSERT( SUCCEEDED(hRes) );
  1741. //
  1742. // diable HelpAssistant TS 'Connect' right.
  1743. //
  1744. g_HelpAccount.EnableRemoteInteractiveRight(FALSE);
  1745. hRes = g_HelpAccount.EnableHelpAssistantAccount( FALSE );
  1746. if( FAILED(hRes) )
  1747. {
  1748. // not a critical error.
  1749. DebugPrintf( _TEXT("Can't disable help assistant account 0x%x\n"), hRes );
  1750. }
  1751. }
  1752. #endif
  1753. return S_OK;
  1754. }
  1755. STDMETHODIMP
  1756. CRemoteDesktopHelpSessionMgr::GetUserSessionRdsSetting(
  1757. OUT REMOTE_DESKTOP_SHARING_CLASS* rdsLevel
  1758. )
  1759. /*++
  1760. --*/
  1761. {
  1762. HRESULT hRes;
  1763. DWORD dwStatus;
  1764. REMOTE_DESKTOP_SHARING_CLASS userRdsDefault;
  1765. if( NULL != rdsLevel )
  1766. {
  1767. hRes = ImpersonateClient();
  1768. if( SUCCEEDED(hRes) )
  1769. {
  1770. hRes = LoadUserSid();
  1771. MYASSERT( SUCCEEDED(hRes) );
  1772. dwStatus = GetUserRDSLevel( m_LogonId, &userRdsDefault );
  1773. hRes = HRESULT_FROM_WIN32( dwStatus );
  1774. *rdsLevel = userRdsDefault;
  1775. EndImpersonateClient();
  1776. }
  1777. }
  1778. else
  1779. {
  1780. hRes = E_POINTER;
  1781. }
  1782. return hRes;
  1783. }
  1784. STDMETHODIMP
  1785. CRemoteDesktopHelpSessionMgr::ResetHelpAssistantAccount(
  1786. BOOL bForce
  1787. )
  1788. /*++
  1789. Routine Description:
  1790. Reset help assistant account password.
  1791. Parameters:
  1792. bForce : TRUE if delete all pending help and reset the account password, FALSE
  1793. if reset account password if there is no more pending help session.
  1794. Returns:
  1795. S_OK
  1796. HRESULT_FROM_WIN32( ERROR_MORE_DATA )
  1797. --*/
  1798. {
  1799. HRESULT hRes = S_OK;
  1800. hRes = LoadUserSid();
  1801. MYASSERT( SUCCEEDED(hRes) );
  1802. // Check any help stil pending
  1803. if( g_HelpSessTable.NumEntries() > 0 )
  1804. {
  1805. if( FALSE == bForce )
  1806. {
  1807. hRes = HRESULT_FROM_WIN32( ERROR_MORE_DATA );
  1808. }
  1809. else
  1810. {
  1811. IDToSessionMap::LOCK_ITERATOR it = gm_HelpIdToHelpSession.begin();
  1812. //
  1813. // notify all in cached pending help session that it has been deleted.
  1814. // rest help entry will be deleted via DeleteSessionTable().
  1815. for( ;it != gm_HelpIdToHelpSession.end(); )
  1816. {
  1817. RemoteDesktopHelpSessionObj* pObj = (*it).second;
  1818. // DeleteHelp() will wipe entry from cache.
  1819. it++;
  1820. // We can't not release this object since client might still
  1821. // holding pointer
  1822. pObj->DeleteHelp();
  1823. }
  1824. g_HelpSessTable.DeleteSessionTable();
  1825. }
  1826. }
  1827. if(SUCCEEDED(hRes))
  1828. {
  1829. hRes = g_HelpAccount.ResetHelpAccountPassword();
  1830. }
  1831. return hRes;
  1832. }
  1833. HRESULT
  1834. CRemoteDesktopHelpSessionMgr::GenerateHelpSessionId(
  1835. CComBSTR& bstrHelpSessionId
  1836. )
  1837. /*++
  1838. Routine Description:
  1839. Create a unique Help Session ID.
  1840. Parameters:
  1841. bstrHelpSessionId : Reference to CComBSTR to receive HelpSessionId.
  1842. Returns:
  1843. S_OK
  1844. HRESULT_FROM_WIN32( Status from RPC call UuidCreate() or UuidToString() )
  1845. --*/
  1846. {
  1847. LPTSTR pszRandomString = NULL;
  1848. DWORD dwStatus;
  1849. dwStatus = GenerateRandomString( 32, &pszRandomString );
  1850. if( ERROR_SUCCESS == dwStatus )
  1851. {
  1852. bstrHelpSessionId = pszRandomString;
  1853. LocalFree( pszRandomString );
  1854. }
  1855. return HRESULT_FROM_WIN32( dwStatus );
  1856. }
  1857. STDMETHODIMP
  1858. CRemoteDesktopHelpSessionMgr::CreateHelpSessionEx(
  1859. /*[in]*/ REMOTE_DESKTOP_SHARING_CLASS sharingClass,
  1860. /*[in]*/ BOOL fEnableCallback,
  1861. /*[in]*/ LONG timeOut,
  1862. /*[in]*/ LONG userSessionId,
  1863. /*[in]*/ BSTR userSid,
  1864. /*[in]*/ BSTR bstrUserHelpCreateBlob,
  1865. /*[out, retval]*/ IRemoteDesktopHelpSession** ppIRemoteDesktopHelpSession
  1866. )
  1867. /*++
  1868. Routine Description:
  1869. Simimar to CreateHelpSession() except it allow caller to assoicate a
  1870. help session to a specific user, caller must be running in
  1871. system context.
  1872. Parameters:
  1873. sharingClass : Level of remote control (shadow setting) needed.
  1874. fEnableCallback : TRUE to enable resolver callback, FALSE otherwise.
  1875. timeOut : Help session timeout value.
  1876. userSessionId : Logon user TS session ID.
  1877. userSid : User SID that help session associated.
  1878. bstrUserHelpCreateBlob : user specific create blob.
  1879. parms: Return connect parm.
  1880. Returns:
  1881. --*/
  1882. {
  1883. HRESULT hRes;
  1884. RemoteDesktopHelpSessionObj* pRemoteDesktopHelpSessionObj = NULL;
  1885. if( NULL == ppIRemoteDesktopHelpSession )
  1886. {
  1887. hRes = E_POINTER;
  1888. }
  1889. else
  1890. {
  1891. hRes = RemoteCreateHelpSessionEx(
  1892. TRUE, // cache entry
  1893. fEnableCallback, // enable resolver ?
  1894. sharingClass,
  1895. (timeOut == 0) ? EXPIRE_HELPSESSION_PERIOD : timeOut,
  1896. userSessionId,
  1897. userSid,
  1898. bstrUserHelpCreateBlob,
  1899. &pRemoteDesktopHelpSessionObj
  1900. );
  1901. //
  1902. // 1) pcHealth resolver interprete salem connection parm, reset help session name to
  1903. // some default string.
  1904. // 2) When resolver invoke helpctr, script will truncate up to first space so
  1905. // our name can not contain space.
  1906. //
  1907. if( SUCCEEDED(hRes) && pRemoteDesktopHelpSessionObj )
  1908. {
  1909. ULONG flag;
  1910. hRes = pRemoteDesktopHelpSessionObj->put_HelpSessionName( HELPSESSION_NORMAL_RA );
  1911. if( SUCCEEDED(hRes) )
  1912. {
  1913. hRes = pRemoteDesktopHelpSessionObj->put_HelpSessionDescription( HELPSESSION_NORMAL_RA );
  1914. }
  1915. if( FAILED(hRes) )
  1916. {
  1917. pRemoteDesktopHelpSessionObj->Release();
  1918. pRemoteDesktopHelpSessionObj = NULL;
  1919. }
  1920. flag = pRemoteDesktopHelpSessionObj->GetHelpSessionFlag();
  1921. pRemoteDesktopHelpSessionObj->SetHelpSessionFlag( flag & ~HELPSESSIONFLAG_UNSOLICITEDHELP );
  1922. }
  1923. *ppIRemoteDesktopHelpSession = pRemoteDesktopHelpSessionObj;
  1924. }
  1925. return hRes;
  1926. }
  1927. STDMETHODIMP
  1928. CRemoteDesktopHelpSessionMgr::RemoteCreateHelpSession(
  1929. /*[in]*/ REMOTE_DESKTOP_SHARING_CLASS sharingClass,
  1930. /*[in]*/ LONG timeOut,
  1931. /*[in]*/ LONG userSessionId,
  1932. /*[in]*/ BSTR userSid,
  1933. /*[in]*/ BSTR bstrHelpCreateBlob,
  1934. /*[out, retval]*/ BSTR* parms
  1935. )
  1936. /*++
  1937. Description:
  1938. UNSOLICTED SUPPORT, only invoke by PCHEALTH, differ to CreateHelpSessionEx()
  1939. are help session entry will not cached into registry and resolver callback is
  1940. always enable.
  1941. Parameters:
  1942. Refer to CreateHelpSessionEx().
  1943. Returns:
  1944. --*/
  1945. {
  1946. HRESULT hRes;
  1947. RemoteDesktopHelpSessionObj* pIRemoteDesktopHelpSession = NULL;
  1948. // if pcHealth pass unresolve session, cache the entry, set
  1949. // timeout to very short for security reason.
  1950. hRes = RemoteCreateHelpSessionEx(
  1951. FALSE, // don't cache entry in registry.
  1952. TRUE, // force resolver call.
  1953. sharingClass,
  1954. (timeOut == 0) ? DEFAULT_UNSOLICATED_HELP_TIMEOUT : timeOut,
  1955. userSessionId,
  1956. userSid,
  1957. bstrHelpCreateBlob,
  1958. &pIRemoteDesktopHelpSession
  1959. );
  1960. if( SUCCEEDED(hRes) && NULL != pIRemoteDesktopHelpSession )
  1961. {
  1962. hRes = pIRemoteDesktopHelpSession->get_ConnectParms( parms );
  1963. }
  1964. return hRes;
  1965. }
  1966. HRESULT
  1967. CRemoteDesktopHelpSessionMgr::RemoteCreateHelpSessionEx(
  1968. /*[in]*/ BOOL bCacheEntry,
  1969. /*[in]*/ BOOL bEnableResolver,
  1970. /*[in]*/ REMOTE_DESKTOP_SHARING_CLASS sharingClass,
  1971. /*[in]*/ LONG timeOut,
  1972. /*[in]*/ LONG userSessionId,
  1973. /*[in]*/ BSTR userSid,
  1974. /*[in]*/ BSTR bstrHelpCreateBlob,
  1975. /*[out, retval]*/ RemoteDesktopHelpSessionObj** ppIRemoteDesktopHelpSession
  1976. )
  1977. /*++
  1978. Routine Description:
  1979. Create help ticket and return connection parameters.
  1980. Parameters:
  1981. bCacheEntry : Cache help session to registry.
  1982. bEnableCallback : TRUE to enable resolver callback, FALSE otherwise.
  1983. sharingClass : RDS setting requested.
  1984. timeout : Help session expiry period.
  1985. userSessionId : User TS session ID that help session associated with.
  1986. userSid : SID of user on the TS session.
  1987. bstrHelpCreateBlob : User specific help session create blob, meaningless
  1988. if resolver is not enabled.
  1989. ppIRemoteDesktopHelpSession : Help session created.
  1990. Returns:
  1991. S_OK
  1992. S_FALSE sharingClass violate policy setting.
  1993. other error code.
  1994. --*/
  1995. {
  1996. HRESULT hRes = S_OK;
  1997. BOOL bStatus;
  1998. RemoteDesktopHelpSessionObj *pIHelpSession = NULL;
  1999. BOOL bAllowGetHelp = FALSE;
  2000. ULONG flag;
  2001. #if DBG
  2002. long HelpSessLogonId;
  2003. #endif
  2004. if( FALSE == _Module.IsSuccessServiceStartup() )
  2005. {
  2006. // service startup problem, return error code.
  2007. hRes = _Module.GetServiceStartupStatus();
  2008. DebugPrintf(
  2009. _TEXT("Service startup failed with 0x%x\n"),
  2010. hRes
  2011. );
  2012. goto CLEANUPANDEXIT;
  2013. }
  2014. if( 0 == timeOut )
  2015. {
  2016. hRes = E_INVALIDARG;
  2017. MYASSERT(FALSE);
  2018. goto CLEANUPANDEXIT;
  2019. }
  2020. hRes = LoadUserSid();
  2021. if( FAILED(hRes) )
  2022. {
  2023. goto CLEANUPANDEXIT;
  2024. }
  2025. // common routine in tsremdsk.lib
  2026. if( FALSE == TSIsMachinePolicyAllowHelp() )
  2027. {
  2028. hRes = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  2029. goto CLEANUPANDEXIT;
  2030. }
  2031. hRes = ImpersonateClient();
  2032. if( FAILED(hRes) )
  2033. {
  2034. goto CLEANUPANDEXIT;
  2035. }
  2036. //
  2037. // Make sure only system service can invoke this call.
  2038. //
  2039. if( !g_pSidSystem || FALSE == IsCallerSystem(g_pSidSystem) )
  2040. {
  2041. #if DISABLESECURITYCHECKS
  2042. DWORD dump;
  2043. //
  2044. // For testing only, allow admin to invoke this call
  2045. //
  2046. dump = IsUserAdmin(&bStatus);
  2047. hRes = HRESULT_FROM_WIN32( dump );
  2048. if( FAILED(hRes) || FALSE == bStatus )
  2049. {
  2050. EndImpersonateClient();
  2051. hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  2052. goto CLEANUPANDEXIT;
  2053. }
  2054. #else
  2055. EndImpersonateClient();
  2056. hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  2057. goto CLEANUPANDEXIT;
  2058. #endif
  2059. }
  2060. // No need to run as client.
  2061. EndImpersonateClient();
  2062. //
  2063. // No ERROR checking on userSessionId and userSid, pcHealth
  2064. // will make sure all parameter is correct
  2065. //
  2066. //
  2067. // Create a Help Session.
  2068. //
  2069. hRes = CreateHelpSession(
  2070. bCacheEntry,
  2071. HELPSESSION_UNSOLICATED,
  2072. CComBSTR(""),
  2073. HELPSESSION_UNSOLICATED,
  2074. bstrHelpCreateBlob,
  2075. (userSessionId == -1) ? UNKNOWN_LOGONID : userSessionId,
  2076. userSid,
  2077. &pIHelpSession
  2078. );
  2079. if( FAILED(hRes) )
  2080. {
  2081. goto CLEANUPANDEXIT;
  2082. }
  2083. if( NULL == pIHelpSession )
  2084. {
  2085. MYASSERT( NULL != pIHelpSession );
  2086. hRes = E_UNEXPECTED;
  2087. goto CLEANUPANDEXIT;
  2088. }
  2089. #if DBG
  2090. hRes = pIHelpSession->get_UserLogonId( &HelpSessLogonId );
  2091. MYASSERT( SUCCEEDED(hRes) );
  2092. if( userSessionId != -1 )
  2093. {
  2094. MYASSERT( HelpSessLogonId == userSessionId );
  2095. }
  2096. else
  2097. {
  2098. MYASSERT( HelpSessLogonId == UNKNOWN_LOGONID );
  2099. }
  2100. #endif
  2101. //
  2102. // setup help session parms.
  2103. //
  2104. hRes = pIHelpSession->put_EnableResolver(bEnableResolver);
  2105. MYASSERT( SUCCEEDED(hRes) );
  2106. if( FAILED(hRes) )
  2107. {
  2108. goto CLEANUPANDEXIT;
  2109. }
  2110. hRes = pIHelpSession->put_TimeOut( timeOut );
  2111. if( FAILED(hRes) )
  2112. {
  2113. DebugPrintf(
  2114. _TEXT("put_TimeOut() failed with 0x%08x\n"),
  2115. hRes
  2116. );
  2117. goto CLEANUPANDEXIT;
  2118. }
  2119. //
  2120. // We change default RDS value at the end so we can return error code or S_FALSE
  2121. // from this.
  2122. //
  2123. hRes = pIHelpSession->put_UserHelpSessionRemoteDesktopSharingSetting( sharingClass );
  2124. if( FAILED( hRes) )
  2125. {
  2126. DebugPrintf(
  2127. _TEXT("put_UserHelpSessionRemoteDesktopSharingSetting() failed with 0x%08x\n"),
  2128. hRes
  2129. );
  2130. }
  2131. flag = pIHelpSession->GetHelpSessionFlag();
  2132. pIHelpSession->SetHelpSessionFlag( flag | HELPSESSIONFLAG_UNSOLICITEDHELP );
  2133. CLEANUPANDEXIT:
  2134. if( FAILED(hRes) )
  2135. {
  2136. if( NULL != pIHelpSession )
  2137. {
  2138. pIHelpSession->Release();
  2139. }
  2140. }
  2141. else
  2142. {
  2143. MYASSERT( NULL != pIHelpSession );
  2144. *ppIRemoteDesktopHelpSession = pIHelpSession;
  2145. }
  2146. return hRes;
  2147. }
  2148. HRESULT
  2149. LoadLocalSystemSID()
  2150. /*
  2151. Routine Description:
  2152. Load service account as SID string.
  2153. Parameter:
  2154. None.
  2155. Returns:
  2156. S_OK or error code
  2157. --*/
  2158. {
  2159. DWORD dwStatus;
  2160. BOOL bSuccess = TRUE;
  2161. LPTSTR pszTextualSid = NULL;
  2162. DWORD dwTextualSid = 0;
  2163. dwStatus = CreateSystemSid( &g_pSidSystem );
  2164. if( ERROR_SUCCESS == dwStatus )
  2165. {
  2166. // convert SID to string
  2167. bSuccess = GetTextualSid(
  2168. g_pSidSystem,
  2169. NULL,
  2170. &dwTextualSid
  2171. );
  2172. if( FALSE == bSuccess && ERROR_INSUFFICIENT_BUFFER == GetLastError() )
  2173. {
  2174. pszTextualSid = (LPTSTR)LocalAlloc(
  2175. LPTR,
  2176. (dwTextualSid + 1) * sizeof(TCHAR)
  2177. );
  2178. if( NULL != pszTextualSid )
  2179. {
  2180. bSuccess = GetTextualSid(
  2181. g_pSidSystem,
  2182. pszTextualSid,
  2183. &dwTextualSid
  2184. );
  2185. if( TRUE == bSuccess )
  2186. {
  2187. g_LocalSystemSID = pszTextualSid;
  2188. }
  2189. }
  2190. }
  2191. if( 0 == g_LocalSystemSID.Length() )
  2192. {
  2193. dwStatus = GetLastError();
  2194. }
  2195. }
  2196. if( NULL != pszTextualSid )
  2197. {
  2198. LocalFree(pszTextualSid);
  2199. }
  2200. return HRESULT_FROM_WIN32(dwStatus);
  2201. }
  2202. HRESULT
  2203. CRemoteDesktopHelpSessionMgr::LogSalemEvent(
  2204. IN long ulEventType,
  2205. IN long ulEventCode,
  2206. IN long numStrings,
  2207. IN LPCTSTR* pszStrings
  2208. )
  2209. /*++
  2210. Description:
  2211. Log a Salem related event, this is invoked by TermSrv and rdshost to log
  2212. event related to help assistant connection.
  2213. Parameters:
  2214. Returns:
  2215. S_OK or error code.
  2216. --*/
  2217. {
  2218. HRESULT hRes = S_OK;
  2219. switch( ulEventCode )
  2220. {
  2221. case REMOTEASSISTANCE_EVENTLOG_TERMSRV_INVALID_TICKET:
  2222. if( numStrings >= 3 )
  2223. {
  2224. // this event require three parameters.
  2225. ulEventCode = SESSMGR_E_REMOTEASSISTANCE_CONNECTFAILED;
  2226. _Module.LogEventString(
  2227. ulEventType,
  2228. ulEventCode,
  2229. numStrings,
  2230. pszStrings
  2231. );
  2232. }
  2233. else
  2234. {
  2235. hRes = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  2236. }
  2237. break;
  2238. case REMOTEASSISTANCE_EVENTLOG_TERMSRV_REVERSE_CONNECT:
  2239. // need at least three parameters.
  2240. if( numStrings >= 3 )
  2241. {
  2242. //
  2243. // String is in the order of
  2244. // expert IP address from client
  2245. // expert IP address from rdshost.exe
  2246. // Ticket ID.
  2247. //
  2248. LPCTSTR pszLogStrings[4];
  2249. ulEventCode = SESSMGR_I_REMOTEASSISTANCE_CONNECTTOEXPERT;
  2250. RemoteDesktopHelpSessionObj* pObj;
  2251. //
  2252. // Load expire help session in order to log event, we will let
  2253. // validation catch error
  2254. //
  2255. pObj = LoadHelpSessionObj( NULL, CComBSTR(pszStrings[2]), TRUE );
  2256. if( NULL != pObj )
  2257. {
  2258. pszLogStrings[0] = (LPCTSTR)pObj->m_EventLogInfo.bstrNoviceDomain;
  2259. pszLogStrings[1] = (LPCTSTR)pObj->m_EventLogInfo.bstrNoviceAccount;
  2260. pszLogStrings[2] = pszStrings[0];
  2261. pszLogStrings[3] = pszStrings[1];
  2262. _Module.LogEventString(
  2263. ulEventType,
  2264. ulEventCode,
  2265. 4,
  2266. pszLogStrings
  2267. );
  2268. pObj->Release();
  2269. }
  2270. else
  2271. {
  2272. hRes = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  2273. }
  2274. }
  2275. else
  2276. {
  2277. hRes = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  2278. MYASSERT(FALSE);
  2279. }
  2280. break;
  2281. default:
  2282. MYASSERT(FALSE);
  2283. hRes = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2284. }
  2285. return hRes;
  2286. }
  2287. STDMETHODIMP
  2288. CRemoteDesktopHelpSessionMgr::LogSalemEvent(
  2289. /*[in]*/ long ulEventType,
  2290. /*[in]*/ long ulEventCode,
  2291. /*[in]*/ VARIANT* pEventStrings
  2292. )
  2293. /*++
  2294. --*/
  2295. {
  2296. HRESULT hRes = S_OK;
  2297. BSTR* bstrArray = NULL;
  2298. SAFEARRAY* psa = NULL;
  2299. VARTYPE vt_type;
  2300. DWORD dwNumStrings = 0;
  2301. hRes = ImpersonateClient();
  2302. if( FAILED(hRes) )
  2303. {
  2304. goto CLEANUPANDEXIT;
  2305. }
  2306. //
  2307. // Make sure only system service can invoke this call.
  2308. //
  2309. if( !g_pSidSystem || FALSE == IsCallerSystem(g_pSidSystem) )
  2310. {
  2311. #if DISABLESECURITYCHECKS
  2312. DWORD dump;
  2313. BOOL bStatus;
  2314. //
  2315. // For testing only, allow admin to invoke this call
  2316. //
  2317. dump = IsUserAdmin(&bStatus);
  2318. hRes = HRESULT_FROM_WIN32( dump );
  2319. if( FAILED(hRes) || FALSE == bStatus )
  2320. {
  2321. EndImpersonateClient();
  2322. hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  2323. goto CLEANUPANDEXIT;
  2324. }
  2325. #else
  2326. EndImpersonateClient();
  2327. hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  2328. goto CLEANUPANDEXIT;
  2329. #endif
  2330. }
  2331. // No need to run as client.
  2332. EndImpersonateClient();
  2333. if( NULL == pEventStrings )
  2334. {
  2335. hRes = LogSalemEvent( ulEventType, ulEventCode );
  2336. }
  2337. else
  2338. {
  2339. //
  2340. // we only support BSTR data type.
  2341. if( !(pEventStrings->vt & VT_BSTR) )
  2342. {
  2343. MYASSERT(FALSE);
  2344. hRes = E_INVALIDARG;
  2345. goto CLEANUPANDEXIT;
  2346. }
  2347. //
  2348. // we are dealing with multiple BSTRs
  2349. if( pEventStrings->vt & VT_ARRAY )
  2350. {
  2351. psa = pEventStrings->parray;
  2352. // only accept 1 dim.
  2353. if( 1 != SafeArrayGetDim(psa) )
  2354. {
  2355. hRes = E_INVALIDARG;
  2356. MYASSERT(FALSE);
  2357. goto CLEANUPANDEXIT;
  2358. }
  2359. // only accept BSTR as input type.
  2360. hRes = SafeArrayGetVartype( psa, &vt_type );
  2361. if( FAILED(hRes) )
  2362. {
  2363. MYASSERT(FALSE);
  2364. goto CLEANUPANDEXIT;
  2365. }
  2366. if( VT_BSTR != vt_type )
  2367. {
  2368. DebugPrintf(
  2369. _TEXT("Unsupported type 0x%08x\n"),
  2370. vt_type
  2371. );
  2372. hRes = E_INVALIDARG;
  2373. MYASSERT(FALSE);
  2374. goto CLEANUPANDEXIT;
  2375. }
  2376. hRes = SafeArrayAccessData(psa, (void **)&bstrArray);
  2377. if( FAILED(hRes) )
  2378. {
  2379. MYASSERT(FALSE);
  2380. goto CLEANUPANDEXIT;
  2381. }
  2382. hRes = LogSalemEvent(
  2383. ulEventType,
  2384. ulEventCode,
  2385. psa->rgsabound->cElements,
  2386. (LPCTSTR *)bstrArray
  2387. );
  2388. SafeArrayUnaccessData(psa);
  2389. }
  2390. else
  2391. {
  2392. hRes = LogSalemEvent(
  2393. ulEventType,
  2394. ulEventCode,
  2395. 1,
  2396. (LPCTSTR *)&(pEventStrings->bstrVal)
  2397. );
  2398. }
  2399. }
  2400. CLEANUPANDEXIT:
  2401. return hRes;
  2402. }
  2403. void
  2404. CRemoteDesktopHelpSessionMgr::NotifyExpertLogoff(
  2405. LONG ExpertSessionId,
  2406. BSTR HelpedTicketId
  2407. )
  2408. /*++
  2409. Routine Description:
  2410. Notify help ticket that helping expert has logoff so
  2411. ticket object can de-associate (mark is not been help) with a
  2412. particular helper session.
  2413. Parameters:
  2414. ExpertSessionId : Expert logon session ID.
  2415. HelpedTicketId : Ticket ID that expert was providing help.
  2416. Returns:
  2417. None.
  2418. --*/
  2419. {
  2420. MYASSERT( NULL != HelpedTicketId );
  2421. if( NULL != HelpedTicketId )
  2422. {
  2423. DebugPrintf(
  2424. _TEXT("NotifyExpertLogoff() on %d %s...\n"),
  2425. ExpertSessionId,
  2426. HelpedTicketId
  2427. );
  2428. //
  2429. // Load Help Entry, we need to inform resolver on disconnect so load
  2430. // expired ticket.
  2431. //
  2432. RemoteDesktopHelpSessionObj* pObj = LoadHelpSessionObj( NULL, HelpedTicketId, TRUE );
  2433. if( NULL != pObj )
  2434. {
  2435. MYASSERT( ExpertSessionId == pObj->GetHelperSessionId() );
  2436. if( ExpertSessionId == pObj->GetHelperSessionId() )
  2437. {
  2438. pObj->NotifyDisconnect();
  2439. }
  2440. pObj->Release();
  2441. }
  2442. //
  2443. // Free ticket ID
  2444. //
  2445. SysFreeString( HelpedTicketId );
  2446. }
  2447. return;
  2448. }