Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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