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.

2960 lines
80 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. sessmgr.cpp
  5. Abstract:
  6. ATL wizard generated code.
  7. Author:
  8. HueiWang 2/17/2000
  9. --*/
  10. // Note: Proxy/Stub Information
  11. // To build a separate proxy/stub DLL,
  12. // run nmake -f sessmgrps.mk in the project directory.
  13. #include "stdafx.h"
  14. #include "resource.h"
  15. #include <initguid.h>
  16. #include <process.h>
  17. #include <tchar.h>
  18. #include "sessmgr.h"
  19. #include "sessmgr_i.c"
  20. #include <stdio.h>
  21. //#include <new.h>
  22. #include "global.h"
  23. #include "HelpSess.h"
  24. #include "HelpMgr.h"
  25. #include "helper.h"
  26. #include "helpacc.h"
  27. #include <rdshost.h>
  28. #include "policy.h"
  29. #include "remotedesktoputils.h"
  30. #define SETUPLOGFILE_NAME _TEXT("sessmgr.setup.log")
  31. #define SESSMGR_SERVICE 0
  32. #define SESSMGR_REGSERVER 1
  33. #define SESSMGR_UNREGSERVER 2
  34. #define SESSMGR_SP1UPGRADE 3
  35. BEGIN_OBJECT_MAP(ObjectMap)
  36. //OBJECT_ENTRY(CLSID_RemoteDesktopHelpSession, CRemoteDesktopHelpSession)
  37. OBJECT_ENTRY(CLSID_RemoteDesktopHelpSessionMgr, CRemoteDesktopHelpSessionMgr)
  38. END_OBJECT_MAP()
  39. CServiceModule _Module;
  40. HANDLE g_hTSCertificateChanged = NULL;
  41. HANDLE g_hWaitTSCertificateChanged = NULL;
  42. HKEY g_hTSCertificateRegKey = NULL;
  43. VOID CALLBACK
  44. TSCertChangeCallback(
  45. PVOID pContext,
  46. BOOLEAN bTimerOrWaitFired
  47. )
  48. /*++
  49. Callback for TS certificate registry change from threadpool function.
  50. --*/
  51. {
  52. MYASSERT( FALSE == bTimerOrWaitFired );
  53. // Our wait is forever so can't be timeout.
  54. if( FALSE == bTimerOrWaitFired )
  55. {
  56. PostThreadMessage(
  57. _Module.dwThreadID,
  58. WM_LOADTSPUBLICKEY,
  59. 0,
  60. 0
  61. );
  62. }
  63. else
  64. {
  65. DebugPrintf(
  66. _TEXT("TSCertChangeCallback does not expect timeout...\n") );
  67. MYASSERT(FALSE);
  68. }
  69. }
  70. DWORD
  71. LoadTermSrvSecurityBlob()
  72. /*++
  73. Function to load TS machine specific identification blob, for now
  74. we use TS public key.
  75. --*/
  76. {
  77. DWORD dwStatus;
  78. PBYTE pbTSPublicKey = NULL;
  79. DWORD cbTSPublicKey = 0;
  80. DWORD dwType;
  81. DWORD cbData;
  82. BOOL bSuccess;
  83. BOOL bUsesX509PublicKey = FALSE;
  84. if( NULL == g_hTSCertificateRegKey )
  85. {
  86. MYASSERT(FALSE);
  87. dwStatus = ERROR_INTERNAL_ERROR;
  88. goto CLEANUPANDEXIT;
  89. }
  90. //
  91. // Make sure TS certificate is there before
  92. // we directly load public key from LSA
  93. //
  94. dwStatus = RegQueryValueEx(
  95. g_hTSCertificateRegKey,
  96. REGVALUE_TSX509_CERT,
  97. NULL,
  98. &dwType,
  99. NULL,
  100. &cbData
  101. );
  102. if( ERROR_SUCCESS == dwStatus )
  103. {
  104. DebugPrintf(
  105. _TEXT("TermSrv X509 certificate found, trying to load TS X509 public key\n")
  106. );
  107. cbTSPublicKey = 0;
  108. //
  109. // Current TLSAPI does not support retrival of
  110. // X509 certificate public key and TS cert is in
  111. // special format not standard x509 cert chain.
  112. //
  113. dwStatus = LsCsp_RetrieveSecret(
  114. LSA_TSX509_CERT_PUBLIC_KEY_NAME,
  115. NULL,
  116. &cbTSPublicKey
  117. );
  118. if( LICENSE_STATUS_OK != dwStatus &&
  119. LICENSE_STATUS_INSUFFICIENT_BUFFER != dwStatus )
  120. {
  121. MYASSERT( FALSE );
  122. goto CLEANUPANDEXIT;
  123. }
  124. pbTSPublicKey = (PBYTE)LocalAlloc( LPTR, cbTSPublicKey );
  125. if( NULL == pbTSPublicKey )
  126. {
  127. dwStatus = GetLastError();
  128. goto CLEANUPANDEXIT;
  129. }
  130. dwStatus = LsCsp_RetrieveSecret(
  131. LSA_TSX509_CERT_PUBLIC_KEY_NAME,
  132. pbTSPublicKey,
  133. &cbTSPublicKey
  134. );
  135. //
  136. // Critical error, We have certificate in registry
  137. // but don't have public key in LSA
  138. //
  139. MYASSERT( LICENSE_STATUS_OK == dwStatus );
  140. if( LICENSE_STATUS_OK != dwStatus )
  141. {
  142. DebugPrintf(
  143. _TEXT("TermSrv X509 certificate found but can't load X509 public key\n")
  144. );
  145. goto CLEANUPANDEXIT;
  146. }
  147. bUsesX509PublicKey = TRUE;
  148. }
  149. else
  150. {
  151. DebugPrintf(
  152. _TEXT("TermSrv X509 certificate not found\n")
  153. );
  154. //
  155. // Load pre-define TS public key
  156. //
  157. dwStatus = LsCsp_GetServerData(
  158. LsCspInfo_PublicKey,
  159. pbTSPublicKey,
  160. &cbTSPublicKey
  161. );
  162. // expecting insufficient buffer
  163. if( LICENSE_STATUS_INSUFFICIENT_BUFFER != dwStatus &&
  164. LICENSE_STATUS_OK != dwStatus )
  165. {
  166. // invalid return code.
  167. MYASSERT(FALSE);
  168. goto CLEANUPANDEXIT;
  169. }
  170. MYASSERT( cbTSPublicKey > 0 );
  171. pbTSPublicKey = (PBYTE)LocalAlloc( LPTR, cbTSPublicKey );
  172. if( NULL == pbTSPublicKey )
  173. {
  174. dwStatus = GetLastError();
  175. goto CLEANUPANDEXIT;
  176. }
  177. dwStatus = LsCsp_GetServerData(
  178. LsCspInfo_PublicKey,
  179. pbTSPublicKey,
  180. &cbTSPublicKey
  181. );
  182. if( LICENSE_STATUS_OK != dwStatus )
  183. {
  184. MYASSERT(FALSE);
  185. goto CLEANUPANDEXIT;
  186. }
  187. }
  188. if( ERROR_SUCCESS == dwStatus )
  189. {
  190. dwStatus = HashSecurityData(
  191. pbTSPublicKey,
  192. cbTSPublicKey,
  193. g_TSSecurityBlob
  194. );
  195. MYASSERT( ERROR_SUCCESS == dwStatus );
  196. MYASSERT( g_TSSecurityBlob.Length() > 0 );
  197. DebugPrintf(
  198. _TEXT("HashSecurityData() returns %d\n"), dwStatus
  199. );
  200. if( ERROR_SUCCESS != dwStatus )
  201. {
  202. goto CLEANUPANDEXIT;
  203. }
  204. }
  205. //
  206. // SRV, ADS, ... SKU uses seperate thread
  207. // to register with license server, so we use
  208. // different thread to receive certificate change notification.
  209. // Since TermSrv cached certificate, no reason to queue
  210. // notification once we successfully loaded tersrmv public key
  211. //
  212. if( !IsPersonalOrProMachine() && FALSE == bUsesX509PublicKey )
  213. {
  214. DebugPrintf(
  215. _TEXT("Setting up registry notification...\n")
  216. );
  217. MYASSERT( NULL != g_hTSCertificateChanged );
  218. ResetEvent(g_hTSCertificateChanged);
  219. // register a registry change notification
  220. // RegNotifyChangeKeyValue() only signal once.
  221. dwStatus = RegNotifyChangeKeyValue(
  222. g_hTSCertificateRegKey,
  223. TRUE,
  224. REG_NOTIFY_CHANGE_LAST_SET,
  225. g_hTSCertificateChanged,
  226. TRUE
  227. );
  228. if( ERROR_SUCCESS != dwStatus )
  229. {
  230. MYASSERT(FALSE);
  231. DebugPrintf(
  232. _TEXT("RegNotifyChangeKeyValue() returns %d\n"), dwStatus
  233. );
  234. goto CLEANUPANDEXIT;
  235. }
  236. if( NULL != g_hWaitTSCertificateChanged )
  237. {
  238. if( FALSE == UnregisterWait( g_hWaitTSCertificateChanged ) )
  239. {
  240. dwStatus = GetLastError();
  241. DebugPrintf(
  242. _TEXT("UnregisterWait() returns %d\n"),
  243. dwStatus
  244. );
  245. MYASSERT(FALSE);
  246. }
  247. g_hWaitTSCertificateChanged = NULL;
  248. }
  249. //
  250. // Queue notification to threadpool, we need to use WT_EXECUTEONLYONCE
  251. // since we are registering manual reset event.
  252. //
  253. bSuccess = RegisterWaitForSingleObject(
  254. &g_hWaitTSCertificateChanged,
  255. g_hTSCertificateChanged,
  256. (WAITORTIMERCALLBACK) TSCertChangeCallback,
  257. NULL,
  258. INFINITE,
  259. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE
  260. );
  261. if( FALSE == bSuccess )
  262. {
  263. dwStatus = GetLastError();
  264. DebugPrintf(
  265. _TEXT("RegisterWaitForSingleObject() returns %d\n"), dwStatus
  266. );
  267. }
  268. }
  269. CLEANUPANDEXIT:
  270. if( ERROR_SUCCESS != dwStatus )
  271. {
  272. //
  273. // TS either update its public key or key has change
  274. // and we failed to reload it, there is no reason to
  275. // to continue create help ticket since public key already
  276. /// mismatached, set service status and log error event
  277. //
  278. g_TSSecurityBlob.Empty();
  279. }
  280. if( NULL != pbTSPublicKey )
  281. {
  282. LocalFree(pbTSPublicKey);
  283. }
  284. return HRESULT_FROM_WIN32( dwStatus );
  285. }
  286. DWORD
  287. LoadAndSetupTSCertChangeNotification()
  288. {
  289. DWORD dwStatus;
  290. DWORD dwDisp;
  291. BOOL bSuccess;
  292. //
  293. // Only setup registry change notification if we
  294. // runs on higher SKU
  295. //
  296. g_hTSCertificateChanged = CreateEvent( NULL, TRUE, FALSE, NULL );
  297. if( NULL == g_hTSCertificateChanged )
  298. {
  299. dwStatus = GetLastError();
  300. goto CLEANUPANDEXIT;
  301. }
  302. //
  303. // Open parameters key under TermServices if key isn't
  304. // there, create it, this does not interfere with TermSrv
  305. // since we only create the reg. key not updating values
  306. // under it.
  307. //
  308. dwStatus = RegCreateKeyEx(
  309. HKEY_LOCAL_MACHINE,
  310. REGKEY_TSX509_CERT ,
  311. 0,
  312. NULL,
  313. REG_OPTION_NON_VOLATILE,
  314. KEY_WRITE | KEY_READ,
  315. NULL,
  316. &g_hTSCertificateRegKey,
  317. &dwDisp
  318. );
  319. if( ERROR_SUCCESS != dwStatus )
  320. {
  321. MYASSERT(FALSE);
  322. DebugPrintf(
  323. _TEXT("RegCreateKeyEx on %s failed with 0x%08x\n"),
  324. REGKEY_TSX509_CERT,
  325. dwStatus
  326. );
  327. goto CLEANUPANDEXIT;
  328. }
  329. //
  330. // Load security blob from TS, currently, we use TS public key
  331. // as security blob
  332. //
  333. dwStatus = LoadTermSrvSecurityBlob();
  334. if( ERROR_SUCCESS != dwStatus )
  335. {
  336. MYASSERT(FALSE);
  337. }
  338. CLEANUPANDEXIT:
  339. return dwStatus;
  340. }
  341. LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
  342. {
  343. while (p1 != NULL && *p1 != NULL)
  344. {
  345. LPCTSTR p = p2;
  346. while (p != NULL && *p != NULL)
  347. {
  348. if (*p1 == *p)
  349. return CharNext(p1);
  350. p = CharNext(p);
  351. }
  352. p1 = CharNext(p1);
  353. }
  354. return NULL;
  355. }
  356. void
  357. LogSetup(
  358. IN FILE* pfd,
  359. IN LPCTSTR format, ...
  360. )
  361. /*++
  362. Routine Description:
  363. sprintf() like wrapper around OutputDebugString().
  364. Parameters:
  365. hConsole : Handle to console.
  366. format : format string.
  367. Returns:
  368. None.
  369. Note:
  370. To be replace by generic tracing code.
  371. ++*/
  372. {
  373. TCHAR buf[8096]; // max. error text
  374. DWORD dump;
  375. va_list marker;
  376. va_start(marker, format);
  377. try {
  378. _vsntprintf(
  379. buf,
  380. sizeof(buf)/sizeof(buf[0])-1,
  381. format,
  382. marker
  383. );
  384. if( NULL == pfd )
  385. {
  386. OutputDebugString(buf);
  387. }
  388. else
  389. {
  390. _fputts( buf, pfd );
  391. fflush( pfd );
  392. }
  393. }
  394. catch(...) {
  395. }
  396. va_end(marker);
  397. return;
  398. }
  399. DWORD WINAPI
  400. NotifySessionLogoff(
  401. LPARAM pParm
  402. )
  403. /*++
  404. Routine Description:
  405. Routine to notified all currently loaded help that a user has
  406. logoff/disconnect from session, routine is kick off via thread pools'
  407. QueueUserWorkItem().
  408. Parameters:
  409. pContext : logoff or disconnected Session ID
  410. Returns:
  411. None.
  412. Note :
  413. We treat disconnect same as logoff since user might be actually
  414. active on the other session logged in with same credential, so
  415. we rely on resolver.
  416. --*/
  417. {
  418. DebugPrintf(_TEXT("NotifySessionLogoff() started...\n"));
  419. //
  420. // Tell service don't shutdown, we are in process.
  421. //
  422. _Module.AddRef();
  423. CRemoteDesktopHelpSessionMgr::NotifyHelpSesionLogoff( pParm );
  424. _Module.Release();
  425. return ERROR_SUCCESS;
  426. }
  427. /////////////////////////////////////////////////////////////////////////////
  428. void
  429. AddAccountToFilterList(
  430. LPCTSTR lpszAccountName
  431. )
  432. /*++
  433. Routine Description:
  434. Add HelpAssistant account into account filter list, this is temporary
  435. until we have long term solution.
  436. Parameters:
  437. lpszAccountName : Name of HelpAssistant account.
  438. Returns:
  439. None.
  440. Note:
  441. Account filter list is on
  442. HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList
  443. <name of SALEM account> REG_DWORD 0x00000000
  444. --*/
  445. {
  446. HKEY hKey = NULL;
  447. DWORD dwStatus;
  448. DWORD dwValue = 0;
  449. dwStatus = RegCreateKeyEx(
  450. HKEY_LOCAL_MACHINE,
  451. _TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList"),
  452. 0,
  453. NULL,
  454. REG_OPTION_NON_VOLATILE,
  455. KEY_ALL_ACCESS,
  456. NULL,
  457. &hKey,
  458. NULL
  459. );
  460. if( ERROR_SUCCESS == dwStatus )
  461. {
  462. dwStatus = RegSetValueEx(
  463. hKey,
  464. lpszAccountName,
  465. 0,
  466. REG_DWORD,
  467. (LPBYTE) &dwValue,
  468. sizeof(DWORD)
  469. );
  470. }
  471. //MYASSERT( ERROR_SUCCESS == dwStatus );
  472. if( NULL != hKey )
  473. {
  474. RegCloseKey( hKey );
  475. }
  476. return;
  477. }
  478. void
  479. CServiceModule::LogSessmgrEventLog(
  480. DWORD dwEventType,
  481. DWORD dwEventCode,
  482. CComBSTR& bstrNoviceDomain,
  483. CComBSTR& bstrNoviceAccount,
  484. CComBSTR& bstrRaType,
  485. CComBSTR& bstrExpertIPFromClient,
  486. CComBSTR& bstrExpertIPFromTS,
  487. DWORD dwErrCode
  488. )
  489. /*++
  490. Description:
  491. Log a Salem specific event log, this includes all event log in sessmgr.
  492. Parameters:
  493. dwEventCode : Event code.
  494. bstrNoviceDomain : Ticket owner's domain name.
  495. bstrNoviceAccount : Ticket owner's user account name.
  496. bstrExpertIPFromClient : Expert's IP address send from mstacax.
  497. bstrExpertIPFromTS : Expert IP address we query from TermSrv.
  498. dwErrCode : Error code.
  499. Returns:
  500. None.
  501. Note:
  502. Max. sessmgr specific log require at most 5 parameters but must
  503. contain novice domain, account name and also expert IP address
  504. send to mstscax and expert IP address we query from TermSrv.
  505. --*/
  506. {
  507. TCHAR szErrCode[256];
  508. LPCTSTR eventString[6];
  509. _stprintf( szErrCode, L"0x%x", dwErrCode );
  510. eventString[0] = (LPCTSTR)bstrNoviceDomain;
  511. eventString[1] = (LPCTSTR)bstrNoviceAccount;
  512. eventString[2] = (LPCTSTR)bstrRaType;
  513. eventString[3] = (LPCTSTR)bstrExpertIPFromClient;
  514. eventString[4] = (LPCTSTR)bstrExpertIPFromTS;
  515. eventString[5] = szErrCode;
  516. LogEventString(
  517. dwEventType,
  518. dwEventCode,
  519. sizeof(eventString)/sizeof(eventString[0]),
  520. eventString,
  521. sizeof(dwErrCode),
  522. &dwErrCode
  523. );
  524. return;
  525. }
  526. /////////////////////////////////////////////////////////////////////////////
  527. void
  528. CServiceModule::LogEventWithStatusCode(
  529. IN DWORD dwEventType,
  530. IN DWORD dwEventId,
  531. IN DWORD dwErrorCode
  532. )
  533. /*++
  534. --*/
  535. {
  536. TCHAR szErrCode[256];
  537. LPCTSTR eventString[1];
  538. eventString[0] = szErrCode;
  539. _stprintf( szErrCode, L"0x%x", dwErrorCode );
  540. LogEventString(
  541. dwEventType,
  542. dwEventId,
  543. 1,
  544. eventString
  545. );
  546. return;
  547. }
  548. /////////////////////////////////////////////////////////////////////////////
  549. void
  550. CServiceModule::LogInfoEvent(
  551. IN DWORD code
  552. )
  553. /*++
  554. --*/
  555. {
  556. LogEventString(
  557. EVENTLOG_INFORMATION_TYPE,
  558. code,
  559. 0,
  560. NULL
  561. );
  562. }
  563. /////////////////////////////////////////////////////////////////////////////
  564. void
  565. CServiceModule::LogWarningEvent(
  566. IN DWORD code
  567. )
  568. /*++
  569. --*/
  570. {
  571. LogEventString(
  572. EVENTLOG_WARNING_TYPE,
  573. code,
  574. 0,
  575. NULL
  576. );
  577. }
  578. /////////////////////////////////////////////////////////////////////////////
  579. void
  580. CServiceModule::LogErrorEvent(
  581. IN DWORD errCode
  582. )
  583. /*++
  584. --*/
  585. {
  586. LogEventString(
  587. EVENTLOG_ERROR_TYPE,
  588. errCode,
  589. 0,
  590. NULL
  591. );
  592. }
  593. /////////////////////////////////////////////////////////////////////////////
  594. void
  595. CServiceModule::LogEventString(
  596. IN DWORD dwEventType,
  597. IN DWORD dwEventId,
  598. IN DWORD wNumString,
  599. IN LPCTSTR* lpStrings,
  600. DWORD dwBinaryDataSize, /* 0 */
  601. LPVOID lpRawData /* NULL */
  602. )
  603. /*++
  604. --*/
  605. {
  606. HANDLE hAppLog=NULL;
  607. BOOL bSuccess=FALSE;
  608. WORD wElogType = (WORD) dwEventType;
  609. try {
  610. if(hAppLog=RegisterEventSource(NULL, m_szServiceDispName))
  611. {
  612. bSuccess = ReportEvent(
  613. hAppLog,
  614. wElogType,
  615. 0,
  616. dwEventId,
  617. NULL,
  618. (WORD)wNumString,
  619. dwBinaryDataSize,
  620. (const TCHAR **) lpStrings,
  621. lpRawData
  622. );
  623. DeregisterEventSource(hAppLog);
  624. }
  625. }
  626. catch(...) {
  627. }
  628. return;
  629. }
  630. inline HRESULT
  631. CServiceModule::SetupEventViewerSource(
  632. IN FILE* pSetupLog
  633. )
  634. /*++
  635. --*/
  636. {
  637. HKEY hKey = NULL;
  638. DWORD dwData;
  639. TCHAR szBuffer[MAX_PATH + 2];
  640. DWORD dwStatus;
  641. LogSetup( pSetupLog, L"Entering SetupEventViewerSource()...\n" );
  642. _stprintf(
  643. szBuffer,
  644. _TEXT("%s\\%s"),
  645. REGKEY_SYSTEM_EVENTSOURCE,
  646. m_szServiceDispName
  647. );
  648. // Add your source name as a subkey under the Application
  649. // key in the EventLog registry key.
  650. dwStatus = RegCreateKey(
  651. HKEY_LOCAL_MACHINE,
  652. szBuffer,
  653. &hKey
  654. );
  655. if( ERROR_SUCCESS != dwStatus )
  656. {
  657. LogSetup(
  658. pSetupLog,
  659. L"RegCreateKey() fail to create key %s with %d\n",
  660. szBuffer,
  661. dwStatus
  662. );
  663. goto CLEANUPANDEXIT;
  664. }
  665. dwStatus = GetModuleFileName(
  666. NULL,
  667. szBuffer,
  668. MAX_PATH+1
  669. );
  670. if( 0 == dwStatus )
  671. {
  672. LogSetup(
  673. pSetupLog,
  674. L"GetModuleFileName() failed with error code %s\n",
  675. dwStatus = GetLastError()
  676. );
  677. goto CLEANUPANDEXIT;
  678. }
  679. // Add the name to the EventMessageFile subkey.
  680. dwStatus = RegSetValueEx(
  681. hKey,
  682. L"EventMessageFile",
  683. 0,
  684. REG_SZ,
  685. (LPBYTE) szBuffer,
  686. (_tcslen(szBuffer)+1)*sizeof(TCHAR)
  687. );
  688. if( ERROR_SUCCESS != dwStatus )
  689. {
  690. LogSetup(
  691. pSetupLog,
  692. L"Failed to create EventMessageFile value, error code %d\n",
  693. dwStatus
  694. );
  695. goto CLEANUPANDEXIT;
  696. }
  697. // Set the supported event types in the TypesSupported subkey.
  698. dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
  699. dwStatus = RegSetValueEx(
  700. hKey,
  701. L"TypesSupported",
  702. 0,
  703. REG_DWORD,
  704. (LPBYTE) &dwData,
  705. sizeof(DWORD)
  706. );
  707. if( ERROR_SUCCESS != dwStatus )
  708. {
  709. LogSetup(
  710. pSetupLog,
  711. L"Failed to create TypesSupported value, error code %d\n",
  712. dwStatus
  713. );
  714. }
  715. CLEANUPANDEXIT:
  716. if( NULL != hKey )
  717. {
  718. RegCloseKey(hKey);
  719. }
  720. LogSetup(
  721. pSetupLog,
  722. L"Exiting SetupEventViewerSource() with status code %d...\n",
  723. dwStatus
  724. );
  725. return HRESULT_FROM_WIN32(dwStatus);
  726. }
  727. // Although some of these functions are big they are declared inline since they are only used once
  728. inline HRESULT
  729. CServiceModule::RegisterServer(FILE* pSetupLog, BOOL bRegTypeLib, BOOL bService)
  730. {
  731. CRegKey key;
  732. HRESULT hr;
  733. CRegKey keyAppID;
  734. LONG lRes;
  735. LogSetup(
  736. pSetupLog,
  737. L"\nEntering CServiceModule::RegisterServer %d, %d\n",
  738. bRegTypeLib,
  739. bService
  740. );
  741. hr = CoInitialize(NULL);
  742. if (FAILED(hr))
  743. {
  744. LogSetup( pSetupLog, L"CoInitialize() failed with 0x%08x\n", hr );
  745. goto CLEANUPANDEXIT;
  746. }
  747. // Remove any previous service since it may point to
  748. // the incorrect file
  749. //Uninstall();
  750. // Add service entries
  751. UpdateRegistryFromResource(IDR_Sessmgr, TRUE);
  752. // Adjust the AppID for Local Server or Service
  753. lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE);
  754. if (lRes != ERROR_SUCCESS)
  755. {
  756. LogSetup( pSetupLog, L"Open key AppID failed with %d\n", lRes );
  757. hr = HRESULT_FROM_WIN32(lRes);
  758. goto CLEANUPANDEXIT;
  759. }
  760. lRes = key.Open(keyAppID, _T("{038ABBA4-4138-4AC4-A492-4A3DF068BD8A}"), KEY_WRITE);
  761. if (lRes != ERROR_SUCCESS)
  762. {
  763. LogSetup( pSetupLog, L"Open key 038ABBA4-4138-4AC4-A492-4A3DF068BD8A failed with %d\n", lRes );
  764. hr = HRESULT_FROM_WIN32(lRes);
  765. goto CLEANUPANDEXIT;
  766. }
  767. key.DeleteValue(_T("LocalService"));
  768. if (bService)
  769. {
  770. LogSetup( pSetupLog, L"Installing service...\n" );
  771. BOOL bInstallSuccess;
  772. key.SetValue(m_szServiceName, _T("LocalService"));
  773. key.SetValue(_T("-Service"), _T("ServiceParameters"));
  774. if( IsInstalled(pSetupLog) )
  775. {
  776. // update service description.
  777. bInstallSuccess = UpdateService( pSetupLog );
  778. }
  779. else
  780. {
  781. //
  782. // Create service
  783. //
  784. bInstallSuccess = Install(pSetupLog);
  785. }
  786. if( FALSE == bInstallSuccess )
  787. {
  788. LogSetup( pSetupLog, L"Install or update service description failed %d\n", GetLastError() );
  789. MYASSERT( FALSE );
  790. hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);
  791. }
  792. else
  793. {
  794. LogSetup( pSetupLog, L"successfully installing service...\n" );
  795. if( IsInstalled(pSetupLog) == FALSE )
  796. {
  797. LogSetup( pSetupLog, L"IsInstalled() return FALSE after Install()\n" );
  798. MYASSERT(FALSE);
  799. hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);
  800. }
  801. SetupEventViewerSource(pSetupLog);
  802. }
  803. }
  804. if( SUCCEEDED(hr) )
  805. {
  806. // Add object entries
  807. hr = CComModule::RegisterServer(bRegTypeLib);
  808. if( FAILED(hr) )
  809. {
  810. LogSetup( pSetupLog, L"CComModule::RegisterServer() on type library failed with 0x%08x\n", hr );
  811. }
  812. }
  813. CoUninitialize();
  814. CLEANUPANDEXIT:
  815. LogSetup( pSetupLog, L"Leaving CServiceModule::RegisterServer 0x%08x\n", hr );
  816. return hr;
  817. }
  818. inline HRESULT CServiceModule::UnregisterServer(FILE* pSetupLog)
  819. {
  820. LogSetup( pSetupLog, L"\nEntering CServiceModule::UnregisterServer\n" );
  821. HRESULT hr = CoInitialize(NULL);
  822. if (FAILED(hr))
  823. {
  824. LogSetup( pSetupLog, L"CoInitialize() failed with 0x%08x\n", hr );
  825. goto CLEANUPANDEXIT;
  826. }
  827. // Remove service entries
  828. UpdateRegistryFromResource(IDR_Sessmgr, FALSE);
  829. // Remove service
  830. Uninstall(pSetupLog);
  831. // Remove object entries
  832. CComModule::UnregisterServer(TRUE);
  833. CoUninitialize();
  834. CLEANUPANDEXIT:
  835. LogSetup( pSetupLog, L"Leaving CServiceModule::UnregisterServer() - 0x%08x\n", hr );
  836. return S_OK;
  837. }
  838. inline void
  839. CServiceModule::Init(
  840. _ATL_OBJMAP_ENTRY* p,
  841. HINSTANCE h,
  842. UINT nServiceNameID,
  843. UINT nServiceDispNameID,
  844. UINT nServiceDescID,
  845. const GUID* plibid
  846. )
  847. /*++
  848. ATL Wizard generated code
  849. --*/
  850. {
  851. CComModule::Init(p, h, plibid);
  852. m_bService = TRUE;
  853. m_dwServiceStartupStatus = ERROR_SUCCESS;
  854. LoadString(h, nServiceNameID, m_szServiceName, sizeof(m_szServiceName) / sizeof(TCHAR));
  855. LoadString(h, nServiceDescID, m_szServiceDesc, sizeof(m_szServiceDesc) / sizeof(TCHAR));
  856. LoadString(h, nServiceDispNameID, m_szServiceDispName, sizeof(m_szServiceDispName)/sizeof(TCHAR));
  857. // set up the initial service status
  858. m_hServiceStatus = NULL;
  859. m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  860. m_status.dwCurrentState = SERVICE_STOPPED;
  861. m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SESSIONCHANGE;
  862. m_status.dwWin32ExitCode = 0;
  863. m_status.dwServiceSpecificExitCode = 0;
  864. m_status.dwCheckPoint = 0;
  865. m_status.dwWaitHint = 0;
  866. }
  867. LONG CServiceModule::Unlock()
  868. {
  869. LONG l = CComModule::Unlock();
  870. if (l == 0 && !m_bService)
  871. PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
  872. return l;
  873. }
  874. BOOL CServiceModule::IsInstalled(FILE* pSetupLog)
  875. {
  876. LogSetup( pSetupLog, L"\nEntering CServiceModule::IsInstalled()\n" );
  877. BOOL bResult = FALSE;
  878. SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  879. if (hSCM != NULL)
  880. {
  881. SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_QUERY_CONFIG);
  882. if (hService != NULL)
  883. {
  884. LogSetup( pSetupLog, L"OpenService() Succeeded\n" );
  885. bResult = TRUE;
  886. ::CloseServiceHandle(hService);
  887. }
  888. else
  889. {
  890. LogSetup( pSetupLog, L"OpenService() failed with %d\n", GetLastError() );
  891. }
  892. ::CloseServiceHandle(hSCM);
  893. }
  894. else
  895. {
  896. LogSetup( pSetupLog, L"OpenSCManager() failed with %d\n", GetLastError() );
  897. }
  898. LogSetup( pSetupLog, L"Leaving IsInstalled() - %d\n", bResult );
  899. return bResult;
  900. }
  901. inline BOOL CServiceModule::UpdateService(FILE* pSetupLog)
  902. {
  903. DWORD dwStatus = ERROR_SUCCESS;
  904. SERVICE_DESCRIPTION serviceDesc;
  905. SC_HANDLE hSCM = NULL;
  906. SC_HANDLE hService = NULL;
  907. LogSetup( pSetupLog, L"\nEntering CServiceModule::UpdateServiceDescription()...\n" );
  908. hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  909. if (hSCM == NULL)
  910. {
  911. dwStatus = GetLastError();
  912. LogSetup( pSetupLog, L"OpenSCManager() failed with %d\n", dwStatus );
  913. goto CLEANUPANDEXIT;
  914. }
  915. hService = ::OpenService( hSCM, m_szServiceName, SERVICE_CHANGE_CONFIG );
  916. if (hService == NULL)
  917. {
  918. dwStatus = GetLastError();
  919. LogSetup( pSetupLog, L"OpenService() failed with %d\n", dwStatus );
  920. goto CLEANUPANDEXIT;
  921. }
  922. serviceDesc.lpDescription = (LPTSTR)m_szServiceDesc;
  923. if( FALSE == ChangeServiceConfig2( hService, SERVICE_CONFIG_DESCRIPTION, (LPVOID)&serviceDesc ) )
  924. {
  925. dwStatus = GetLastError();
  926. LogSetup( pSetupLog, L"ChangeServiceConfig2() failed with %d\n", dwStatus );
  927. MYASSERT( ERROR_SUCCESS == dwStatus );
  928. }
  929. //
  930. // Performance : Set service to be demand start for upgrade
  931. //
  932. if( FALSE == ChangeServiceConfig(
  933. hService,
  934. SERVICE_NO_CHANGE,
  935. SERVICE_DEMAND_START,
  936. SERVICE_NO_CHANGE,
  937. NULL,
  938. NULL,
  939. NULL,
  940. NULL,
  941. NULL,
  942. NULL,
  943. m_szServiceDispName
  944. ) )
  945. {
  946. dwStatus = GetLastError();
  947. LogSetup( pSetupLog, L"ChangeServiceConfig() failed with %d\n", dwStatus );
  948. MYASSERT( ERROR_SUCCESS == dwStatus );
  949. }
  950. CLEANUPANDEXIT:
  951. if( NULL != hService )
  952. {
  953. ::CloseServiceHandle(hService);
  954. }
  955. if( NULL != hSCM )
  956. {
  957. ::CloseServiceHandle(hSCM);
  958. }
  959. LogSetup( pSetupLog, L"Leaving UpdateServiceDescription::Install() - %d\n", dwStatus );
  960. return dwStatus == ERROR_SUCCESS;
  961. }
  962. inline BOOL CServiceModule::Install(FILE* pSetupLog)
  963. {
  964. DWORD dwStatus = ERROR_SUCCESS;
  965. SERVICE_DESCRIPTION serviceDesc;
  966. SC_HANDLE hSCM;
  967. TCHAR szFilePath[_MAX_PATH];
  968. SC_HANDLE hService;
  969. LogSetup( pSetupLog, L"\nEntering CServiceModule::Install()...\n" );
  970. if (IsInstalled(pSetupLog))
  971. {
  972. LogSetup( pSetupLog, L"Service already installed\n" );
  973. dwStatus = ERROR_SUCCESS;
  974. goto CLEANUPANDEXIT;
  975. }
  976. hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  977. if (hSCM == NULL)
  978. {
  979. dwStatus = GetLastError();
  980. LogSetup( pSetupLog, L"OpenSCManager() failed with %d\n", dwStatus );
  981. goto CLEANUPANDEXIT;
  982. }
  983. // Get the executable file path
  984. ::GetModuleFileName(NULL, szFilePath, _MAX_PATH);
  985. hService = ::CreateService(
  986. hSCM,
  987. m_szServiceName,
  988. m_szServiceDispName,
  989. SERVICE_ALL_ACCESS,
  990. SERVICE_WIN32_OWN_PROCESS,
  991. SERVICE_DEMAND_START,
  992. SERVICE_ERROR_NORMAL,
  993. szFilePath,
  994. NULL,
  995. NULL,
  996. _T("RPCSS\0"),
  997. NULL,
  998. NULL
  999. );
  1000. if (hService == NULL)
  1001. {
  1002. dwStatus = GetLastError();
  1003. LogSetup( pSetupLog, L"CreateService() failed with %d\n", dwStatus );
  1004. ::CloseServiceHandle(hSCM);
  1005. goto CLEANUPANDEXIT;
  1006. }
  1007. serviceDesc.lpDescription = (LPTSTR)m_szServiceDesc;
  1008. if( FALSE == ChangeServiceConfig2( hService, SERVICE_CONFIG_DESCRIPTION, (LPVOID)&serviceDesc ) )
  1009. {
  1010. dwStatus = GetLastError();
  1011. LogSetup( pSetupLog, L"ChangeServiceConfig2() failed with %d\n", dwStatus );
  1012. MYASSERT( ERROR_SUCCESS == dwStatus );
  1013. }
  1014. ::CloseServiceHandle(hService);
  1015. ::CloseServiceHandle(hSCM);
  1016. CLEANUPANDEXIT:
  1017. LogSetup( pSetupLog, L"Leaving CServiceModule::Install() - %d\n", dwStatus );
  1018. return dwStatus == ERROR_SUCCESS;
  1019. }
  1020. inline BOOL CServiceModule::Uninstall(FILE* pSetupLog)
  1021. {
  1022. BOOL bStatus = TRUE;
  1023. SC_HANDLE hService;
  1024. SC_HANDLE hSCM;
  1025. SERVICE_STATUS status;
  1026. LogSetup( pSetupLog, L"\nEntering CServiceModule::Uninstall()...\n" );
  1027. if (!IsInstalled(pSetupLog))
  1028. {
  1029. LogSetup( pSetupLog, L"Service is not installed...\n" );
  1030. goto CLEANUPANDEXIT;
  1031. }
  1032. hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  1033. if (hSCM == NULL)
  1034. {
  1035. LogSetup( pSetupLog, L"OpenSCManager() failed with %d\n", GetLastError() );
  1036. bStatus = FALSE;
  1037. goto CLEANUPANDEXIT;
  1038. }
  1039. hService = ::OpenService(hSCM, m_szServiceName, SERVICE_STOP | DELETE);
  1040. if (hService == NULL)
  1041. {
  1042. ::CloseServiceHandle(hSCM);
  1043. LogSetup( pSetupLog, L"OpenService() failed with %d\n", GetLastError() );
  1044. bStatus = FALSE;
  1045. goto CLEANUPANDEXIT;
  1046. }
  1047. ::ControlService(hService, SERVICE_CONTROL_STOP, &status);
  1048. bStatus = ::DeleteService(hService);
  1049. if( FALSE == bStatus )
  1050. {
  1051. LogSetup( pSetupLog, L"DeleteService() failed with %d\n", GetLastError() );
  1052. }
  1053. ::CloseServiceHandle(hService);
  1054. ::CloseServiceHandle(hSCM);
  1055. CLEANUPANDEXIT:
  1056. LogSetup( pSetupLog, L"Leaving CServiceModule::Uninstall()\n" );
  1057. return bStatus;
  1058. }
  1059. //////////////////////////////////////////////////////////////////////////////////////////////
  1060. // Service startup and registration
  1061. inline void CServiceModule::Start()
  1062. {
  1063. SERVICE_TABLE_ENTRY st[] =
  1064. {
  1065. { m_szServiceName, _ServiceMain },
  1066. { NULL, NULL }
  1067. };
  1068. if (m_bService && !::StartServiceCtrlDispatcher(st))
  1069. {
  1070. m_bService = FALSE;
  1071. }
  1072. if (m_bService == FALSE)
  1073. Run();
  1074. }
  1075. inline void CServiceModule::ServiceMain(DWORD /* dwArgc */, LPTSTR* /* lpszArgv */)
  1076. {
  1077. // Register the control request handler
  1078. m_status.dwCurrentState = SERVICE_START_PENDING;
  1079. m_hServiceStatus = RegisterServiceCtrlHandlerEx(m_szServiceName, HandlerEx, this);
  1080. if (m_hServiceStatus == NULL)
  1081. {
  1082. //LogEvent(_T("Handler not installed"));
  1083. return;
  1084. }
  1085. m_status.dwWin32ExitCode = S_OK;
  1086. m_status.dwCheckPoint = 0;
  1087. m_status.dwWaitHint = SERVICE_STARTUP_WAITHINT;
  1088. SetServiceStatus(SERVICE_START_PENDING);
  1089. // When the Run function returns, the service has stopped.
  1090. Run();
  1091. SetServiceStatus(SERVICE_STOPPED);
  1092. }
  1093. inline void CServiceModule::Handler(DWORD dwOpcode)
  1094. {
  1095. switch (dwOpcode)
  1096. {
  1097. case SERVICE_CONTROL_STOP:
  1098. SetServiceStatus(SERVICE_STOP_PENDING);
  1099. if( PostThreadMessage(dwThreadID, WM_QUIT, 0, 0) == FALSE )
  1100. {
  1101. DWORD dwStatus = GetLastError();
  1102. }
  1103. break;
  1104. case SERVICE_CONTROL_PAUSE:
  1105. break;
  1106. case SERVICE_CONTROL_CONTINUE:
  1107. break;
  1108. case SERVICE_CONTROL_INTERROGATE:
  1109. break;
  1110. case SERVICE_CONTROL_SHUTDOWN:
  1111. break;
  1112. //default:
  1113. // LogEvent(_T("Bad service request"));
  1114. }
  1115. }
  1116. inline DWORD WINAPI
  1117. CServiceModule::HandlerEx(
  1118. DWORD dwControl,
  1119. DWORD dwEventType,
  1120. LPVOID lpEventData,
  1121. LPVOID lpContext
  1122. )
  1123. /*++
  1124. --*/
  1125. {
  1126. DWORD dwRetCode;
  1127. switch (dwControl)
  1128. {
  1129. case SERVICE_CONTROL_STOP:
  1130. case SERVICE_CONTROL_PAUSE:
  1131. case SERVICE_CONTROL_CONTINUE:
  1132. case SERVICE_CONTROL_INTERROGATE:
  1133. case SERVICE_CONTROL_SHUTDOWN:
  1134. dwRetCode = NO_ERROR;
  1135. _Handler(dwControl);
  1136. break;
  1137. #if DISABLESECURITYCHECKS
  1138. // this is require for Salem Unit test, we need to update
  1139. // user session status but for pcHealth, resolver will
  1140. // always popup invitation dialog so no need to track
  1141. // user session status.
  1142. case SERVICE_CONTROL_SESSIONCHANGE:
  1143. MYASSERT( NULL != lpEventData );
  1144. if( NULL != lpEventData )
  1145. {
  1146. switch( dwEventType )
  1147. {
  1148. case WTS_SESSION_LOGON:
  1149. DebugPrintf(
  1150. _TEXT("Session %d has log on...\n"),
  1151. ((WTSSESSION_NOTIFICATION *)lpEventData)->dwSessionId
  1152. );
  1153. break;
  1154. case WTS_SESSION_LOGOFF:
  1155. case WTS_CONSOLE_DISCONNECT:
  1156. case WTS_REMOTE_DISCONNECT:
  1157. DebugPrintf(
  1158. _TEXT("Session %d has log off...\n"),
  1159. ((WTSSESSION_NOTIFICATION *)lpEventData)->dwSessionId
  1160. );
  1161. //
  1162. // Deadlock if we use other thread to process logoff or
  1163. // disconnect.
  1164. //
  1165. // Notification thread lock pending help table and need
  1166. // to run Resolver in COM, COM is in the middle of
  1167. // dispatching create help ticket call which also need
  1168. // lock to pending help table, this causes deadlock
  1169. //
  1170. PostThreadMessage(
  1171. _Module.dwThreadID,
  1172. WM_SESSIONLOGOFFDISCONNECT,
  1173. 0,
  1174. (LPARAM)((WTSSESSION_NOTIFICATION *)lpEventData)->dwSessionId
  1175. );
  1176. }
  1177. }
  1178. dwRetCode = NO_ERROR;
  1179. break;
  1180. #endif
  1181. default:
  1182. dwRetCode = ERROR_CALL_NOT_IMPLEMENTED;
  1183. }
  1184. return dwRetCode;
  1185. }
  1186. void WINAPI CServiceModule::_ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
  1187. {
  1188. _Module.ServiceMain(dwArgc, lpszArgv);
  1189. }
  1190. void WINAPI CServiceModule::_Handler(DWORD dwOpcode)
  1191. {
  1192. _Module.Handler(dwOpcode);
  1193. }
  1194. void CServiceModule::SetServiceStatus(DWORD dwState)
  1195. {
  1196. m_status.dwCurrentState = dwState;
  1197. ::SetServiceStatus(m_hServiceStatus, &m_status);
  1198. }
  1199. HANDLE CServiceModule::gm_hIdle = NULL;
  1200. HANDLE CServiceModule::gm_hIdleMonitorThread = NULL;
  1201. HANDLE CServiceModule::gm_hICSAlertEvent = NULL;
  1202. unsigned __stdcall
  1203. StartupInitThread( void* ptr )
  1204. {
  1205. HRESULT hRes = S_OK;
  1206. DWORD dwErrCode = ERROR_SUCCESS;
  1207. hRes = g_HelpSessTable.OpenSessionTable(NULL);
  1208. if( SUCCEEDED(hRes) )
  1209. {
  1210. CRemoteDesktopHelpSessionMgr::NotifyPendingHelpServiceStartup();
  1211. }
  1212. else
  1213. {
  1214. dwErrCode = SESSMGR_E_HELPSESSIONTABLE;
  1215. }
  1216. if( FAILED(hRes) )
  1217. {
  1218. _Module.LogEventWithStatusCode(
  1219. EVENTLOG_ERROR_TYPE,
  1220. dwErrCode,
  1221. hRes
  1222. );
  1223. hRes = dwErrCode;
  1224. }
  1225. _endthreadex( hRes );
  1226. return hRes;
  1227. }
  1228. ULONG
  1229. CServiceModule::AddRef()
  1230. {
  1231. CCriticalSectionLocker l( m_Locks );
  1232. m_RefCount++;
  1233. if( m_RefCount > 0 )
  1234. {
  1235. ResetEvent( gm_hIdle );
  1236. }
  1237. return m_RefCount;
  1238. }
  1239. ULONG
  1240. CServiceModule::Release()
  1241. {
  1242. CCriticalSectionLocker l( m_Locks );
  1243. m_RefCount--;
  1244. if( m_RefCount <= 0 )
  1245. {
  1246. // Only signal idle when there is no more pending help
  1247. if( g_HelpSessTable.NumEntries() == 0 )
  1248. {
  1249. SetEvent( gm_hIdle );
  1250. }
  1251. }
  1252. return m_RefCount;
  1253. }
  1254. unsigned int WINAPI
  1255. CServiceModule::IdleMonitorThread( void* ptr )
  1256. {
  1257. DWORD dwStatus = ERROR_SUCCESS;
  1258. CServiceModule* pServiceModule = (CServiceModule *)ptr;
  1259. HANDLE hWaitHandles[] = {gm_hICSAlertEvent, gm_hIdle};
  1260. CoInitialize(NULL);
  1261. if( pServiceModule != NULL )
  1262. {
  1263. while (TRUE)
  1264. {
  1265. dwStatus = WaitForMultipleObjects(
  1266. sizeof( hWaitHandles ) / sizeof( hWaitHandles[0] ),
  1267. hWaitHandles,
  1268. FALSE,
  1269. EXPIRE_HELPSESSION_PERIOD
  1270. );
  1271. if( WAIT_TIMEOUT == dwStatus )
  1272. {
  1273. // expire help ticket, refer to session logoff/disconnect
  1274. // comment above on why PostThreadMessage.
  1275. PostThreadMessage(
  1276. _Module.dwThreadID,
  1277. WM_EXPIREHELPSESSION,
  1278. 0,
  1279. 0
  1280. );
  1281. }
  1282. else if( WAIT_OBJECT_0 == dwStatus )
  1283. {
  1284. // ICS has signal us something has changed.
  1285. ResetEvent( gm_hICSAlertEvent );
  1286. }
  1287. else if( WAIT_OBJECT_0 + 1 == dwStatus )
  1288. {
  1289. // we have been idel for too long, time to try shutdown.
  1290. // idle event will only be signal when there is no
  1291. // pending help so we don't have to worry about address
  1292. // changes.
  1293. Sleep( IDLE_SHUTDOWN_PERIOD );
  1294. dwStatus = WaitForSingleObject( gm_hIdle, 0 );
  1295. if( WAIT_OBJECT_0 == dwStatus )
  1296. {
  1297. // no one holding object, time to shutdown
  1298. dwStatus = ERROR_SUCCESS;
  1299. break;
  1300. }
  1301. }
  1302. else if( WAIT_FAILED == dwStatus )
  1303. {
  1304. // some bad thing happen, shutdown.
  1305. //MYASSERT(FALSE);
  1306. break;
  1307. }
  1308. }
  1309. }
  1310. // TOBE enable with ICS work
  1311. //pServiceModule->LogInfoEvent( SESSMGR_I_SERVICE_IDLESTOP );
  1312. pServiceModule->Handler(SERVICE_CONTROL_STOP);
  1313. CoUninitialize();
  1314. _endthreadex( dwStatus );
  1315. return dwStatus;
  1316. }
  1317. BOOL
  1318. CServiceModule::InitializeSessmgr()
  1319. {
  1320. CCriticalSectionLocker l( m_Locks );
  1321. //
  1322. // Already initialize.
  1323. //
  1324. if( m_Initialized )
  1325. {
  1326. return TRUE;
  1327. }
  1328. //
  1329. // Service failed to startup, just return without initialize
  1330. // anything
  1331. //
  1332. if( !_Module.IsSuccessServiceStartup() )
  1333. {
  1334. return FALSE;
  1335. }
  1336. DWORD dwStatus;
  1337. unsigned int junk;
  1338. //
  1339. // Start ICSHELPER library.
  1340. //
  1341. dwStatus = StartICSLib();
  1342. if( ERROR_SUCCESS != dwStatus )
  1343. {
  1344. // Log an error event, we still need to startup
  1345. // so that we can report error back to caller
  1346. LogEventWithStatusCode(
  1347. EVENTLOG_ERROR_TYPE,
  1348. SESSMGR_E_ICSHELPER,
  1349. dwStatus
  1350. );
  1351. _Module.m_dwServiceStartupStatus = SESSMGR_E_ICSHELPER;
  1352. }
  1353. else
  1354. {
  1355. CRemoteDesktopHelpSessionMgr::NotifyPendingHelpServiceStartup();
  1356. }
  1357. m_Initialized = TRUE;
  1358. return _Module.IsSuccessServiceStartup();
  1359. }
  1360. void CServiceModule::Run()
  1361. {
  1362. //
  1363. // Mark we are not initialized yet...
  1364. //
  1365. m_Initialized = FALSE;
  1366. _Module.dwThreadID = GetCurrentThreadId();
  1367. DWORD dwStatus;
  1368. unsigned int dwJunk;
  1369. WSADATA wsData;
  1370. ISAFRemoteDesktopCallback* pIResolver = NULL;
  1371. LPWSTR pszSysAccName = NULL;
  1372. DWORD cbSysAccName = 0;
  1373. LPWSTR pszSysDomainName = NULL;
  1374. DWORD cbSysDomainName = 0;
  1375. SID_NAME_USE SidType;
  1376. HRESULT hr;
  1377. //
  1378. // **** DO NOT CHANGE SEQUENCE ****
  1379. //
  1380. // Refer to XP RAID 407457 for detail
  1381. //
  1382. // A thread named SessMgr!DpNatHlpThread is calling into dpnhupnp.dll,
  1383. // which is doing COM-related stuff, this is happening before the
  1384. // sessmgr!CServiceModule__Run method calls CoInitializeSecurity.
  1385. // When you do COM stuff before calling CoInitSec, COM do it for you,
  1386. // and you end up accepting the defaults
  1387. //
  1388. hr = g_HelpAccount.Initialize();
  1389. if( FAILED(hr) )
  1390. {
  1391. dwStatus = SESSMGR_E_HELPACCOUNT;
  1392. LogEventWithStatusCode(
  1393. EVENTLOG_ERROR_TYPE,
  1394. SESSMGR_E_GENERALSTARTUP,
  1395. hr
  1396. );
  1397. _Module.m_dwServiceStartupStatus = SESSMGR_E_HELPACCOUNT;
  1398. MYASSERT(FALSE);
  1399. }
  1400. hr = LoadLocalSystemSID();
  1401. if( FAILED(hr) )
  1402. {
  1403. LogEventWithStatusCode(
  1404. EVENTLOG_ERROR_TYPE,
  1405. SESSMGR_E_GENERALSTARTUP,
  1406. hr
  1407. );
  1408. _Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
  1409. MYASSERT(FALSE);
  1410. }
  1411. //
  1412. // We always need to startup otherwise will cause caller to timeout
  1413. // or AV.
  1414. //
  1415. hr = CoInitialize(NULL);
  1416. // If you are running on NT 4.0 or higher you can use the following call
  1417. // instead to make the EXE free threaded.
  1418. // This means that calls come in on a random RPC thread
  1419. // HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1420. _ASSERTE(SUCCEEDED(hr));
  1421. CSecurityDescriptor sd;
  1422. sd.InitializeFromThreadToken(); // get a default DACL
  1423. #ifndef DISABLESECURITYCHECKS
  1424. if( _Module.IsSuccessServiceStartup() )
  1425. {
  1426. BOOL bSuccess;
  1427. CComBSTR bstrHelpAccName;
  1428. //
  1429. // Retrieve System account name, might not be necessary since this
  1430. // pre-defined account shouldn't be localizable.
  1431. //
  1432. pszSysAccName = NULL;
  1433. cbSysAccName = 0;
  1434. pszSysDomainName = NULL;
  1435. cbSysDomainName = 0;
  1436. bSuccess = LookupAccountSid(
  1437. NULL,
  1438. g_pSidSystem,
  1439. pszSysAccName,
  1440. &cbSysAccName,
  1441. pszSysDomainName,
  1442. &cbSysDomainName,
  1443. &SidType
  1444. );
  1445. if( TRUE == bSuccess ||
  1446. ERROR_INSUFFICIENT_BUFFER == GetLastError() )
  1447. {
  1448. pszSysAccName = (LPWSTR) LocalAlloc( LPTR, (cbSysAccName + 1) * sizeof(WCHAR) );
  1449. pszSysDomainName = (LPWSTR) LocalAlloc( LPTR, (cbSysDomainName + 1) * sizeof(WCHAR) );
  1450. if( NULL != pszSysAccName && NULL != pszSysDomainName )
  1451. {
  1452. bSuccess = LookupAccountSid(
  1453. NULL,
  1454. g_pSidSystem,
  1455. pszSysAccName,
  1456. &cbSysAccName,
  1457. pszSysDomainName,
  1458. &cbSysDomainName,
  1459. &SidType
  1460. );
  1461. if( TRUE == bSuccess )
  1462. {
  1463. hr = sd.Allow( pszSysAccName, COM_RIGHTS_EXECUTE );
  1464. }
  1465. }
  1466. }
  1467. if( FALSE == bSuccess )
  1468. {
  1469. dwStatus = GetLastError();
  1470. hr = HRESULT_FROM_WIN32( dwStatus );
  1471. MYASSERT( SUCCEEDED(hr) );
  1472. }
  1473. //
  1474. // Add access permission to help assistant account
  1475. if( SUCCEEDED(hr) )
  1476. {
  1477. //
  1478. // Allow access to HelpAssistant account
  1479. //
  1480. hr = g_HelpAccount.GetHelpAccountNameEx( bstrHelpAccName );
  1481. if( SUCCEEDED(hr) )
  1482. {
  1483. hr = sd.Allow( (LPCTSTR)bstrHelpAccName, COM_RIGHTS_EXECUTE );
  1484. MYASSERT( SUCCEEDED(hr) );
  1485. }
  1486. }
  1487. //
  1488. // If we failed in setting DACL, we still need to startup but without
  1489. // full security, however, our interface will fail because service
  1490. // does not initialize correctly.
  1491. //
  1492. if( FAILED(hr) )
  1493. {
  1494. LogEventWithStatusCode(
  1495. EVENTLOG_ERROR_TYPE,
  1496. SESSMGR_E_RESTRICTACCESS,
  1497. hr
  1498. );
  1499. _Module.m_dwServiceStartupStatus = SESSMGR_E_RESTRICTACCESS;
  1500. }
  1501. }
  1502. #endif
  1503. //
  1504. // We still need to startup or client might behave weird; interface call
  1505. // will be block by checking service startup status.
  1506. //
  1507. hr = CoInitializeSecurity(
  1508. sd,
  1509. -1,
  1510. NULL,
  1511. NULL,
  1512. RPC_C_AUTHN_LEVEL_PKT,
  1513. RPC_C_IMP_LEVEL_IMPERSONATE,
  1514. NULL,
  1515. EOAC_NONE,
  1516. NULL
  1517. );
  1518. _ASSERTE(SUCCEEDED(hr));
  1519. hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
  1520. _ASSERTE(SUCCEEDED(hr));
  1521. //
  1522. // Load unknown string for event loggging
  1523. //
  1524. g_UnknownString.LoadString( IDS_UNKNOWN );
  1525. //
  1526. // Load RA and URA string for event log
  1527. //
  1528. g_RAString.LoadString( IDS_RA_STRING );
  1529. g_URAString.LoadString( IDS_URA_STRING );
  1530. if( _Module.IsSuccessServiceStartup() )
  1531. {
  1532. //
  1533. // Startup TLSAPI in order to get public key
  1534. //
  1535. dwStatus = TLSInit();
  1536. if( LICENSE_STATUS_OK != dwStatus )
  1537. {
  1538. LogEventWithStatusCode(
  1539. EVENTLOG_ERROR_TYPE,
  1540. SESSMGR_E_GENERALSTARTUP,
  1541. dwStatus
  1542. );
  1543. _Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
  1544. MYASSERT(FALSE);
  1545. }
  1546. }
  1547. if( _Module.IsSuccessServiceStartup() )
  1548. {
  1549. //
  1550. // Load TermSrv public key, on PRO/PER we load public key from
  1551. // non-x509 certificate, on other SKU, we register a registry change
  1552. // notification and post ourself a message regarding public key
  1553. // change.
  1554. //
  1555. dwStatus = LoadAndSetupTSCertChangeNotification();
  1556. MYASSERT( ERROR_SUCCESS == dwStatus );
  1557. if( ERROR_SUCCESS != dwStatus )
  1558. {
  1559. // Log an error event, we still need to startup
  1560. // so that we can report error back to caller
  1561. LogEventWithStatusCode(
  1562. EVENTLOG_ERROR_TYPE,
  1563. SESSMGR_E_GENERALSTARTUP,
  1564. dwStatus
  1565. );
  1566. _Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
  1567. }
  1568. }
  1569. if( _Module.IsSuccessServiceStartup() )
  1570. {
  1571. //
  1572. // Create an event for ICS to signal us
  1573. // any address change
  1574. //
  1575. gm_hICSAlertEvent = CreateEvent(
  1576. NULL,
  1577. TRUE,
  1578. FALSE,
  1579. NULL
  1580. );
  1581. if( NULL == gm_hICSAlertEvent )
  1582. {
  1583. LogEventWithStatusCode(
  1584. EVENTLOG_ERROR_TYPE,
  1585. SESSMGR_E_GENERALSTARTUP,
  1586. GetLastError()
  1587. );
  1588. _Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
  1589. MYASSERT(FALSE);
  1590. }
  1591. }
  1592. if( _Module.IsSuccessServiceStartup() )
  1593. {
  1594. //
  1595. // Initialize encryption library
  1596. //
  1597. dwStatus = TSHelpAssistantInitializeEncryptionLib();
  1598. if( ERROR_SUCCESS != dwStatus )
  1599. {
  1600. // Log an error event, we still need to startup
  1601. // so that we can report error back to caller
  1602. LogEventWithStatusCode(
  1603. EVENTLOG_ERROR_TYPE,
  1604. SESSMGR_E_INIT_ENCRYPTIONLIB,
  1605. dwStatus
  1606. );
  1607. _Module.m_dwServiceStartupStatus = SESSMGR_E_INIT_ENCRYPTIONLIB;
  1608. MYASSERT(FALSE);
  1609. }
  1610. }
  1611. if( _Module.IsSuccessServiceStartup() )
  1612. {
  1613. //
  1614. // startup WSA so we can invoke gethostname()
  1615. // critical error if we can startup WSA
  1616. if( WSAStartup(0x0101, &wsData) != 0 )
  1617. {
  1618. // Log an error event, we still need to startup
  1619. // so that we can report error back to caller
  1620. LogEventWithStatusCode(
  1621. EVENTLOG_ERROR_TYPE,
  1622. SESSMGR_E_WSASTARTUP,
  1623. GetLastError()
  1624. );
  1625. _Module.m_dwServiceStartupStatus = SESSMGR_E_WSASTARTUP;
  1626. }
  1627. }
  1628. if( _Module.IsSuccessServiceStartup() )
  1629. {
  1630. hr = g_HelpSessTable.OpenSessionTable(NULL);
  1631. if( FAILED(hr) )
  1632. {
  1633. LogEventWithStatusCode(
  1634. EVENTLOG_ERROR_TYPE,
  1635. SESSMGR_E_HELPSESSIONTABLE,
  1636. hr
  1637. );
  1638. _Module.m_dwServiceStartupStatus = SESSMGR_E_HELPSESSIONTABLE;
  1639. MYASSERT(FALSE);
  1640. }
  1641. }
  1642. if( _Module.IsSuccessServiceStartup() )
  1643. {
  1644. //
  1645. // Service might startup from system restore, re-setup HelpAssistant account
  1646. // settings
  1647. if( g_HelpSessTable.NumEntries() == 0)
  1648. {
  1649. g_HelpAccount.EnableHelpAssistantAccount(FALSE);
  1650. g_HelpAccount.EnableRemoteInteractiveRight(FALSE);
  1651. }
  1652. else
  1653. {
  1654. //
  1655. // make sure HelpAssistant account is enabled and can logon locally
  1656. //
  1657. g_HelpAccount.EnableHelpAssistantAccount(TRUE);
  1658. g_HelpAccount.EnableRemoteInteractiveRight(TRUE);
  1659. g_HelpAccount.SetupHelpAccountTSSettings();
  1660. }
  1661. //
  1662. // Create an manual reset event for background thread to terminate
  1663. // service
  1664. //
  1665. gm_hIdle = CreateEvent(
  1666. NULL,
  1667. TRUE,
  1668. (g_HelpSessTable.NumEntries() == 0) ? TRUE : FALSE,
  1669. NULL
  1670. );
  1671. if( NULL == gm_hIdle )
  1672. {
  1673. LogEventWithStatusCode(
  1674. EVENTLOG_ERROR_TYPE,
  1675. SESSMGR_E_GENERALSTARTUP,
  1676. GetLastError()
  1677. );
  1678. _Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
  1679. MYASSERT(FALSE);
  1680. }
  1681. // Create nackground thread thread
  1682. gm_hIdleMonitorThread = (HANDLE)_beginthreadex(
  1683. NULL,
  1684. 0,
  1685. IdleMonitorThread,
  1686. (HANDLE)this,
  1687. 0,
  1688. &dwJunk
  1689. );
  1690. if( NULL == gm_hIdleMonitorThread )
  1691. {
  1692. _Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
  1693. }
  1694. }
  1695. //LogEvent(_T("Service started"));
  1696. if (m_bService)
  1697. SetServiceStatus(SERVICE_RUNNING);
  1698. // TOBE enable with ICS work
  1699. //LogInfoEvent(SESSMGR_I_SERVICE_START);
  1700. //
  1701. // Load resolver, this will put one ref. count on it
  1702. // so it won't got unload until we are done.
  1703. //
  1704. hr = CoCreateInstance(
  1705. SESSIONRESOLVERCLSID,
  1706. NULL,
  1707. CLSCTX_SERVER,
  1708. IID_ISAFRemoteDesktopCallback,
  1709. (void **)&pIResolver
  1710. );
  1711. MYASSERT( SUCCEEDED(hr) );
  1712. if( FAILED(hr) )
  1713. {
  1714. //
  1715. // Can't initialize session resolver,
  1716. // session resolver will not be able to
  1717. // do caching.
  1718. //
  1719. LogEventWithStatusCode(
  1720. EVENTLOG_WARNING_TYPE,
  1721. SESSMGR_E_SESSIONRESOLVER,
  1722. hr
  1723. );
  1724. _Module.m_dwServiceStartupStatus = SESSMGR_E_SESSIONRESOLVER;
  1725. }
  1726. else
  1727. {
  1728. //
  1729. // Create global interface table
  1730. //
  1731. hr = InitializeGlobalInterfaceTable();
  1732. if( SUCCEEDED(hr) )
  1733. {
  1734. //
  1735. // register resolver interface with GIT, resolver has some
  1736. // data structure that depends on single instance.
  1737. //
  1738. hr = RegisterResolverWithGIT(pIResolver);
  1739. }
  1740. if( FAILED(hr) )
  1741. {
  1742. //
  1743. // Not critical, Resolver function is disabled.
  1744. LogEventWithStatusCode(
  1745. EVENTLOG_WARNING_TYPE,
  1746. SESSMGR_E_REGISTERSESSIONRESOLVER,
  1747. hr
  1748. );
  1749. _Module.m_dwServiceStartupStatus = SESSMGR_E_REGISTERSESSIONRESOLVER;
  1750. }
  1751. }
  1752. MSG msg;
  1753. while (GetMessage(&msg, 0, 0, 0))
  1754. {
  1755. switch( msg.message )
  1756. {
  1757. case WM_EXPIREHELPSESSION:
  1758. DebugPrintf(_TEXT("Executing TimeoutHelpSesion()...\n"));
  1759. CRemoteDesktopHelpSessionMgr::TimeoutHelpSesion();
  1760. break;
  1761. case WM_SESSIONLOGOFFDISCONNECT:
  1762. DebugPrintf(_TEXT("Executing NotifySessionLogoff() %d...\n"), msg.lParam);
  1763. NotifySessionLogoff( msg.lParam );
  1764. break;
  1765. case WM_LOADTSPUBLICKEY:
  1766. DebugPrintf( _TEXT("Executing LoadTermSrvSecurityBlob() ...\n") );
  1767. dwStatus = LoadTermSrvSecurityBlob();
  1768. if( ERROR_SUCCESS != dwStatus )
  1769. {
  1770. // Log an error event, we still need to startup
  1771. // so that we can report error back to caller
  1772. LogEventWithStatusCode(
  1773. EVENTLOG_ERROR_TYPE,
  1774. SESSMGR_E_GENERALSTARTUP,
  1775. dwStatus
  1776. );
  1777. _Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
  1778. }
  1779. break;
  1780. case WM_HELPERRDSADDINEXIT:
  1781. DebugPrintf( _TEXT("WM_HELPERRDSADDINEXIT()...\n") );
  1782. CRemoteDesktopHelpSessionMgr::NotifyExpertLogoff( msg.wParam, (BSTR)msg.lParam );
  1783. break;
  1784. default:
  1785. DispatchMessage(&msg);
  1786. }
  1787. }
  1788. CleanupMonitorExpertList();
  1789. if( g_hWaitTSCertificateChanged )
  1790. {
  1791. UnregisterWait( g_hWaitTSCertificateChanged );
  1792. g_hWaitTSCertificateChanged = NULL;
  1793. }
  1794. if( g_hTSCertificateChanged )
  1795. {
  1796. CloseHandle( g_hTSCertificateChanged );
  1797. g_hTSCertificateChanged = NULL;
  1798. }
  1799. if( g_hTSCertificateRegKey )
  1800. {
  1801. RegCloseKey( g_hTSCertificateRegKey );
  1802. g_hTSCertificateRegKey = NULL;
  1803. }
  1804. //
  1805. //
  1806. if( NULL != pIResolver )
  1807. {
  1808. pIResolver->Release();
  1809. }
  1810. _Module.RevokeClassObjects();
  1811. // TOBE enable with ICS work
  1812. //LogInfoEvent(SESSMGR_I_SERVICE_STOP);
  1813. CoUninitialize();
  1814. if( NULL != gm_hIdle )
  1815. {
  1816. CloseHandle( gm_hIdle );
  1817. }
  1818. if( WSACleanup() != 0 )
  1819. {
  1820. // shutting down, ignore WSA error
  1821. #if DBG
  1822. OutputDebugString( _TEXT("WSACleanup() failed...\n") );
  1823. #endif
  1824. }
  1825. #if DBG
  1826. OutputDebugString( _TEXT("Help Session Manager Exited...\n") );
  1827. #endif
  1828. // Close the help session table, help session table
  1829. // open by init. thread
  1830. g_HelpSessTable.CloseSessionTable();
  1831. // Stop ICS library, ignore error code.
  1832. StopICSLib();
  1833. TSHelpAssistantEndEncryptionLib();
  1834. UnInitializeGlobalInterfaceTable();
  1835. if( NULL != pszSysAccName )
  1836. {
  1837. LocalFree( pszSysAccName );
  1838. }
  1839. if( NULL != pszSysDomainName )
  1840. {
  1841. LocalFree( pszSysDomainName );
  1842. }
  1843. TLSShutdown();
  1844. }
  1845. HRESULT
  1846. CreatePendingHelpTable(
  1847. FILE* pSetupLog
  1848. )
  1849. /*++
  1850. Routine to create pending help table registry key, if registry key already exist,
  1851. set the DACL to system context only.
  1852. --*/
  1853. {
  1854. PACL pAcl=NULL;
  1855. DWORD dwStatus = ERROR_SUCCESS;
  1856. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  1857. DWORD cbAcl = 0;
  1858. PSID pSidSystem = NULL;
  1859. HKEY hKey = NULL;
  1860. LogSetup( pSetupLog, L"\nEntering CreatePendingHelpTable\n" );
  1861. pSecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, sizeof(SECURITY_DESCRIPTOR));
  1862. if( NULL == pSecurityDescriptor )
  1863. {
  1864. LogSetup( pSetupLog, L"Can't alloc memory for SECURITY_DESCRIPTOR\n" );
  1865. dwStatus = GetLastError();
  1866. goto CLEANUPANDEXIT;
  1867. }
  1868. //
  1869. // Initialize the security descriptor.
  1870. //
  1871. if (!InitializeSecurityDescriptor(
  1872. pSecurityDescriptor,
  1873. SECURITY_DESCRIPTOR_REVISION
  1874. ))
  1875. {
  1876. dwStatus = GetLastError();
  1877. LogSetup( pSetupLog, L"InitializeSecurityDescriptor() failed with %d\n", dwStatus );
  1878. goto CLEANUPANDEXIT;
  1879. }
  1880. dwStatus = CreateSystemSid( &pSidSystem );
  1881. if( ERROR_SUCCESS != dwStatus )
  1882. {
  1883. LogSetup( pSetupLog, L"CreateSystemSid() failed with %d\n", dwStatus );
  1884. goto CLEANUPANDEXIT;
  1885. }
  1886. cbAcl = GetLengthSid( pSidSystem ) + sizeof(ACL) + (2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
  1887. pAcl = (PACL) LocalAlloc( LPTR, cbAcl );
  1888. if( NULL == pAcl )
  1889. {
  1890. LogSetup( pSetupLog, L"Can't alloc memory for ACL\n" );
  1891. dwStatus = GetLastError();
  1892. goto CLEANUPANDEXIT;
  1893. }
  1894. //
  1895. // Initialize the ACL.
  1896. //
  1897. if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION))
  1898. {
  1899. dwStatus = GetLastError();
  1900. LogSetup( pSetupLog, L"InitializeAcl() failed with error code %d\n", dwStatus );
  1901. goto CLEANUPANDEXIT;
  1902. }
  1903. //
  1904. if (!AddAccessAllowedAce(pAcl,
  1905. ACL_REVISION,
  1906. GENERIC_READ | GENERIC_WRITE | GENERIC_ALL,
  1907. pSidSystem
  1908. ))
  1909. {
  1910. dwStatus = GetLastError();
  1911. LogSetup( pSetupLog, L"AddAccessAllowedAce() failed with error code %d\n", dwStatus );
  1912. goto CLEANUPANDEXIT;
  1913. }
  1914. if (!SetSecurityDescriptorDacl(pSecurityDescriptor,
  1915. TRUE, pAcl, FALSE))
  1916. {
  1917. dwStatus = GetLastError();
  1918. LogSetup( pSetupLog, L"SetSecurityDescriptorDacl() failed with error code %d\n", dwStatus );
  1919. goto CLEANUPANDEXIT;
  1920. }
  1921. //
  1922. // Create/open the pending table registry key
  1923. //
  1924. dwStatus = RegCreateKeyEx(
  1925. HKEY_LOCAL_MACHINE,
  1926. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
  1927. 0,
  1928. NULL,
  1929. REG_OPTION_NON_VOLATILE,
  1930. KEY_ALL_ACCESS,
  1931. NULL,
  1932. &hKey,
  1933. NULL
  1934. );
  1935. if( ERROR_SUCCESS != dwStatus )
  1936. {
  1937. LogSetup( pSetupLog, L"RegCreateKeyEx() failed with error code %d\n", dwStatus );
  1938. goto CLEANUPANDEXIT;
  1939. }
  1940. //
  1941. // Set table (registry) DACL
  1942. //
  1943. dwStatus = RegSetKeySecurity(
  1944. hKey,
  1945. DACL_SECURITY_INFORMATION,
  1946. pSecurityDescriptor
  1947. );
  1948. if( ERROR_SUCCESS != dwStatus )
  1949. {
  1950. LogSetup( pSetupLog, L"RegSetKeySecurity() failed with error code %d\n", dwStatus );
  1951. }
  1952. CLEANUPANDEXIT:
  1953. if( NULL != hKey )
  1954. {
  1955. RegCloseKey(hKey);
  1956. }
  1957. if( pAcl != NULL )
  1958. {
  1959. LocalFree(pAcl);
  1960. }
  1961. if( pSecurityDescriptor != NULL )
  1962. {
  1963. LocalFree( pSecurityDescriptor );
  1964. }
  1965. if( pSidSystem != NULL )
  1966. {
  1967. FreeSid( pSidSystem );
  1968. }
  1969. LogSetup( pSetupLog, L"CreatePendingHelpTable() return %d\n", dwStatus );
  1970. return HRESULT_FROM_WIN32(dwStatus);
  1971. }
  1972. void
  1973. UpgradeSessmgr(
  1974. FILE* pSetupLog
  1975. )
  1976. /*++
  1977. Routine to upgrade session manager
  1978. --*/
  1979. {
  1980. LogSetup( pSetupLog, L"\nEntering UpgradeSessmgr\n" );
  1981. //
  1982. // Migrate fAllowToGetHelp policy in HKLM\Software\Microsoft\Remote Desktop\Policies
  1983. // to termsrv so listening thread can look at single place.
  1984. //
  1985. DWORD dwValue;
  1986. DWORD dwStatus;
  1987. DWORD dwSize;
  1988. DWORD dwType;
  1989. HKEY hKey;
  1990. BOOL bUpgradeFromB1 = FALSE;
  1991. LogSetup( pSetupLog, L"Setting policy registry key\n" );
  1992. //
  1993. // Open TS registry key under HKLM\System\CurrentControlSet\Control\Terminal Serv...
  1994. //
  1995. dwStatus = RegOpenKeyEx(
  1996. HKEY_LOCAL_MACHINE,
  1997. REG_CONTROL_GETHELP,
  1998. 0,
  1999. KEY_READ | KEY_WRITE,
  2000. &hKey
  2001. );
  2002. if( ERROR_SUCCESS == dwStatus )
  2003. {
  2004. dwStatus = GetPolicyAllowGetHelpSetting(
  2005. HKEY_LOCAL_MACHINE,
  2006. OLD_REG_CONTROL_GETHELP,
  2007. RDS_ALLOWGETHELP_VALUENAME,
  2008. &dwValue
  2009. );
  2010. if( ERROR_SUCCESS == dwStatus )
  2011. {
  2012. LogSetup( pSetupLog, L"B1 policy value %d\n", dwValue );
  2013. //
  2014. // Delete the old policy key, ignore error.
  2015. //
  2016. RegDelKey( HKEY_LOCAL_MACHINE, OLD_REG_CONTROL_GETHELP );
  2017. //
  2018. // This value exists in old Salem policy key, system must be
  2019. // upgrading from B1.
  2020. //
  2021. dwStatus = RegSetValueEx(
  2022. hKey,
  2023. RDS_ALLOWGETHELP_VALUENAME,
  2024. 0,
  2025. REG_DWORD,
  2026. (PBYTE)&dwValue,
  2027. sizeof(dwValue)
  2028. );
  2029. bUpgradeFromB1 = TRUE;
  2030. }
  2031. else
  2032. {
  2033. LogSetup( pSetupLog, L"B1 policy key does not exist\n" );
  2034. dwSize = sizeof(dwValue);
  2035. //
  2036. // Upgrade from B2 and beyond, check to see if fAllowToGetHelp exist
  2037. // if not, set it to 1.
  2038. //
  2039. dwStatus = RegQueryValueEx(
  2040. hKey,
  2041. RDS_ALLOWGETHELP_VALUENAME,
  2042. 0,
  2043. &dwType,
  2044. (PBYTE)&dwValue,
  2045. &dwSize
  2046. );
  2047. if( ERROR_FILE_NOT_FOUND == dwStatus || REG_DWORD != dwType )
  2048. {
  2049. //
  2050. // default is not allow to get help if
  2051. // value does not exist.
  2052. //
  2053. dwValue = 1;
  2054. dwStatus = RegSetValueEx(
  2055. hKey,
  2056. RDS_ALLOWGETHELP_VALUENAME,
  2057. 0,
  2058. REG_DWORD,
  2059. (PBYTE)&dwValue,
  2060. sizeof(dwValue)
  2061. );
  2062. }
  2063. else
  2064. {
  2065. LogSetup( pSetupLog, L"Existing fAllowToGetHelp Policy value %d\n", dwValue );
  2066. }
  2067. }
  2068. LogSetup( pSetupLog, L"Setting fAllowGetHelp policy key result - %d\n", dwStatus );
  2069. RegCloseKey( hKey );
  2070. }
  2071. else
  2072. {
  2073. LogSetup(
  2074. pSetupLog,
  2075. L"Can't open registry key %s, error code %d\n",
  2076. REG_CONTROL_GETHELP,
  2077. dwStatus
  2078. );
  2079. }
  2080. if( TRUE == bUpgradeFromB1 )
  2081. {
  2082. //
  2083. // B1, help assistant account password is clear text, this will fix the
  2084. // security leak.
  2085. //
  2086. LogSetup( pSetupLog, L"Upgrade from B1, delete all pending help and reset account password\n" );
  2087. RegDelKey(
  2088. HKEY_LOCAL_MACHINE,
  2089. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
  2090. );
  2091. g_HelpAccount.ResetHelpAccountPassword();
  2092. }
  2093. LogSetup( pSetupLog, L"Leaving UpgradeSessmgr\n" );
  2094. return;
  2095. }
  2096. #define UNINSTALL_BEFORE_INSTALL _TEXT("UninstallBeforeInstall")
  2097. HRESULT
  2098. InstallUninstallSessmgr(
  2099. DWORD code
  2100. )
  2101. /*++
  2102. --*/
  2103. {
  2104. FILE* pSetupLog;
  2105. TCHAR LogFile[MAX_PATH+1];
  2106. HRESULT hRes = S_OK;
  2107. DWORD dwStatus = ERROR_SUCCESS;
  2108. HKEY hKey = NULL;
  2109. DWORD dwValue = 1;
  2110. DWORD dwType;
  2111. DWORD cbData = sizeof(dwValue);
  2112. GetWindowsDirectory( LogFile, MAX_PATH );
  2113. lstrcat( LogFile, L"\\" );
  2114. lstrcat( LogFile, SETUPLOGFILE_NAME );
  2115. pSetupLog = _tfopen( LogFile, L"a+t" );
  2116. MYASSERT( NULL != pSetupLog );
  2117. LogSetup( pSetupLog, L"\n\n********* Install/uninstall sessmgr service *********\n" );
  2118. //
  2119. // no checking on return, if failure, we just do OutputDebugString();
  2120. //
  2121. switch( code )
  2122. {
  2123. case SESSMGR_UNREGSERVER:
  2124. {
  2125. LogSetup( pSetupLog, L"Uninstalling sessmgr service\n" );
  2126. //
  2127. // Delete all pending help session.
  2128. //
  2129. dwStatus = RegDelKey(
  2130. HKEY_LOCAL_MACHINE,
  2131. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
  2132. );
  2133. LogSetup( pSetupLog, L"Delete pending table return %d\n", dwStatus );
  2134. //
  2135. // We might not be running in system context so deleting registry and
  2136. // cleanup LSA key will fail, write a key to our control location to
  2137. // mark such that delete everything before install
  2138. //
  2139. dwStatus = RegOpenKeyEx(
  2140. HKEY_LOCAL_MACHINE,
  2141. REGKEYCONTROL_REMDSK,
  2142. 0,
  2143. KEY_ALL_ACCESS,
  2144. &hKey
  2145. );
  2146. if( ERROR_SUCCESS == dwStatus )
  2147. {
  2148. dwStatus = RegSetValueEx(
  2149. hKey,
  2150. UNINSTALL_BEFORE_INSTALL,
  2151. 0,
  2152. REG_DWORD,
  2153. (BYTE *) &dwValue,
  2154. sizeof(dwValue)
  2155. );
  2156. if( ERROR_SUCCESS != dwStatus )
  2157. {
  2158. LogSetup( pSetupLog, L"Failed to set value, error code %d\n", dwStatus );
  2159. MYASSERT(FALSE);
  2160. }
  2161. RegCloseKey( hKey );
  2162. }
  2163. else
  2164. {
  2165. // This is OK since we havn't been install before.
  2166. LogSetup( pSetupLog, L"Failed to open control key, error code %d\n", dwStatus );
  2167. }
  2168. //
  2169. // Initialize to get help account name.
  2170. //
  2171. hRes = g_HelpAccount.Initialize();
  2172. LogSetup( pSetupLog, L"Initialize help account return 0x%08x\n", hRes );
  2173. //
  2174. // ignore error, try to delete the account
  2175. hRes = g_HelpAccount.DeleteHelpAccount();
  2176. LogSetup( pSetupLog, L"Delete help account return 0x%08x\n", hRes );
  2177. MYASSERT( SUCCEEDED(hRes) );
  2178. hRes = _Module.UnregisterServer(pSetupLog);
  2179. LogSetup( pSetupLog, L"UnregisterServer() returns 0x%08x\n", hRes );
  2180. if( ERROR_SUCCESS == StartICSLib() )
  2181. {
  2182. // Non-critical if we can't startup the lib since after we shutdown,
  2183. // we would have close all the port
  2184. CloseAllOpenPorts();
  2185. StopICSLib();
  2186. }
  2187. }
  2188. break;
  2189. case SESSMGR_REGSERVER:
  2190. {
  2191. LogSetup( pSetupLog, L"Installing as non-service\n" );
  2192. #if DBG
  2193. AddAccountToFilterList( HELPASSISTANTACCOUNT_NAME );
  2194. MYASSERT( ERROR_SUCCESS == g_HelpAccount.CreateHelpAccount() ) ;
  2195. hRes = _Module.RegisterServer(pSetupLog, TRUE, FALSE);
  2196. #else
  2197. hRes = E_INVALIDARG;
  2198. #endif
  2199. }
  2200. break;
  2201. //case SESSMGR_UPGRADE:
  2202. //
  2203. // TODO - ICS work, add upgrade special code.
  2204. //
  2205. case SESSMGR_SERVICE:
  2206. {
  2207. LogSetup( pSetupLog, L"Installing sessmgr service\n" );
  2208. hRes = S_OK;
  2209. //
  2210. // Clean up again, we might not be running in system
  2211. // context at the time of uninstall so clean up will failed.
  2212. //
  2213. dwStatus = RegOpenKeyEx(
  2214. HKEY_LOCAL_MACHINE,
  2215. REGKEYCONTROL_REMDSK,
  2216. 0,
  2217. KEY_ALL_ACCESS,
  2218. &hKey
  2219. );
  2220. if( ERROR_SUCCESS == dwStatus )
  2221. {
  2222. //
  2223. // Check to see if previous uninstall failed,
  2224. // we only need to check value exists.
  2225. //
  2226. dwStatus = RegQueryValueEx(
  2227. hKey,
  2228. UNINSTALL_BEFORE_INSTALL,
  2229. 0,
  2230. &dwType,
  2231. (BYTE *) &dwValue,
  2232. &cbData
  2233. );
  2234. if( ERROR_SUCCESS != dwStatus || REG_DWORD != dwType )
  2235. {
  2236. //
  2237. // No previous uninstall information, no need to delete anything
  2238. //
  2239. LogSetup( pSetupLog, L"UninstallBeforeInstall value not found or invalid, code %d\n", dwStatus );
  2240. }
  2241. else
  2242. {
  2243. LogSetup( pSetupLog, L"UninstallBeforeInstall exists, cleanup previous uninstall\n" );
  2244. //
  2245. // Previous uninstall failed, delete all pending help session,
  2246. // and clean up encryption key
  2247. //
  2248. dwStatus = RegDelKey(
  2249. HKEY_LOCAL_MACHINE,
  2250. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
  2251. );
  2252. //
  2253. // It's OK to fail here since we reset encryption key making existing
  2254. // ticket useless and will be deleted on expire.
  2255. //
  2256. LogSetup( pSetupLog, L"Delete pending table return %d\n", dwStatus );
  2257. dwStatus = TSHelpAssistantInitializeEncryptionLib();
  2258. if( ERROR_SUCCESS == dwStatus )
  2259. {
  2260. dwStatus = TSHelpAssisantEndEncryptionCycle();
  2261. if( ERROR_SUCCESS != dwStatus )
  2262. {
  2263. LogSetup( pSetupLog, L"TSHelpAssisantEndEncryptionCycle() returns 0x%08x\n", dwStatus );
  2264. LogSetup( pSetupLog, L"sessmgr setup can't continue\n" );
  2265. // Critical security error, existing ticket might still be valid
  2266. hRes = HRESULT_FROM_WIN32( dwStatus );
  2267. }
  2268. TSHelpAssistantEndEncryptionLib();
  2269. }
  2270. else
  2271. {
  2272. LogSetup( pSetupLog, L"TSHelpAssistantInitializeEncryptionLib return %d\n", dwStatus );
  2273. LogSetup( pSetupLog, L"sessmgr setup can't continue\n" );
  2274. // Critical security error, existing ticket might still be valid
  2275. hRes = HRESULT_FROM_WIN32( dwStatus );
  2276. }
  2277. }
  2278. if( SUCCEEDED(hRes) )
  2279. {
  2280. //
  2281. // Delete reg. value to uninstall before install only when successfully
  2282. // resetting encryption key
  2283. //
  2284. RegDeleteValue( hKey, UNINSTALL_BEFORE_INSTALL );
  2285. }
  2286. RegCloseKey( hKey );
  2287. }
  2288. if( SUCCEEDED(hRes) )
  2289. {
  2290. hRes = g_HelpAccount.CreateHelpAccount();
  2291. if( SUCCEEDED(hRes) )
  2292. {
  2293. CComBSTR bstrHelpAccName;
  2294. hRes = g_HelpAccount.GetHelpAccountNameEx( bstrHelpAccName );
  2295. MYASSERT( SUCCEEDED(hRes) );
  2296. if( FAILED(hRes) )
  2297. {
  2298. // not a critical error, we can still use help
  2299. LogSetup( pSetupLog, L"Failed to retrieve HelpAssistantaccount name - 0x%08x\n", hRes );
  2300. }
  2301. else
  2302. {
  2303. LogSetup( pSetupLog, L"HelpAssistant account name - %s\n", bstrHelpAccName );
  2304. // Add HelpAssistantAccount into account filter list
  2305. AddAccountToFilterList( bstrHelpAccName );
  2306. }
  2307. //
  2308. // Two type of SP install, one thru SP1 installer and the other is
  2309. // normal NT setup including all SP fixes.
  2310. // We disable account on setup and let service startup to re-enable it
  2311. //
  2312. g_HelpAccount.EnableHelpAssistantAccount(FALSE);
  2313. //
  2314. // Upgrade session manager
  2315. //
  2316. UpgradeSessmgr(pSetupLog);
  2317. LogSetup( pSetupLog, L"Successfully setup account\n" );
  2318. hRes = _Module.RegisterServer(pSetupLog, TRUE, TRUE);
  2319. if( FAILED(hRes) )
  2320. {
  2321. LogSetup( pSetupLog, L"Failed to register/installing service - 0x%08x\n", hRes );
  2322. }
  2323. }
  2324. else
  2325. {
  2326. LogSetup( pSetupLog, L"Creating Help Assistant account failed with 0x%08x\n", hRes );
  2327. (void) g_HelpAccount.DeleteHelpAccount();
  2328. hRes = E_FAIL;
  2329. }
  2330. }
  2331. if( SUCCEEDED(hRes) )
  2332. {
  2333. hRes = CreatePendingHelpTable(pSetupLog);
  2334. if( FAILED(hRes) )
  2335. {
  2336. LogSetup(
  2337. pSetupLog,
  2338. L"CreatePendingHelpTable() failed - 0x%08x\n",
  2339. hRes
  2340. );
  2341. }
  2342. }
  2343. }
  2344. break;
  2345. default:
  2346. LogSetup( pSetupLog, L"Invalid setup operation %d\n", code );
  2347. hRes = E_UNEXPECTED;
  2348. }
  2349. LogSetup( pSetupLog, L"\n*** Finish Setup with Status 0x%08x ***\n", hRes );
  2350. if( pSetupLog )
  2351. {
  2352. fflush( pSetupLog );
  2353. fclose( pSetupLog);
  2354. }
  2355. return hRes;
  2356. }
  2357. /////////////////////////////////////////////////////////////////////////////
  2358. //
  2359. extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
  2360. HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
  2361. {
  2362. HRESULT hRes;
  2363. CComBSTR bstrErrMsg;
  2364. CComBSTR bstrServiceDesc;
  2365. DWORD dwStatus;
  2366. lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
  2367. _Module.Init(ObjectMap, hInstance, IDS_SERVICENAME, IDS_SERVICEDISPLAYNAME, IDS_SERVICEDESC, &LIBID_RDSESSMGRLib);
  2368. _Module.m_bService = TRUE;
  2369. TCHAR szTokens[] = _T("-/");
  2370. //
  2371. // We don't do OS version checking as in Win9x case, some of our
  2372. // call uses API not exists on Win9x so will get unresolve
  2373. // reference when running on Win9x box.
  2374. //
  2375. bstrServiceDesc.LoadString( IDS_SERVICEDISPLAYNAME );
  2376. LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);
  2377. while (lpszToken != NULL)
  2378. {
  2379. if (lstrcmpi(lpszToken, _T("UnregServer"))==0)
  2380. {
  2381. return InstallUninstallSessmgr( SESSMGR_UNREGSERVER );
  2382. }
  2383. else if (lstrcmpi(lpszToken, _T("RegServer"))==0)
  2384. {
  2385. return InstallUninstallSessmgr( SESSMGR_REGSERVER );
  2386. }
  2387. else if (lstrcmpi(lpszToken, _T("Service"))==0)
  2388. {
  2389. return InstallUninstallSessmgr( SESSMGR_SERVICE );
  2390. }
  2391. else if ( lstrcmpi(lpszToken, _T("SP1Upgrade"))==0)
  2392. {
  2393. // BUGL 602653, HelpAssistant account is not disable at clean install
  2394. // disable account here and let service start up to re-enable.
  2395. return EnableLocalAccount( HELPASSISTANTACCOUNT_NAME, FALSE );
  2396. }
  2397. lpszToken = FindOneOf(lpszToken, szTokens);
  2398. }
  2399. // Are we Service or Local Server
  2400. CRegKey keyAppID;
  2401. LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_READ);
  2402. if (lRes != ERROR_SUCCESS)
  2403. {
  2404. _Module.LogErrorEvent( SESSMGR_E_SETUP );
  2405. return lRes;
  2406. }
  2407. CRegKey key;
  2408. lRes = key.Open(keyAppID, _T("{038ABBA4-4138-4AC4-A492-4A3DF068BD8A}"), KEY_READ);
  2409. if (lRes != ERROR_SUCCESS)
  2410. {
  2411. _Module.LogErrorEvent( SESSMGR_E_SETUP );
  2412. return lRes;
  2413. }
  2414. TCHAR szValue[_MAX_PATH];
  2415. DWORD dwLen = _MAX_PATH;
  2416. lRes = key.QueryValue(szValue, _T("LocalService"), &dwLen);
  2417. _Module.m_bService = FALSE;
  2418. if (lRes == ERROR_SUCCESS)
  2419. _Module.m_bService = TRUE;
  2420. _Module.Start();
  2421. // When we get here, the service has been stopped
  2422. return _Module.m_status.dwWin32ExitCode;
  2423. }