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

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