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.

977 lines
28 KiB

  1. /****************************************************************************/
  2. // icasrv.c
  3. //
  4. // TermSrv service process entry points.
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. #include <objbase.h>
  11. #include "icaevent.h"
  12. #include "sessdir.h"
  13. #include <safeboot.h>
  14. extern BOOL UpdateOemAndProductInfo(HKEY);
  15. extern BOOL IsServiceLoggedAsSystem( VOID );
  16. extern VOID WriteErrorLogEntry(
  17. IN NTSTATUS NtStatusCode,
  18. IN PVOID pRawData,
  19. IN ULONG RawDataLength
  20. );
  21. extern NTSTATUS WinStationInitRPC();
  22. extern NTSTATUS InitializeWinStationSecurityLock(VOID);
  23. extern VOID AuditEnd();
  24. /*
  25. * Definitions
  26. */
  27. #define STACKSIZE_LPCTHREAD (4 * 0x1000)
  28. /*
  29. * Internal Procedures defined
  30. */
  31. VOID ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
  32. VOID Handler(DWORD fdwControl);
  33. BOOL UpdateServiceStatus(DWORD, DWORD, DWORD, DWORD);
  34. void ShutdownService();
  35. /*
  36. * Global variables
  37. */
  38. WCHAR gpszServiceName[] = L"TermService";
  39. SERVICE_TABLE_ENTRY gpServiceTable[] = {
  40. gpszServiceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain,
  41. NULL, NULL,
  42. };
  43. SERVICE_STATUS_HANDLE gStatusHandle;
  44. SERVICE_STATUS gStatus;
  45. DWORD gExitStatus = STATUS_SUCCESS;
  46. WCHAR g_wszProductVersion[22];
  47. TCHAR g_tszServiceAccount[UNLEN + 1];
  48. BOOL g_fAppCompat = TRUE;
  49. BOOL g_bPersonalTS = FALSE;
  50. BOOL g_bPersonalWks = FALSE;
  51. BOOL g_SafeBootWithNetwork = FALSE;
  52. BOOL gbServer = FALSE;
  53. BOOL gBreakOnProcessExit = FALSE;
  54. OSVERSIONINFOEX gOsVersion;
  55. HANDLE gReadyEventHandle = NULL;
  56. //
  57. // The following is used to inform Session 0 winlogon of the credentials needed to notify 3rd party n/w logon providers
  58. // This happens only during force logoff console reconnect scenario in PTS and /console in Server
  59. //
  60. ExtendedClientCredentials g_MprNotifyInfo;
  61. extern PSID gAdminSid;
  62. extern PSID gSystemSid;
  63. // Local prototypes.
  64. void LicenseModeInit(HKEY);
  65. NTSTATUS WsxInit(VOID);
  66. NTSTATUS VfyInit(VOID);
  67. BOOL WINAPI
  68. IsSafeBootWithNetwork();
  69. void CreateTermsrvHeap ()
  70. {
  71. IcaHeap = GetProcessHeap();
  72. return;
  73. }
  74. #ifdef TERMSRV_PROC
  75. /****************************************************************************/
  76. // main
  77. //
  78. // Standard console-app-style entry point. Returns an NTSTATUS code.
  79. /****************************************************************************/
  80. int _cdecl main(int argc, char *argv[])
  81. {
  82. NTSTATUS Status = STATUS_SUCCESS;
  83. KPRIORITY BasePriority;
  84. HRESULT hr;
  85. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Loading...\n"));
  86. /*
  87. * Run TermSrv at just above foreground priority.
  88. */
  89. BasePriority = FOREGROUND_BASE_PRIORITY + 1;
  90. Status = NtSetInformationProcess(NtCurrentProcess(),
  91. ProcessBasePriority,
  92. &BasePriority,
  93. sizeof(BasePriority) );
  94. ASSERT((Status == STATUS_PRIVILEGE_NOT_HELD) || NT_SUCCESS(Status));
  95. // Initialize COM once with multithreaded capability. This must be done
  96. // on the main service thread to allow other threads in the service to
  97. // inherit this initialization, if not specifically initialized for
  98. // apartment threading.
  99. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  100. if (!SUCCEEDED(hr)) {
  101. HANDLE h;
  102. WCHAR hrString[16];
  103. PWSTR String;
  104. h = RegisterEventSource(NULL, gpszServiceName);
  105. if (h != NULL) {
  106. wsprintfW(hrString, L"0x%X", hr);
  107. String = hrString;
  108. ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, EVENT_TERMSRV_FAIL_COM_INIT,
  109. NULL, 1, 0, &String, NULL);
  110. DeregisterEventSource(h);
  111. }
  112. DbgPrint("TERMSRV: Failed init COM, hr=0x%X\n", hr);
  113. goto done;
  114. }
  115. /*
  116. * Call service dispatcher
  117. */
  118. if (!StartServiceCtrlDispatcher(gpServiceTable)) {
  119. Status = GetLastError();
  120. DbgPrint("TERMSRV: Error %d in StartServiceCtrlDispatcher\n", Status);
  121. goto done;
  122. }
  123. done:
  124. if (SUCCEEDED(hr))
  125. CoUninitialize();
  126. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Unloading...\n"));
  127. return Status;
  128. }
  129. #else // TERMSRV_PROC
  130. BOOL WINAPI DllMain(
  131. HINSTANCE hinstDLL, // handle to the DLL module
  132. DWORD fdwReason, // reason for calling function
  133. LPVOID lpvReserved // reserved
  134. )
  135. {
  136. BOOL fResult = TRUE;
  137. switch(fdwReason) {
  138. case DLL_PROCESS_ATTACH:
  139. hModuleWin = hinstDLL;
  140. DisableThreadLibraryCalls(hinstDLL);
  141. break;
  142. default:;
  143. }
  144. return fResult;
  145. }
  146. #endif // TERMSRV_PROC
  147. /*****************************************************************************
  148. *
  149. * InitializeLoadMetrics
  150. *
  151. * Grabs baseline system resource values for use in load balancing. These
  152. * values are used to factor out the system resources required for basic OS
  153. * operation so they don't get into the calculations for how much resource on
  154. * average a user is consuming.
  155. *
  156. *
  157. * ENTRY:
  158. * no arguments.
  159. *
  160. * EXIT:
  161. * void
  162. *
  163. ****************************************************************************/
  164. VOID InitializeLoadMetrics()
  165. {
  166. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcessorInfo[MAX_PROCESSORS];
  167. SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
  168. SYSTEM_BASIC_INFORMATION SysBasicInfo;
  169. ULONG i;
  170. NTSTATUS Status;
  171. memset(&gLB, 0, sizeof(LOAD_BALANCING_METRICS));
  172. // Get basic system information
  173. Status = NtQuerySystemInformation(SystemBasicInformation, &SysBasicInfo,
  174. sizeof(SysBasicInfo), NULL);
  175. if (!NT_SUCCESS(Status)) {
  176. TRACE((hTrace, TC_LOAD, TT_ERROR,
  177. "InitializeLoadMetrics failed! SystemBasicInformation: %lx\n",
  178. Status));
  179. return;
  180. }
  181. gLB.NumProcessors = SysBasicInfo.NumberOfProcessors;
  182. gLB.PageSize = SysBasicInfo.PageSize;
  183. gLB.PhysicalPages = SysBasicInfo.NumberOfPhysicalPages;
  184. // Establish minimum usage levels to prevent absurd estimation
  185. gLB.MinPtesPerUser = SimAvgPtesPerUser;
  186. gLB.MinPagedPoolPerUser = (SimAvgPagedPoolPerUser * 1024) / gLB.PageSize;
  187. gLB.MinCommitPerUser = (SimCommitPerUser * 1024) / gLB.PageSize;
  188. // Grab base boot values. This isn't perfect, but it allows us to factor
  189. // out base OS resource requirements from the per user averages. The runtime
  190. // algorithm will reset the baselines if we go below these.
  191. Status = NtQuerySystemInformation(SystemPerformanceInformation,
  192. &SysPerfInfo, sizeof(SysPerfInfo),
  193. NULL);
  194. if (!NT_SUCCESS(Status)) {
  195. TRACE((hTrace, TC_LOAD, TT_ERROR,
  196. "InitializeLoadMetrics failed! SystemPerformanceInformation: %lx\n",
  197. Status));
  198. return;
  199. }
  200. // Note: we have an unsolvable problem in that there is no way to get
  201. // perfect values for how much memory the baseline system consumes. We
  202. // default baseline commit to 64M since that is the minimum recommended
  203. // system requirement.
  204. gLB.BaselineCommit = (64 * 1024*1024) / gLB.PageSize;
  205. // gLB.BaselineCommit = SysPerfInfo.CommittedPages;
  206. gLB.BaselineFreePtes = SysPerfInfo.FreeSystemPtes;
  207. gLB.BaselinePagedPool = SysPerfInfo.PagedPoolPages;
  208. // Initialize CPU Loading
  209. Status = NtQuerySystemInformation(SystemProcessorPerformanceInformation,
  210. ProcessorInfo,
  211. sizeof(ProcessorInfo),
  212. NULL);
  213. if (!NT_SUCCESS(Status)) {
  214. TRACE((hTrace, TC_LOAD, TT_ERROR,
  215. "InitializeLoadMetrics failed! SystemProcessorPerformanceInformation: %lx\n",
  216. Status));
  217. return;
  218. }
  219. for (i = 0; i < gLB.NumProcessors; i++) {
  220. gLB.IdleCPU.QuadPart += ProcessorInfo[i].IdleTime.QuadPart;
  221. gLB.TotalCPU.QuadPart += ProcessorInfo[i].KernelTime.QuadPart +
  222. ProcessorInfo[i].UserTime.QuadPart;
  223. }
  224. // Start out saying we're 80 percent idle (0-255 based)
  225. gLB.AvgIdleCPU = 204 ;
  226. // Indicate we got all the intial values!
  227. gLB.fInitialized = TRUE;
  228. TRACE((hTrace, TC_LOAD, TT_API1, "InitializeLoadMetrics():\n"));
  229. TRACE((hTrace, TC_LOAD, TT_API1,
  230. " Processors [%6ld], PageSize [%6ld], Physical [%6ld]\n",
  231. gLB.NumProcessors, gLB.PageSize, gLB.PhysicalPages));
  232. TRACE((hTrace, TC_LOAD, TT_API1,
  233. " PtesAvail [%6ld], PagedUsed [%6ld], Commit [%6ld]\n",
  234. gLB.BaselineFreePtes, gLB.BaselinePagedPool, gLB.BaselineCommit));
  235. }
  236. BOOL IsKernelDebuggerAttached ()
  237. {
  238. SYSTEM_KERNEL_DEBUGGER_INFORMATION KernelDebuggerInfo;
  239. NTSTATUS Status;
  240. Status = NtQuerySystemInformation( SystemKernelDebuggerInformation,
  241. &KernelDebuggerInfo,
  242. sizeof(KernelDebuggerInfo),
  243. NULL
  244. );
  245. return ( NT_SUCCESS(Status) && KernelDebuggerInfo.KernelDebuggerEnabled );
  246. }
  247. void DebugBreakIfAsked()
  248. {
  249. TCHAR REG_TERMSRV_DEBUGBREAK[] = TEXT("DebugTS");
  250. TCHAR REG_TERMSRV_DEBUGGER[] = TEXT("Debugger");
  251. TCHAR szDebugger[256];
  252. TCHAR szCommand[256];
  253. HKEY hTermSrv = NULL;
  254. DWORD dwBreakIn;
  255. DWORD dwValueType;
  256. DWORD dwSize;
  257. DWORD dwError;
  258. enum
  259. {
  260. TermSrvDoNotBreak = 0,
  261. TermSrvBreakIfBeingDebugged = 1,
  262. TermSrvAttachDebugger = 2,
  263. TermSrvBreakAlways = 3
  264. };
  265. dwError = RegOpenKeyEx(
  266. HKEY_LOCAL_MACHINE,
  267. REG_CONTROL_TSERVER,
  268. 0,
  269. KEY_READ,
  270. &hTermSrv
  271. );
  272. if (ERROR_SUCCESS == dwError)
  273. {
  274. dwSize = sizeof(dwBreakIn);
  275. dwError = RegQueryValueEx(
  276. hTermSrv,
  277. REG_TERMSRV_DEBUGBREAK,
  278. NULL,
  279. &dwValueType,
  280. (LPBYTE)&dwBreakIn,
  281. &dwSize
  282. );
  283. if (ERROR_SUCCESS == dwError && dwValueType == REG_DWORD)
  284. {
  285. switch (dwBreakIn)
  286. {
  287. case TermSrvAttachDebugger:
  288. //
  289. // if its already being debugged Break into it.
  290. //
  291. if (IsDebuggerPresent())
  292. {
  293. DebugBreak();
  294. break;
  295. }
  296. //
  297. // Get the debugger to be launched.
  298. // must contain %d which will be replaced by processid
  299. //
  300. dwSize = sizeof(szDebugger) / sizeof(TCHAR);
  301. dwError = RegQueryValueEx(
  302. hTermSrv,
  303. REG_TERMSRV_DEBUGGER,
  304. NULL,
  305. &dwValueType,
  306. (LPBYTE)szDebugger,
  307. &dwSize
  308. );
  309. if (ERROR_SUCCESS == dwError && dwValueType == REG_SZ)
  310. {
  311. PROCESS_INFORMATION ProcessInfo;
  312. STARTUPINFO StartupInfo;
  313. wsprintf(szCommand, szDebugger, GetCurrentProcessId());
  314. DbgPrint("TERMSRV:*-----------------* Executing:<%ws> *-----------------*\n", szCommand);
  315. ZeroMemory(&StartupInfo, sizeof(StartupInfo));
  316. StartupInfo.cb = sizeof(StartupInfo);
  317. if (!CreateProcess(NULL, szCommand, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo))
  318. {
  319. DbgPrint("TERMSRV:*-----------------* TERMSRV:CreateProcess failed *-----------------*\n");
  320. }
  321. else
  322. {
  323. CloseHandle(ProcessInfo.hProcess);
  324. CloseHandle(ProcessInfo.hThread);
  325. while (!IsDebuggerPresent())
  326. {
  327. Sleep(500);
  328. }
  329. }
  330. }
  331. else
  332. {
  333. DbgPrint("TERMSRV:*-----------------* Did not find the debugger entry. *-----------------*\n");
  334. }
  335. break;
  336. case TermSrvBreakIfBeingDebugged:
  337. // check if any debugger is attached, if not dont breakin.
  338. if (!IsDebuggerPresent() && !IsKernelDebuggerAttached ())
  339. break;
  340. case TermSrvBreakAlways:
  341. DebugBreak();
  342. break;
  343. case TermSrvDoNotBreak:
  344. default:
  345. break;
  346. }
  347. }
  348. RegCloseKey(hTermSrv);
  349. }
  350. else
  351. {
  352. DbgPrint("TERMSRV:*-----------------* Could not open termsrv registry *-----------------*\n");
  353. }
  354. }
  355. /****************************************************************************/
  356. // ServiceMain
  357. //
  358. // TermSrv service entry point.
  359. /****************************************************************************/
  360. VOID ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
  361. {
  362. HANDLE hIcaLPCThread;
  363. HANDLE hIcaLPCPort = NULL;
  364. DWORD dwValueType;
  365. LONG lReturn;
  366. DWORD cbValue;
  367. BOOL bAdvertiseTS;
  368. DWORD dwTSAdvertise;
  369. NTSTATUS Status;
  370. HKEY hKeyTermSrv = NULL;
  371. DWORDLONG dwlConditionMask;
  372. DebugBreakIfAsked();
  373. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: ServiceMain entered...\n"));
  374. gStatus.dwServiceType = SERVICE_WIN32;
  375. gStatus.dwWaitHint = 30000;
  376. gStatus.dwCurrentState = SERVICE_STOPPED;
  377. /*
  378. * Register the control handler
  379. */
  380. if (!(gStatusHandle = RegisterServiceCtrlHandler(gpszServiceName,
  381. Handler))) {
  382. DbgPrint("TERMSRV: Error %d in RegisterServiceCtrlHandler\n",
  383. GetLastError());
  384. goto done;
  385. }
  386. // If Terminal Services are not enabled then don't allow starting termsrv
  387. // service.
  388. if (!IsTerminalServicesEnabled()) {
  389. HANDLE h;
  390. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Not a TSBox."));
  391. h = RegisterEventSource(NULL, gpszServiceName);
  392. if (h != NULL) {
  393. if (!ReportEvent(
  394. h, // event log handle
  395. EVENTLOG_ERROR_TYPE, // event type
  396. 0, // category zero
  397. EVENT_NOT_A_TSBOX, // event identifier
  398. NULL, // no user security identifier
  399. 0, // one substitution string
  400. 0, // no data
  401. NULL, // pointer to string array
  402. NULL // pointer to data
  403. )) {
  404. DBGPRINT(("ReportEvent Failed %ld. Event ID=%lx\n",GetLastError(), EVENT_NOT_A_TSBOX));
  405. }
  406. }
  407. goto done;
  408. }
  409. CreateTermsrvHeap ();
  410. /*
  411. * Create and set an event which indicates that TermSrv is ready.
  412. * WinLogon checks this event. Do not signal now.
  413. *
  414. */
  415. gReadyEventHandle = CreateEvent(NULL, TRUE, FALSE,
  416. TEXT("Global\\TermSrvReadyEvent"));
  417. // Initialize Global System and Admin SID
  418. Status = NtCreateAdminSid(&gAdminSid);
  419. if (!NT_SUCCESS(Status))
  420. {
  421. goto done;
  422. }
  423. Status = InitializeWinStationSecurityLock();
  424. if (!NT_SUCCESS(Status))
  425. {
  426. goto done;
  427. }
  428. Status = NtCreateSystemSid(&gSystemSid);
  429. if (!NT_SUCCESS(Status))
  430. {
  431. goto done;
  432. }
  433. if (!IsServiceLoggedAsSystem()) {
  434. WriteErrorLogEntry(EVENT_NOT_SYSTEM_ACCOUNT, NULL, 0);
  435. gExitStatus = ERROR_PRIVILEGE_NOT_HELD;
  436. goto done;
  437. }
  438. // Set global flag for Personal WorkStation
  439. g_bPersonalWks = IsPersonalWorkstation();
  440. #if DBG
  441. if( TRUE == g_bPersonalWks )
  442. {
  443. DbgPrint("TERMSRV : TS running on Personal Workstation\n");
  444. }
  445. else
  446. {
  447. DbgPrint("TERMSRV : Not Personal Workstation\n");
  448. }
  449. #endif
  450. //
  451. // Initialize HelpAssistant password encryption.
  452. //
  453. lReturn = TSHelpAssistantInitializeEncryptionLib();
  454. //
  455. // Not a critical error, No help will be available
  456. //
  457. #if DBG
  458. if( lReturn != ERROR_SUCCESS ) {
  459. DbgPrint( "TERMSRV : EncryptionLib failed with %d, no help is available\n", lReturn );
  460. }
  461. #endif
  462. //
  463. // We are booting in safeboot with network support
  464. //
  465. g_SafeBootWithNetwork = IsSafeBootWithNetwork();
  466. // Set the global flag for Personal TS support. We use this to reduce
  467. // the feature set based on product (e.g. no load balancing session
  468. // directory if not on Server).
  469. g_bPersonalTS = IsPersonalTerminalServicesEnabled();
  470. ZeroMemory(&gOsVersion, sizeof(OSVERSIONINFOEX));
  471. gOsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  472. gOsVersion.wProductType = VER_NT_WORKSTATION;
  473. dwlConditionMask = 0;
  474. VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
  475. gbServer = !VerifyVersionInfo(&gOsVersion, VER_PRODUCT_TYPE, dwlConditionMask);
  476. // Open a single, global HKLM\System\CCS\Control\TS reg handle, from which
  477. // other init code can query.
  478. lReturn = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0,
  479. KEY_READ, &hKeyTermSrv);
  480. if (lReturn != ERROR_SUCCESS) {
  481. DbgPrint("TERMSRV: Unable to open TS key in HKLM, lasterr=0x%X",
  482. GetLastError());
  483. goto done;
  484. }
  485. /*
  486. * Indicate service is starting.
  487. */
  488. Status = UpdateServiceStatus(SERVICE_START_PENDING, 0, 1, 0);
  489. if (!NT_SUCCESS(Status)) {
  490. DbgPrint("TERMSRV: Unable update service status %X\n", Status );
  491. }
  492. Status = RtlCreateEnvironment(TRUE, &DefaultEnvironment);
  493. if (!NT_SUCCESS(Status)) {
  494. DbgPrint("TERMSRV: Unable to alloc default environment, Status=0x%X\n",
  495. Status);
  496. goto done;
  497. }
  498. #ifdef TERMSRV_PROC
  499. /*
  500. * Get the module handle for messages.
  501. */
  502. hModuleWin = GetModuleHandleW(NULL);
  503. #endif // TERMSRV_PROC
  504. /*
  505. * Indicate service has started successfully.
  506. * Maybe this should be moved below? No way!!!
  507. */
  508. Status = UpdateServiceStatus(SERVICE_RUNNING, 0, 2, 0);
  509. if (!Status)
  510. DbgPrint("TERMSRV: Unable to update service status %X\n", Status);
  511. /*
  512. * Connect to the session manager
  513. */
  514. Status = SmConnectToSm((PUNICODE_STRING)NULL, (HANDLE)NULL, 0,
  515. &IcaSmApiPort);
  516. if (!NT_SUCCESS(Status))
  517. goto done;
  518. // Initialize the licensing mode - this only gets information, it doesn't
  519. // initialize the licensing core.
  520. LicenseModeInit(hKeyTermSrv);
  521. // Perform the bulk of the TermSrv init.
  522. Status = InitTermSrv(hKeyTermSrv);
  523. if (!NT_SUCCESS(Status))
  524. goto ShutdownService;
  525. /*
  526. * Indicate that we are a Terminal Server unless were asked not to
  527. * advertise ourselves as a Terminal Server.
  528. */
  529. bAdvertiseTS = TRUE;
  530. cbValue = sizeof(dwTSAdvertise);
  531. lReturn = RegQueryValueEx(hKeyTermSrv, REG_TERMSRV_ADVERTISE, NULL,
  532. &dwValueType, (LPBYTE)&dwTSAdvertise, &cbValue);
  533. if (ERROR_SUCCESS == lReturn && dwValueType == REG_DWORD)
  534. bAdvertiseTS = dwTSAdvertise;
  535. if (bAdvertiseTS)
  536. SetServiceBits(gStatusHandle, SV_TYPE_TERMINALSERVER, TRUE, TRUE);
  537. /*
  538. * Need to do this at least once
  539. */
  540. UpdateOemAndProductInfo(hKeyTermSrv);
  541. // Initialize TermSrv and TermDD trace.
  542. InitializeSystemTrace(hKeyTermSrv);
  543. /*
  544. * Set TermDD parameters.
  545. */
  546. GetSetSystemParameters(hKeyTermSrv);
  547. /*
  548. * Initialize WinStation extension DLL support
  549. */
  550. Status = WsxInit();
  551. if (!NT_SUCCESS(Status))
  552. goto ShutdownService;
  553. /*
  554. * Initialize DLL Verification mechanism.
  555. */
  556. Status = VfyInit();
  557. if (!NT_SUCCESS(Status))
  558. goto ShutdownService;
  559. /*
  560. * Start WinStations
  561. */
  562. StartAllWinStations(hKeyTermSrv);
  563. // Initialize the TS Session Directory for load balancing.
  564. // Not available on Personal TS or remote admin.
  565. if (!g_bPersonalTS && g_fAppCompat)
  566. InitSessionDirectory();
  567. InitializeLoadMetrics();
  568. // Done with init, close the TermSrv regkey.
  569. RegCloseKey(hKeyTermSrv);
  570. hKeyTermSrv = NULL;
  571. /*
  572. * Initialize WinStationAPI's
  573. */
  574. Status = WinStationInitRPC();
  575. ASSERT( NT_SUCCESS( Status ) );
  576. if (!NT_SUCCESS(Status)) {
  577. goto done;
  578. }
  579. /*
  580. * Set break on termination flag for our process.
  581. */
  582. {
  583. NTSTATUS stp;
  584. if ( IsKernelDebuggerAttached ()) {
  585. stp = RtlSetProcessIsCritical(TRUE, NULL, FALSE);
  586. if (stp == STATUS_SUCCESS) {
  587. gBreakOnProcessExit = TRUE;
  588. }
  589. else {
  590. DbgPrint("TERMSRV: RtlSetProcessIsCritical returned: %x ", stp);
  591. }
  592. }
  593. }
  594. /*
  595. * Set the event which indicates that TermSrv is ready.
  596. * WinLogon checks this event.
  597. */
  598. if (gReadyEventHandle != NULL)
  599. SetEvent(gReadyEventHandle);
  600. TSStartupSalem();
  601. return;
  602. ShutdownService:
  603. ShutdownService();
  604. done:
  605. // Kill the session directory.
  606. if (!g_bPersonalTS && g_fAppCompat)
  607. DestroySessionDirectory();
  608. // In case of error, check the TermSrv regkey again.
  609. if (hKeyTermSrv != NULL)
  610. RegCloseKey(hKeyTermSrv);
  611. UpdateServiceStatus(SERVICE_STOPPED, gExitStatus, 5, 0);
  612. }
  613. /****************************************************************************/
  614. // Handler
  615. //
  616. // TermSrv service control event handler.
  617. /****************************************************************************/
  618. VOID Handler(DWORD fdwControl)
  619. {
  620. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Handler %d\n", fdwControl));
  621. switch (fdwControl) {
  622. case SERVICE_CONTROL_STOP:
  623. // We absolutely do not want to be stopping TermSrv -- it is
  624. // the only location for a lot of system-wide TS related state.
  625. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: control code %d, stopping service...\n",
  626. fdwControl));
  627. if (gStatus.dwCurrentState == SERVICE_RUNNING) {
  628. UpdateServiceStatus(SERVICE_STOP_PENDING, 0, 3, 0);
  629. #ifdef notdef
  630. // For now don't stop TermSRV
  631. // The CDM service does a KeAttachProcess() to this process
  632. if (gReadyEventHandle != NULL) {
  633. ResetEvent(gReadyEventHandle);
  634. CloseHandle(gReadyEventHandle);
  635. gReadyEventHandle = NULL;
  636. }
  637. ShutdownService();
  638. UpdateServiceStatus(SERVICE_STOPPED, gExitStatus, 5, 0);
  639. #endif
  640. }
  641. break;
  642. case SERVICE_CONTROL_SHUTDOWN:
  643. DBGPRINT(("TERMSRV: control code %d, shutdown service...\n",
  644. fdwControl));
  645. if (gStatus.dwCurrentState == SERVICE_RUNNING) {
  646. // 2 seconds at most to shut down.
  647. UpdateServiceStatus(SERVICE_STOP_PENDING, 0, 4, 2000);
  648. #ifdef notdef
  649. // We don't trigger this event that invokes destructors for
  650. // all of TermSrv, since on shutdown we don't want to be
  651. // destroying machine state. We want to invoke only those
  652. // destructors that are required for proper functioning of
  653. // the system.
  654. #endif
  655. // Invoke required destruction code.
  656. if (gReadyEventHandle != NULL) {
  657. ResetEvent(gReadyEventHandle);
  658. CloseHandle(gReadyEventHandle);
  659. gReadyEventHandle = NULL;
  660. }
  661. ShutdownService();
  662. UpdateServiceStatus(SERVICE_STOPPED, 0, 4, 0);
  663. }
  664. break;
  665. case SERVICE_CONTROL_INTERROGATE :
  666. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Interrogating service...\n"));
  667. SetServiceStatus(gStatusHandle, &gStatus);
  668. break;
  669. default:
  670. DBGPRINT(("TERMSRV: Unhandled control code %d\n", fdwControl));
  671. break;
  672. }
  673. }
  674. /****************************************************************************/
  675. // ShutdownService
  676. //
  677. // Called by service manager to shut down the service at system shutdown
  678. // time. This function should invoke only the most important and required
  679. // destruction code, since we're on a strict time limit on system shutdown.
  680. /****************************************************************************/
  681. void ShutdownService()
  682. {
  683. //free authz resource manager
  684. AuditEnd();
  685. // Destroy the session directory so the directory can be informed to
  686. // remove server- and session-specific information.
  687. if (!g_bPersonalTS && g_fAppCompat)
  688. DestroySessionDirectory();
  689. }
  690. /****************************************************************************/
  691. // UpdateServiceStatus
  692. //
  693. // Updates the service's status to the Service Control Manager. Returns
  694. // FALSE on error.
  695. /****************************************************************************/
  696. BOOL UpdateServiceStatus(
  697. DWORD CurrentState,
  698. DWORD ExitCode,
  699. DWORD CheckPoint,
  700. DWORD WaitHint)
  701. {
  702. // If service is starting, then disable all control requests, otherwise
  703. // accept shutdown notifications if we are an app server, to properly
  704. // clean up the session directory. We do not accept stop requests
  705. // during the lifetime of the server up state, the CDM service does a
  706. // KeAttachProcess() to this process so it must always be around.
  707. if (gStatusHandle == NULL) {
  708. return FALSE;
  709. }
  710. gStatus.dwControlsAccepted = 0;
  711. gStatus.dwCurrentState = CurrentState;
  712. gStatus.dwWin32ExitCode = ExitCode;
  713. gStatus.dwCheckPoint = CheckPoint;
  714. gStatus.dwServiceSpecificExitCode = 0;
  715. gStatus.dwWaitHint = WaitHint;
  716. return SetServiceStatus(gStatusHandle, &gStatus);
  717. }
  718. /*****************************************************************************
  719. * LicenseModeInit
  720. *
  721. * Initialize the licensing mode
  722. ****************************************************************************/
  723. void LicenseModeInit(HKEY hKeyTermSrv)
  724. {
  725. DWORD dwValueType;
  726. LONG lReturn;
  727. DWORD cbValue = sizeof( DWORD ), dwAccount = UNLEN + 1;
  728. DWORD dwRegValue;
  729. OSVERSIONINFO VersionInfo;
  730. ASSERT(hKeyTermSrv != NULL);
  731. //
  732. // Get the user name for which the service is started under
  733. //
  734. GetUserName(g_tszServiceAccount, &dwAccount);
  735. //
  736. // Check whether Remote Admin is enabled
  737. //
  738. lReturn = RegQueryValueEx(hKeyTermSrv,
  739. REG_TERMSRV_APPCOMPAT,
  740. NULL,
  741. &dwValueType,
  742. (LPBYTE) &dwRegValue,
  743. &cbValue);
  744. if (lReturn == ERROR_SUCCESS) {
  745. g_fAppCompat = (BOOL)dwRegValue;
  746. }
  747. //
  748. // Get the product version
  749. //
  750. memset( &VersionInfo, 0, sizeof( OSVERSIONINFO ) );
  751. VersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
  752. if (GetVersionEx(&VersionInfo)) {
  753. wsprintf( g_wszProductVersion, L"%d.%d",
  754. VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion );
  755. }
  756. else {
  757. TRACE((hTrace, TC_ICASRV, TT_ERROR, "LicenseModeInit: GetVersionEx "
  758. "failed: 0x%x\n", GetLastError()));
  759. }
  760. }
  761. //
  762. // Get Safeboot option, code modified from ds\security\gina\winlogon\aenrlhlp.c
  763. //
  764. BOOL WINAPI
  765. IsSafeBootWithNetwork()
  766. {
  767. DWORD dwSafeBoot = 0;
  768. DWORD cbSafeBoot = sizeof(dwSafeBoot);
  769. DWORD dwType = 0;
  770. HKEY hKeySafeBoot = NULL;
  771. if(ERROR_SUCCESS == RegOpenKeyW(
  772. HKEY_LOCAL_MACHINE,
  773. L"system\\currentcontrolset\\control\\safeboot\\option",
  774. &hKeySafeBoot))
  775. {
  776. // we did in fact boot under safeboot control
  777. if(ERROR_SUCCESS != RegQueryValueExW(
  778. hKeySafeBoot,
  779. L"OptionValue",
  780. NULL,
  781. &dwType,
  782. (LPBYTE)&dwSafeBoot,
  783. &cbSafeBoot))
  784. {
  785. dwSafeBoot = 0;
  786. }
  787. if(hKeySafeBoot)
  788. RegCloseKey(hKeySafeBoot);
  789. }
  790. return ( SAFEBOOT_NETWORK == dwSafeBoot );
  791. }