windows-nt/Source/XPSP1/NT/termsrv/winsta/server/icasrv.c

978 lines
28 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/****************************************************************************/
// icasrv.c
//
// TermSrv service process entry points.
//
// Copyright (C) 1997-2000 Microsoft Corporation
/****************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <objbase.h>
#include "icaevent.h"
#include "sessdir.h"
#include <safeboot.h>
extern BOOL UpdateOemAndProductInfo(HKEY);
extern BOOL IsServiceLoggedAsSystem( VOID );
extern VOID WriteErrorLogEntry(
IN NTSTATUS NtStatusCode,
IN PVOID pRawData,
IN ULONG RawDataLength
);
extern NTSTATUS WinStationInitRPC();
extern NTSTATUS InitializeWinStationSecurityLock(VOID);
extern VOID AuditEnd();
/*
* Definitions
*/
#define STACKSIZE_LPCTHREAD (4 * 0x1000)
/*
* Internal Procedures defined
*/
VOID ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
VOID Handler(DWORD fdwControl);
BOOL UpdateServiceStatus(DWORD, DWORD, DWORD, DWORD);
void ShutdownService();
/*
* Global variables
*/
WCHAR gpszServiceName[] = L"TermService";
SERVICE_TABLE_ENTRY gpServiceTable[] = {
gpszServiceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain,
NULL, NULL,
};
SERVICE_STATUS_HANDLE gStatusHandle;
SERVICE_STATUS gStatus;
DWORD gExitStatus = STATUS_SUCCESS;
WCHAR g_wszProductVersion[22];
TCHAR g_tszServiceAccount[UNLEN + 1];
BOOL g_fAppCompat = TRUE;
BOOL g_bPersonalTS = FALSE;
BOOL g_bPersonalWks = FALSE;
BOOL g_SafeBootWithNetwork = FALSE;
BOOL gbServer = FALSE;
BOOL gBreakOnProcessExit = FALSE;
OSVERSIONINFOEX gOsVersion;
HANDLE gReadyEventHandle = NULL;
//
// The following is used to inform Session 0 winlogon of the credentials needed to notify 3rd party n/w logon providers
// This happens only during force logoff console reconnect scenario in PTS and /console in Server
//
ExtendedClientCredentials g_MprNotifyInfo;
extern PSID gAdminSid;
extern PSID gSystemSid;
// Local prototypes.
void LicenseModeInit(HKEY);
NTSTATUS WsxInit(VOID);
NTSTATUS VfyInit(VOID);
BOOL WINAPI
IsSafeBootWithNetwork();
void CreateTermsrvHeap ()
{
IcaHeap = GetProcessHeap();
return;
}
#ifdef TERMSRV_PROC
/****************************************************************************/
// main
//
// Standard console-app-style entry point. Returns an NTSTATUS code.
/****************************************************************************/
int _cdecl main(int argc, char *argv[])
{
NTSTATUS Status = STATUS_SUCCESS;
KPRIORITY BasePriority;
HRESULT hr;
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Loading...\n"));
/*
* Run TermSrv at just above foreground priority.
*/
BasePriority = FOREGROUND_BASE_PRIORITY + 1;
Status = NtSetInformationProcess(NtCurrentProcess(),
ProcessBasePriority,
&BasePriority,
sizeof(BasePriority) );
ASSERT((Status == STATUS_PRIVILEGE_NOT_HELD) || NT_SUCCESS(Status));
// Initialize COM once with multithreaded capability. This must be done
// on the main service thread to allow other threads in the service to
// inherit this initialization, if not specifically initialized for
// apartment threading.
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (!SUCCEEDED(hr)) {
HANDLE h;
WCHAR hrString[16];
PWSTR String;
h = RegisterEventSource(NULL, gpszServiceName);
if (h != NULL) {
wsprintfW(hrString, L"0x%X", hr);
String = hrString;
ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, EVENT_TERMSRV_FAIL_COM_INIT,
NULL, 1, 0, &String, NULL);
DeregisterEventSource(h);
}
DbgPrint("TERMSRV: Failed init COM, hr=0x%X\n", hr);
goto done;
}
/*
* Call service dispatcher
*/
if (!StartServiceCtrlDispatcher(gpServiceTable)) {
Status = GetLastError();
DbgPrint("TERMSRV: Error %d in StartServiceCtrlDispatcher\n", Status);
goto done;
}
done:
if (SUCCEEDED(hr))
CoUninitialize();
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Unloading...\n"));
return Status;
}
#else // TERMSRV_PROC
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to the DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved // reserved
)
{
BOOL fResult = TRUE;
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
hModuleWin = hinstDLL;
DisableThreadLibraryCalls(hinstDLL);
break;
default:;
}
return fResult;
}
#endif // TERMSRV_PROC
/*****************************************************************************
*
* InitializeLoadMetrics
*
* Grabs baseline system resource values for use in load balancing. These
* values are used to factor out the system resources required for basic OS
* operation so they don't get into the calculations for how much resource on
* average a user is consuming.
*
*
* ENTRY:
* no arguments.
*
* EXIT:
* void
*
****************************************************************************/
VOID InitializeLoadMetrics()
{
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcessorInfo[MAX_PROCESSORS];
SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
SYSTEM_BASIC_INFORMATION SysBasicInfo;
ULONG i;
NTSTATUS Status;
memset(&gLB, 0, sizeof(LOAD_BALANCING_METRICS));
// Get basic system information
Status = NtQuerySystemInformation(SystemBasicInformation, &SysBasicInfo,
sizeof(SysBasicInfo), NULL);
if (!NT_SUCCESS(Status)) {
TRACE((hTrace, TC_LOAD, TT_ERROR,
"InitializeLoadMetrics failed! SystemBasicInformation: %lx\n",
Status));
return;
}
gLB.NumProcessors = SysBasicInfo.NumberOfProcessors;
gLB.PageSize = SysBasicInfo.PageSize;
gLB.PhysicalPages = SysBasicInfo.NumberOfPhysicalPages;
// Establish minimum usage levels to prevent absurd estimation
gLB.MinPtesPerUser = SimAvgPtesPerUser;
gLB.MinPagedPoolPerUser = (SimAvgPagedPoolPerUser * 1024) / gLB.PageSize;
gLB.MinCommitPerUser = (SimCommitPerUser * 1024) / gLB.PageSize;
// Grab base boot values. This isn't perfect, but it allows us to factor
// out base OS resource requirements from the per user averages. The runtime
// algorithm will reset the baselines if we go below these.
Status = NtQuerySystemInformation(SystemPerformanceInformation,
&SysPerfInfo, sizeof(SysPerfInfo),
NULL);
if (!NT_SUCCESS(Status)) {
TRACE((hTrace, TC_LOAD, TT_ERROR,
"InitializeLoadMetrics failed! SystemPerformanceInformation: %lx\n",
Status));
return;
}
// Note: we have an unsolvable problem in that there is no way to get
// perfect values for how much memory the baseline system consumes. We
// default baseline commit to 64M since that is the minimum recommended
// system requirement.
gLB.BaselineCommit = (64 * 1024*1024) / gLB.PageSize;
// gLB.BaselineCommit = SysPerfInfo.CommittedPages;
gLB.BaselineFreePtes = SysPerfInfo.FreeSystemPtes;
gLB.BaselinePagedPool = SysPerfInfo.PagedPoolPages;
// Initialize CPU Loading
Status = NtQuerySystemInformation(SystemProcessorPerformanceInformation,
ProcessorInfo,
sizeof(ProcessorInfo),
NULL);
if (!NT_SUCCESS(Status)) {
TRACE((hTrace, TC_LOAD, TT_ERROR,
"InitializeLoadMetrics failed! SystemProcessorPerformanceInformation: %lx\n",
Status));
return;
}
for (i = 0; i < gLB.NumProcessors; i++) {
gLB.IdleCPU.QuadPart += ProcessorInfo[i].IdleTime.QuadPart;
gLB.TotalCPU.QuadPart += ProcessorInfo[i].KernelTime.QuadPart +
ProcessorInfo[i].UserTime.QuadPart;
}
// Start out saying we're 80 percent idle (0-255 based)
gLB.AvgIdleCPU = 204 ;
// Indicate we got all the intial values!
gLB.fInitialized = TRUE;
TRACE((hTrace, TC_LOAD, TT_API1, "InitializeLoadMetrics():\n"));
TRACE((hTrace, TC_LOAD, TT_API1,
" Processors [%6ld], PageSize [%6ld], Physical [%6ld]\n",
gLB.NumProcessors, gLB.PageSize, gLB.PhysicalPages));
TRACE((hTrace, TC_LOAD, TT_API1,
" PtesAvail [%6ld], PagedUsed [%6ld], Commit [%6ld]\n",
gLB.BaselineFreePtes, gLB.BaselinePagedPool, gLB.BaselineCommit));
}
BOOL IsKernelDebuggerAttached ()
{
SYSTEM_KERNEL_DEBUGGER_INFORMATION KernelDebuggerInfo;
NTSTATUS Status;
Status = NtQuerySystemInformation( SystemKernelDebuggerInformation,
&KernelDebuggerInfo,
sizeof(KernelDebuggerInfo),
NULL
);
return ( NT_SUCCESS(Status) && KernelDebuggerInfo.KernelDebuggerEnabled );
}
void DebugBreakIfAsked()
{
TCHAR REG_TERMSRV_DEBUGBREAK[] = TEXT("DebugTS");
TCHAR REG_TERMSRV_DEBUGGER[] = TEXT("Debugger");
TCHAR szDebugger[256];
TCHAR szCommand[256];
HKEY hTermSrv = NULL;
DWORD dwBreakIn;
DWORD dwValueType;
DWORD dwSize;
DWORD dwError;
enum
{
TermSrvDoNotBreak = 0,
TermSrvBreakIfBeingDebugged = 1,
TermSrvAttachDebugger = 2,
TermSrvBreakAlways = 3
};
dwError = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
REG_CONTROL_TSERVER,
0,
KEY_READ,
&hTermSrv
);
if (ERROR_SUCCESS == dwError)
{
dwSize = sizeof(dwBreakIn);
dwError = RegQueryValueEx(
hTermSrv,
REG_TERMSRV_DEBUGBREAK,
NULL,
&dwValueType,
(LPBYTE)&dwBreakIn,
&dwSize
);
if (ERROR_SUCCESS == dwError && dwValueType == REG_DWORD)
{
switch (dwBreakIn)
{
case TermSrvAttachDebugger:
//
// if its already being debugged Break into it.
//
if (IsDebuggerPresent())
{
DebugBreak();
break;
}
//
// Get the debugger to be launched.
// must contain %d which will be replaced by processid
//
dwSize = sizeof(szDebugger) / sizeof(TCHAR);
dwError = RegQueryValueEx(
hTermSrv,
REG_TERMSRV_DEBUGGER,
NULL,
&dwValueType,
(LPBYTE)szDebugger,
&dwSize
);
if (ERROR_SUCCESS == dwError && dwValueType == REG_SZ)
{
PROCESS_INFORMATION ProcessInfo;
STARTUPINFO StartupInfo;
wsprintf(szCommand, szDebugger, GetCurrentProcessId());
DbgPrint("TERMSRV:*-----------------* Executing:<%ws> *-----------------*\n", szCommand);
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
if (!CreateProcess(NULL, szCommand, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo))
{
DbgPrint("TERMSRV:*-----------------* TERMSRV:CreateProcess failed *-----------------*\n");
}
else
{
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
while (!IsDebuggerPresent())
{
Sleep(500);
}
}
}
else
{
DbgPrint("TERMSRV:*-----------------* Did not find the debugger entry. *-----------------*\n");
}
break;
case TermSrvBreakIfBeingDebugged:
// check if any debugger is attached, if not dont breakin.
if (!IsDebuggerPresent() && !IsKernelDebuggerAttached ())
break;
case TermSrvBreakAlways:
DebugBreak();
break;
case TermSrvDoNotBreak:
default:
break;
}
}
RegCloseKey(hTermSrv);
}
else
{
DbgPrint("TERMSRV:*-----------------* Could not open termsrv registry *-----------------*\n");
}
}
/****************************************************************************/
// ServiceMain
//
// TermSrv service entry point.
/****************************************************************************/
VOID ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
HANDLE hIcaLPCThread;
HANDLE hIcaLPCPort = NULL;
DWORD dwValueType;
LONG lReturn;
DWORD cbValue;
BOOL bAdvertiseTS;
DWORD dwTSAdvertise;
NTSTATUS Status;
HKEY hKeyTermSrv = NULL;
DWORDLONG dwlConditionMask;
DebugBreakIfAsked();
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: ServiceMain entered...\n"));
gStatus.dwServiceType = SERVICE_WIN32;
gStatus.dwWaitHint = 30000;
gStatus.dwCurrentState = SERVICE_STOPPED;
/*
* Register the control handler
*/
if (!(gStatusHandle = RegisterServiceCtrlHandler(gpszServiceName,
Handler))) {
DbgPrint("TERMSRV: Error %d in RegisterServiceCtrlHandler\n",
GetLastError());
goto done;
}
// If Terminal Services are not enabled then don't allow starting termsrv
// service.
if (!IsTerminalServicesEnabled()) {
HANDLE h;
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Not a TSBox."));
h = RegisterEventSource(NULL, gpszServiceName);
if (h != NULL) {
if (!ReportEvent(
h, // event log handle
EVENTLOG_ERROR_TYPE, // event type
0, // category zero
EVENT_NOT_A_TSBOX, // event identifier
NULL, // no user security identifier
0, // one substitution string
0, // no data
NULL, // pointer to string array
NULL // pointer to data
)) {
DBGPRINT(("ReportEvent Failed %ld. Event ID=%lx\n",GetLastError(), EVENT_NOT_A_TSBOX));
}
}
goto done;
}
CreateTermsrvHeap ();
/*
* Create and set an event which indicates that TermSrv is ready.
* WinLogon checks this event. Do not signal now.
*
*/
gReadyEventHandle = CreateEvent(NULL, TRUE, FALSE,
TEXT("Global\\TermSrvReadyEvent"));
// Initialize Global System and Admin SID
Status = NtCreateAdminSid(&gAdminSid);
if (!NT_SUCCESS(Status))
{
goto done;
}
Status = InitializeWinStationSecurityLock();
if (!NT_SUCCESS(Status))
{
goto done;
}
Status = NtCreateSystemSid(&gSystemSid);
if (!NT_SUCCESS(Status))
{
goto done;
}
if (!IsServiceLoggedAsSystem()) {
WriteErrorLogEntry(EVENT_NOT_SYSTEM_ACCOUNT, NULL, 0);
gExitStatus = ERROR_PRIVILEGE_NOT_HELD;
goto done;
}
// Set global flag for Personal WorkStation
g_bPersonalWks = IsPersonalWorkstation();
#if DBG
if( TRUE == g_bPersonalWks )
{
DbgPrint("TERMSRV : TS running on Personal Workstation\n");
}
else
{
DbgPrint("TERMSRV : Not Personal Workstation\n");
}
#endif
//
// Initialize HelpAssistant password encryption.
//
lReturn = TSHelpAssistantInitializeEncryptionLib();
//
// Not a critical error, No help will be available
//
#if DBG
if( lReturn != ERROR_SUCCESS ) {
DbgPrint( "TERMSRV : EncryptionLib failed with %d, no help is available\n", lReturn );
}
#endif
//
// We are booting in safeboot with network support
//
g_SafeBootWithNetwork = IsSafeBootWithNetwork();
// Set the global flag for Personal TS support. We use this to reduce
// the feature set based on product (e.g. no load balancing session
// directory if not on Server).
g_bPersonalTS = IsPersonalTerminalServicesEnabled();
ZeroMemory(&gOsVersion, sizeof(OSVERSIONINFOEX));
gOsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
gOsVersion.wProductType = VER_NT_WORKSTATION;
dwlConditionMask = 0;
VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
gbServer = !VerifyVersionInfo(&gOsVersion, VER_PRODUCT_TYPE, dwlConditionMask);
// Open a single, global HKLM\System\CCS\Control\TS reg handle, from which
// other init code can query.
lReturn = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0,
KEY_READ, &hKeyTermSrv);
if (lReturn != ERROR_SUCCESS) {
DbgPrint("TERMSRV: Unable to open TS key in HKLM, lasterr=0x%X",
GetLastError());
goto done;
}
/*
* Indicate service is starting.
*/
Status = UpdateServiceStatus(SERVICE_START_PENDING, 0, 1, 0);
if (!NT_SUCCESS(Status)) {
DbgPrint("TERMSRV: Unable update service status %X\n", Status );
}
Status = RtlCreateEnvironment(TRUE, &DefaultEnvironment);
if (!NT_SUCCESS(Status)) {
DbgPrint("TERMSRV: Unable to alloc default environment, Status=0x%X\n",
Status);
goto done;
}
#ifdef TERMSRV_PROC
/*
* Get the module handle for messages.
*/
hModuleWin = GetModuleHandleW(NULL);
#endif // TERMSRV_PROC
/*
* Indicate service has started successfully.
* Maybe this should be moved below? No way!!!
*/
Status = UpdateServiceStatus(SERVICE_RUNNING, 0, 2, 0);
if (!Status)
DbgPrint("TERMSRV: Unable to update service status %X\n", Status);
/*
* Connect to the session manager
*/
Status = SmConnectToSm((PUNICODE_STRING)NULL, (HANDLE)NULL, 0,
&IcaSmApiPort);
if (!NT_SUCCESS(Status))
goto done;
// Initialize the licensing mode - this only gets information, it doesn't
// initialize the licensing core.
LicenseModeInit(hKeyTermSrv);
// Perform the bulk of the TermSrv init.
Status = InitTermSrv(hKeyTermSrv);
if (!NT_SUCCESS(Status))
goto ShutdownService;
/*
* Indicate that we are a Terminal Server unless were asked not to
* advertise ourselves as a Terminal Server.
*/
bAdvertiseTS = TRUE;
cbValue = sizeof(dwTSAdvertise);
lReturn = RegQueryValueEx(hKeyTermSrv, REG_TERMSRV_ADVERTISE, NULL,
&dwValueType, (LPBYTE)&dwTSAdvertise, &cbValue);
if (ERROR_SUCCESS == lReturn && dwValueType == REG_DWORD)
bAdvertiseTS = dwTSAdvertise;
if (bAdvertiseTS)
SetServiceBits(gStatusHandle, SV_TYPE_TERMINALSERVER, TRUE, TRUE);
/*
* Need to do this at least once
*/
UpdateOemAndProductInfo(hKeyTermSrv);
// Initialize TermSrv and TermDD trace.
InitializeSystemTrace(hKeyTermSrv);
/*
* Set TermDD parameters.
*/
GetSetSystemParameters(hKeyTermSrv);
/*
* Initialize WinStation extension DLL support
*/
Status = WsxInit();
if (!NT_SUCCESS(Status))
goto ShutdownService;
/*
* Initialize DLL Verification mechanism.
*/
Status = VfyInit();
if (!NT_SUCCESS(Status))
goto ShutdownService;
/*
* Start WinStations
*/
StartAllWinStations(hKeyTermSrv);
// Initialize the TS Session Directory for load balancing.
// Not available on Personal TS or remote admin.
if (!g_bPersonalTS && g_fAppCompat)
InitSessionDirectory();
InitializeLoadMetrics();
// Done with init, close the TermSrv regkey.
RegCloseKey(hKeyTermSrv);
hKeyTermSrv = NULL;
/*
* Initialize WinStationAPI's
*/
Status = WinStationInitRPC();
ASSERT( NT_SUCCESS( Status ) );
if (!NT_SUCCESS(Status)) {
goto done;
}
/*
* Set break on termination flag for our process.
*/
{
NTSTATUS stp;
if ( IsKernelDebuggerAttached ()) {
stp = RtlSetProcessIsCritical(TRUE, NULL, FALSE);
if (stp == STATUS_SUCCESS) {
gBreakOnProcessExit = TRUE;
}
else {
DbgPrint("TERMSRV: RtlSetProcessIsCritical returned: %x ", stp);
}
}
}
/*
* Set the event which indicates that TermSrv is ready.
* WinLogon checks this event.
*/
if (gReadyEventHandle != NULL)
SetEvent(gReadyEventHandle);
TSStartupSalem();
return;
ShutdownService:
ShutdownService();
done:
// Kill the session directory.
if (!g_bPersonalTS && g_fAppCompat)
DestroySessionDirectory();
// In case of error, check the TermSrv regkey again.
if (hKeyTermSrv != NULL)
RegCloseKey(hKeyTermSrv);
UpdateServiceStatus(SERVICE_STOPPED, gExitStatus, 5, 0);
}
/****************************************************************************/
// Handler
//
// TermSrv service control event handler.
/****************************************************************************/
VOID Handler(DWORD fdwControl)
{
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Handler %d\n", fdwControl));
switch (fdwControl) {
case SERVICE_CONTROL_STOP:
// We absolutely do not want to be stopping TermSrv -- it is
// the only location for a lot of system-wide TS related state.
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: control code %d, stopping service...\n",
fdwControl));
if (gStatus.dwCurrentState == SERVICE_RUNNING) {
UpdateServiceStatus(SERVICE_STOP_PENDING, 0, 3, 0);
#ifdef notdef
// For now don't stop TermSRV
// The CDM service does a KeAttachProcess() to this process
if (gReadyEventHandle != NULL) {
ResetEvent(gReadyEventHandle);
CloseHandle(gReadyEventHandle);
gReadyEventHandle = NULL;
}
ShutdownService();
UpdateServiceStatus(SERVICE_STOPPED, gExitStatus, 5, 0);
#endif
}
break;
case SERVICE_CONTROL_SHUTDOWN:
DBGPRINT(("TERMSRV: control code %d, shutdown service...\n",
fdwControl));
if (gStatus.dwCurrentState == SERVICE_RUNNING) {
// 2 seconds at most to shut down.
UpdateServiceStatus(SERVICE_STOP_PENDING, 0, 4, 2000);
#ifdef notdef
// We don't trigger this event that invokes destructors for
// all of TermSrv, since on shutdown we don't want to be
// destroying machine state. We want to invoke only those
// destructors that are required for proper functioning of
// the system.
#endif
// Invoke required destruction code.
if (gReadyEventHandle != NULL) {
ResetEvent(gReadyEventHandle);
CloseHandle(gReadyEventHandle);
gReadyEventHandle = NULL;
}
ShutdownService();
UpdateServiceStatus(SERVICE_STOPPED, 0, 4, 0);
}
break;
case SERVICE_CONTROL_INTERROGATE :
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Interrogating service...\n"));
SetServiceStatus(gStatusHandle, &gStatus);
break;
default:
DBGPRINT(("TERMSRV: Unhandled control code %d\n", fdwControl));
break;
}
}
/****************************************************************************/
// ShutdownService
//
// Called by service manager to shut down the service at system shutdown
// time. This function should invoke only the most important and required
// destruction code, since we're on a strict time limit on system shutdown.
/****************************************************************************/
void ShutdownService()
{
//free authz resource manager
AuditEnd();
// Destroy the session directory so the directory can be informed to
// remove server- and session-specific information.
if (!g_bPersonalTS && g_fAppCompat)
DestroySessionDirectory();
}
/****************************************************************************/
// UpdateServiceStatus
//
// Updates the service's status to the Service Control Manager. Returns
// FALSE on error.
/****************************************************************************/
BOOL UpdateServiceStatus(
DWORD CurrentState,
DWORD ExitCode,
DWORD CheckPoint,
DWORD WaitHint)
{
// If service is starting, then disable all control requests, otherwise
// accept shutdown notifications if we are an app server, to properly
// clean up the session directory. We do not accept stop requests
// during the lifetime of the server up state, the CDM service does a
// KeAttachProcess() to this process so it must always be around.
if (gStatusHandle == NULL) {
return FALSE;
}
gStatus.dwControlsAccepted = 0;
gStatus.dwCurrentState = CurrentState;
gStatus.dwWin32ExitCode = ExitCode;
gStatus.dwCheckPoint = CheckPoint;
gStatus.dwServiceSpecificExitCode = 0;
gStatus.dwWaitHint = WaitHint;
return SetServiceStatus(gStatusHandle, &gStatus);
}
/*****************************************************************************
* LicenseModeInit
*
* Initialize the licensing mode
****************************************************************************/
void LicenseModeInit(HKEY hKeyTermSrv)
{
DWORD dwValueType;
LONG lReturn;
DWORD cbValue = sizeof( DWORD ), dwAccount = UNLEN + 1;
DWORD dwRegValue;
OSVERSIONINFO VersionInfo;
ASSERT(hKeyTermSrv != NULL);
//
// Get the user name for which the service is started under
//
GetUserName(g_tszServiceAccount, &dwAccount);
//
// Check whether Remote Admin is enabled
//
lReturn = RegQueryValueEx(hKeyTermSrv,
REG_TERMSRV_APPCOMPAT,
NULL,
&dwValueType,
(LPBYTE) &dwRegValue,
&cbValue);
if (lReturn == ERROR_SUCCESS) {
g_fAppCompat = (BOOL)dwRegValue;
}
//
// Get the product version
//
memset( &VersionInfo, 0, sizeof( OSVERSIONINFO ) );
VersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
if (GetVersionEx(&VersionInfo)) {
wsprintf( g_wszProductVersion, L"%d.%d",
VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion );
}
else {
TRACE((hTrace, TC_ICASRV, TT_ERROR, "LicenseModeInit: GetVersionEx "
"failed: 0x%x\n", GetLastError()));
}
}
//
// Get Safeboot option, code modified from ds\security\gina\winlogon\aenrlhlp.c
//
BOOL WINAPI
IsSafeBootWithNetwork()
{
DWORD dwSafeBoot = 0;
DWORD cbSafeBoot = sizeof(dwSafeBoot);
DWORD dwType = 0;
HKEY hKeySafeBoot = NULL;
if(ERROR_SUCCESS == RegOpenKeyW(
HKEY_LOCAL_MACHINE,
L"system\\currentcontrolset\\control\\safeboot\\option",
&hKeySafeBoot))
{
// we did in fact boot under safeboot control
if(ERROR_SUCCESS != RegQueryValueExW(
hKeySafeBoot,
L"OptionValue",
NULL,
&dwType,
(LPBYTE)&dwSafeBoot,
&cbSafeBoot))
{
dwSafeBoot = 0;
}
if(hKeySafeBoot)
RegCloseKey(hKeySafeBoot);
}
return ( SAFEBOOT_NETWORK == dwSafeBoot );
}