Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1087 lines
27 KiB

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
Service.c
Abstract:
Main routine to setup the exception handlers and initialize everything
to listen to LPC and RPC port requests.
Author:
Arthur Hanson (arth) Dec 07, 1994
Environment:
Revision History:
Jeff Parham (jeffparh) 05-Dec-1995
o Added certificate database support.
o Expanded file load time (the update limit sent to the service
controller) to account for certificate database loading.
o Reordered initialization such that the license purchase subsystem
is initialized before the service subsystem. (The service
subsystem now uses the license subsystem.)
o Increased internal version number.
--*/
#include <nt.h>
#include <ntlsa.h>
#include <ntsam.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <tchar.h>
#include <lm.h>
#include <alertmsg.h>
#include "llsapi.h"
#include "debug.h"
#include "llsutil.h"
#include "llssrv.h"
#include "service.h"
#include "registry.h"
#include "mapping.h"
#include "msvctbl.h"
#include "svctbl.h"
#include "perseat.h"
#include "purchase.h"
#include "server.h"
#include "repl.h"
#include "scaven.h"
#include "llsrpc_s.h"
#include "certdb.h"
VOID LLSRpcInit();
BOOLEAN LLSpLPCInitialize ( VOID );
#define INTERNAL_VERSION 0x0006
#define DEFAULT_LICENSE_CHECK_TIME 24
#define DEFAULT_REPLICATION_TIME 12 * 60 * 60
CONFIG_RECORD ConfigInfo;
RTL_CRITICAL_SECTION ConfigInfoLock;
VOID LoadAll ( );
#if DBG
DWORD TraceFlags = 0;
#endif
//
// this event is signalled when the service should end
//
HANDLE hServerStopEvent = NULL;
TCHAR MyDomain[MAX_COMPUTERNAME_LENGTH + 2];
ULONG MyDomainSize;
BOOL IsMaster = FALSE;
//
// Files
//
TCHAR MappingFileName[MAX_PATH + 1];
TCHAR UserFileName[MAX_PATH + 1];
TCHAR LicenseFileName[MAX_PATH + 1];
TCHAR CertDbFileName[MAX_PATH + 1];
extern SERVICE_STATUS_HANDLE sshStatusHandle;
/////////////////////////////////////////////////////////////////////////
NTSTATUS
NTDomainGet(
LPTSTR ServerName,
LPTSTR Domain
)
/*++
Routine Description:
Arguments:
Return Value:
None.
--*/
{
static TCHAR Serv[MAX_COMPUTERNAME_LENGTH + 3];
UNICODE_STRING us;
NTSTATUS ret;
OBJECT_ATTRIBUTES oa;
ACCESS_MASK am;
SECURITY_QUALITY_OF_SERVICE qos;
LSA_HANDLE hLSA;
PPOLICY_PRIMARY_DOMAIN_INFO pvBuffer;
lstrcpy(Domain, TEXT(""));
// only need read access
am = POLICY_READ | POLICY_VIEW_LOCAL_INFORMATION;
// set up quality of service
qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
qos.ImpersonationLevel = SecurityImpersonation;
qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
qos.EffectiveOnly = FALSE;
// Macro sets everything except security field
InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL );
oa.SecurityQualityOfService = &qos;
if ( (ServerName == NULL) || (ServerName[0] == TEXT('\0')) )
ret = LsaOpenPolicy(NULL, &oa, am, &hLSA);
else {
if (ServerName[0] == TEXT('\\'))
lstrcpy(Serv, ServerName);
else
wsprintf(Serv, TEXT("\\\\%s"), ServerName);
// Set up unicode string structure
us.Length = lstrlen(Serv) * sizeof(TCHAR);
us.MaximumLength = us.Length + sizeof(TCHAR);
us.Buffer = Serv;
ret = LsaOpenPolicy(&us, &oa, am, &hLSA);
}
if (!ret) {
ret = LsaQueryInformationPolicy(hLSA, PolicyPrimaryDomainInformation, (PVOID *) &pvBuffer);
LsaClose(hLSA);
if ((!ret) && (pvBuffer != NULL)) {
lstrcpy(Domain, pvBuffer->Name.Buffer);
LsaFreeMemory((PVOID) pvBuffer);
}
}
return ret;
} // NTDomainGet
/////////////////////////////////////////////////////////////////////////
BOOL
NTIsPDC(
LPTSTR ServerName
)
/*++
Routine Description:
Arguments:
Return Value:
None.
--*/
{
static TCHAR Serv[MAX_COMPUTERNAME_LENGTH + 3];
UNICODE_STRING us;
NTSTATUS ret;
OBJECT_ATTRIBUTES oa;
ACCESS_MASK am;
SECURITY_QUALITY_OF_SERVICE qos;
LSA_HANDLE hLSA;
PPOLICY_LSA_SERVER_ROLE_INFO pvBuffer;
BOOL IsPDC = FALSE;
if (ServerName[0] == TEXT('\\'))
lstrcpy(Serv, ServerName);
else
wsprintf(Serv, TEXT("\\\\%s"), ServerName);
// Set up unicode string structure
us.Length = lstrlen(Serv) * sizeof(TCHAR);
us.MaximumLength = us.Length + sizeof(TCHAR);
us.Buffer = Serv;
// only need read access
am = POLICY_READ | POLICY_VIEW_LOCAL_INFORMATION;
// set up quality of service
qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
qos.ImpersonationLevel = SecurityImpersonation;
qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
qos.EffectiveOnly = FALSE;
// Macro sets everything except security field
InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL );
oa.SecurityQualityOfService = &qos;
ret = LsaOpenPolicy(&us, &oa, am, &hLSA);
if (!ret) {
ret = LsaQueryInformationPolicy(hLSA, PolicyLsaServerRoleInformation, (PVOID *) &pvBuffer);
LsaClose(hLSA);
if ((!ret) && (pvBuffer != NULL)) {
if (pvBuffer->LsaServerRole == PolicyServerRolePrimary)
IsPDC = TRUE;
LsaFreeMemory((PVOID) pvBuffer);
}
}
return IsPDC;
} // NTIsPDC
/////////////////////////////////////////////////////////////////////////
DWORD
LlsTimeGet(
)
/*++
Routine Description:
Arguments:
Return Value:
Seconds since midnight.
--*/
{
DWORD Seconds;
SYSTEMTIME SysTime;
GetLocalTime(&SysTime);
Seconds = (SysTime.wHour * 24 * 60) + (SysTime.wMinute * 60) + (SysTime.wSecond);
return Seconds;
} // LlsTimeGet
/////////////////////////////////////////////////////////////////////////
VOID
ConfigInfoRegistryUpdate( )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
DWORD ReplicationType, ReplicationTime;
#if DBG
if (TraceFlags & TRACE_FUNCTION_TRACE)
dprintf(TEXT("LLS TRACE: ConfigInfoRegistryUpdate\n"));
#endif
RtlEnterCriticalSection(&ConfigInfoLock);
//
// Update values from Registry
//
ReplicationTime = ConfigInfo.ReplicationTime;
ReplicationType = ConfigInfo.ReplicationType;
ConfigInfoRegistryInit( &ConfigInfo.UseEnterprise, ConfigInfo.EnterpriseServer,
&ConfigInfo.ReplicationType, &ConfigInfo.ReplicationTime,
&ConfigInfo.LogLevel );
if ( (ConfigInfo.ReplicationTime == 0) && (LLS_REPLICATION_TYPE_TIME != ConfigInfo.ReplicationType) )
ConfigInfo.ReplicationTime = DEFAULT_REPLICATION_TIME;
//
// Adjust replication time if it has changed
//
if ((ReplicationTime != ConfigInfo.ReplicationTime) || (ReplicationType != ConfigInfo.ReplicationType))
ReplicationTimeSet();
RtlLeaveCriticalSection(&ConfigInfoLock);
} // ConfigInfoRegistryUpdate
/////////////////////////////////////////////////////////////////////////
VOID
ConfigInfoUpdate( )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
BOOL InDomain = FALSE;
BOOL IsPDC = FALSE;
USHORT cbTotalAvail, cbBuffer;
LPBYTE pbBuffer;
NET_API_STATUS uRet;
PSERVER_INFO_101 pServer1;
DWORD ReplicationType, ReplicationTime;
TCHAR pDomain[MAX_COMPUTERNAME_LENGTH + 1];
NT_PRODUCT_TYPE NtType;
#if DBG
if (TraceFlags & TRACE_FUNCTION_TRACE)
dprintf(TEXT("LLS TRACE: ConfigInfoUpdate\n"));
#endif
//
// Try to get a domain
//
lstrcpy(pDomain, TEXT(""));
if ( !NTDomainGet(NULL, pDomain) ) {
InDomain = TRUE;
//
// If we aren't a BDC/PDC then count us as a member
//
NtType = NtProductLanManNt;
RtlGetNtProductType(&NtType);
if (NtType != NtProductLanManNt)
IsPDC = FALSE;
else {
//
// Let's check if we are a PDC...
//
IsPDC = NTIsPDC(ConfigInfo.ComputerName);
}
} else {
IsPDC = TRUE;
InDomain = FALSE;
}
RtlEnterCriticalSection(&ConfigInfoLock);
ConfigInfo.IsMaster = TRUE;
ConfigInfo.Replicate = FALSE;
//
// If we are in a domain, and not the PDC then we replicate to the PDC
//
if (!IsPDC && InDomain) {
//
// Get the PDC of the domain
//
uRet = NetGetDCName(NULL, pDomain, &pbBuffer);
if (uRet == 0) {
lstrcpy(ConfigInfo.ReplicateTo, (LPWSTR) pbBuffer);
NetApiBufferFree(pbBuffer);
ConfigInfo.IsMaster = FALSE;
ConfigInfo.Replicate = TRUE;
} else {
InDomain = FALSE;
memset(ConfigInfo.ReplicateTo, 0, sizeof(ConfigInfo.ReplicateTo));
#if DBG
dprintf(TEXT("LLS: (WARNING) NetGetDCName: 0x%lX\n"), uRet);
#endif
}
}
//
// Update values from Registry
//
ReplicationTime = ConfigInfo.ReplicationTime;
ReplicationType = ConfigInfo.ReplicationType;
ConfigInfoRegistryInit( &ConfigInfo.UseEnterprise, ConfigInfo.EnterpriseServer,
&ConfigInfo.ReplicationType, &ConfigInfo.ReplicationTime,
&ConfigInfo.LogLevel );
//
// Have all registy init'd values - now need to figure out who to
// replicate to.
//
// If we are not in a domain or are a PDC then we can go to the
// Enterprise Server.
//
if (IsPDC || !InDomain) {
if (ConfigInfo.UseEnterprise) {
ConfigInfo.IsMaster = FALSE;
ConfigInfo.Replicate = TRUE;
//
// Make sure we have an enterprise server to go to
//
if ( ConfigInfo.EnterpriseServer[0] == TEXT('\0') ) {
ConfigInfo.UseEnterprise = FALSE;
ConfigInfo.IsMaster = TRUE;
ConfigInfo.Replicate = FALSE;
} else {
//
// Base ReplicateTo on enterprise server name
//
if (ConfigInfo.EnterpriseServer[0] != TEXT('\\'))
lstrcpy(ConfigInfo.ReplicateTo, TEXT("\\\\"));
else
lstrcpy(ConfigInfo.ReplicateTo, TEXT(""));
lstrcat(ConfigInfo.ReplicateTo, ConfigInfo.EnterpriseServer);
}
} else
ConfigInfo.IsMaster = TRUE;
} else
ConfigInfo.UseEnterprise = FALSE;
if (ConfigInfo.IsMaster == FALSE) {
if ( (ConfigInfo.ReplicateTo == NULL) || (lstrlen(ConfigInfo.ReplicateTo) == 0) ||
( (*ConfigInfo.ReplicateTo == TEXT('\\')) && (lstrlen(ConfigInfo.ReplicateTo) < 3) )) {
ConfigInfo.IsMaster = TRUE;
ConfigInfo.Replicate = FALSE;
}
}
//
// Adjust replication time if it has changed
//
if ((ReplicationTime != ConfigInfo.ReplicationTime) || (ReplicationType != ConfigInfo.ReplicationType))
ReplicationTimeSet();
IsMaster = ConfigInfo.IsMaster;
RtlLeaveCriticalSection(&ConfigInfoLock);
} // ConfigInfoUpdate
/////////////////////////////////////////////////////////////////////////
VOID
ConfigInfoInit( )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
DWORD Size;
TCHAR DataPath[MAX_PATH + 1];
//
// First zero init the memory
//
memset(&ConfigInfo, 0, sizeof(CONFIG_RECORD));
ConfigInfo.ComputerName = LocalAlloc(LPTR, (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(TCHAR));
ConfigInfo.ReplicateTo = LocalAlloc(LPTR, (MAX_COMPUTERNAME_LENGTH + 3) * sizeof(TCHAR));
ConfigInfo.EnterpriseServer = LocalAlloc(LPTR, (MAX_COMPUTERNAME_LENGTH + 3) * sizeof(TCHAR));
ConfigInfo.SystemDir = LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(TCHAR));
if ((ConfigInfo.ComputerName == NULL) || (ConfigInfo.ReplicateTo == NULL) || (ConfigInfo.EnterpriseServer == NULL) || (ConfigInfo.SystemDir == NULL) ) {
ASSERT(FALSE);
}
ConfigInfo.Version = INTERNAL_VERSION;
GetLocalTime(&ConfigInfo.Started);
//
// LastReplicated is just for display, LlsReplTime is what is used to
// Calculate it.
GetLocalTime(&ConfigInfo.LastReplicated);
ConfigInfo.LastReplicatedSeconds = DateSystemGet();
GetSystemDirectory(ConfigInfo.SystemDir, MAX_PATH);
lstrcat(ConfigInfo.SystemDir, TEXT("\\"));
ConfigInfo.IsMaster = TRUE;
ConfigInfo.Replicate = FALSE;
ConfigInfo.IsReplicating = FALSE;
ConfigInfo.ReplicationType = REPLICATE_DELTA;
ConfigInfo.ReplicationTime = DEFAULT_REPLICATION_TIME;
Size = MAX_COMPUTERNAME_LENGTH + 1;
GetComputerName(ConfigInfo.ComputerName, &Size);
NTDomainGet( ConfigInfo.ComputerName, MyDomain);
lstrcat(MyDomain, TEXT("\\"));
MyDomainSize = (lstrlen(MyDomain) + 1) * sizeof(TCHAR);
RtlInitializeCriticalSection(&ConfigInfoLock);
ConfigInfoUpdate();
//
// Create File paths
//
lstrcpy(MappingFileName, ConfigInfo.SystemDir);
lstrcat(MappingFileName, TEXT(LLS_FILE_SUBDIR));
lstrcat(MappingFileName, TEXT("\\"));
lstrcat(MappingFileName, TEXT(MAP_FILE_NAME));
lstrcpy(UserFileName, ConfigInfo.SystemDir);
lstrcat(UserFileName, TEXT(LLS_FILE_SUBDIR));
lstrcat(UserFileName, TEXT("\\"));
lstrcat(UserFileName, TEXT(USER_FILE_NAME));
lstrcpy(CertDbFileName, ConfigInfo.SystemDir);
lstrcat(CertDbFileName, TEXT(LLS_FILE_SUBDIR));
lstrcat(CertDbFileName, TEXT("\\"));
lstrcat(CertDbFileName, TEXT(CERT_DB_FILE_NAME));
lstrcpy(LicenseFileName, ConfigInfo.SystemDir);
lstrcat(LicenseFileName, TEXT(LICENSE_FILE_NAME));
//
// Make sure our directory is there.
//
lstrcpy(DataPath, ConfigInfo.SystemDir);
lstrcat(DataPath, TEXT(LLS_FILE_SUBDIR));
CreateDirectory(DataPath, NULL);
} // ConfigInfoInit
/////////////////////////////////////////////////////////////////////////
DWORD WINAPI
LLSTopLevelExceptionHandler(
struct _EXCEPTION_POINTERS *ExceptionInfo
)
/*++
Routine Description:
The Top Level exception filter for LLSMain.exe.
This ensures the entire process will be cleaned up if any of
the threads fail. Since LLSMain.exe is a distributed application,
it is better to fail the entire process than allow random threads
to continue executing.
Arguments:
ExceptionInfo - Identifies the exception that occurred.
Return Values:
EXCEPTION_EXECUTE_HANDLER - Terminate the process.
EXCEPTION_CONTINUE_SEARCH - Continue processing as though this filter
was never called.
--*/
{
HANDLE hModule;
//
// Raise an alert
//
hModule = LoadLibraryA("netapi32");
if ( hModule != NULL ) {
NET_API_STATUS (NET_API_FUNCTION *NetAlertRaiseExFunction)
(LPTSTR, LPVOID, DWORD, LPTSTR);
NetAlertRaiseExFunction =
(NET_API_STATUS (NET_API_FUNCTION *) (LPTSTR, LPVOID, DWORD, LPTSTR))
GetProcAddress(hModule, "NetAlertRaiseEx");
if ( NetAlertRaiseExFunction != NULL ) {
NTSTATUS Status;
UNICODE_STRING Strings;
char message[ALERTSZ + sizeof(ADMIN_OTHER_INFO)];
PADMIN_OTHER_INFO admin = (PADMIN_OTHER_INFO) message;
//
// Build the variable data
//
admin->alrtad_errcode = ALERT_UnhandledException;
admin->alrtad_numstrings = 0;
Strings.Buffer = (LPWSTR) ALERT_VAR_DATA(admin);
Strings.Length = 0;
Strings.MaximumLength = ALERTSZ;
Status = RtlIntegerToUnicodeString(
(ULONG)ExceptionInfo->ExceptionRecord->ExceptionCode,
16,
&Strings );
if ( NT_SUCCESS(Status) ) {
if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
admin->alrtad_numstrings++;
*(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0';
Strings.Length += sizeof(WCHAR);
Status = RtlAppendUnicodeToString( &Strings, L"LLS" );
}
}
if ( NT_SUCCESS(Status) ) {
if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
admin->alrtad_numstrings++;
*(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0';
Strings.Buffer += (Strings.Length/sizeof(WCHAR)) + 1;
Strings.MaximumLength -= Strings.Length + sizeof(WCHAR);
Strings.Length = 0;
Status = RtlIntegerToUnicodeString(
(ULONG)ExceptionInfo->ExceptionRecord->ExceptionAddress,
16,
&Strings );
}
}
if ( NT_SUCCESS(Status) ) {
if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
admin->alrtad_numstrings++;
*(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0';
Strings.Buffer += (Strings.Length/sizeof(WCHAR)) + 1;
(VOID) (*NetAlertRaiseExFunction)(
ALERT_ADMIN_EVENT,
message,
(DWORD)((PCHAR)Strings.Buffer -
(PCHAR)message),
L"LLS" );
}
}
}
(VOID) FreeLibrary( hModule );
}
//
// Just continue processing the exception.
//
return EXCEPTION_CONTINUE_SEARCH;
} // LLSTopLevelExceptionHandler
/////////////////////////////////////////////////////////////////////////
VOID
ServiceStart (
DWORD dwArgc,
LPTSTR *lpszArgv
)
/*++
Routine Description:
The code that starts everything, is really the main().
Arguments:
None.
Return Values:
None.
--*/
{
DWORD dwWait;
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN EnableAlignmentFaults = TRUE;
KPRIORITY BasePriority;
///////////////////////////////////////////////////
//
// Service initialization
//
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
//
// Create the event object. The control handler function signals
// this event when it receives the "stop" control code.
//
hServerStopEvent = CreateEvent(
NULL, // no security attributes
TRUE, // manual reset event
FALSE, // not-signalled
NULL); // no name
if ( hServerStopEvent == NULL)
goto Cleanup;
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
//
// Define a top-level exception handler for the entire process.
//
(VOID) SetErrorMode( SEM_FAILCRITICALERRORS );
(VOID) SetUnhandledExceptionFilter( &LLSTopLevelExceptionHandler );
//
// Turn on alignment fault fixups. This is necessary because
// several structures stored in the registry have qword aligned
// fields. They are nicely aligned in our structures, but they
// end up being forced out of alignment when being stored because
// the registry api require data to be passed following a wierd
// length header.
//
Status = NtSetInformationProcess(
NtCurrentProcess(),
ProcessEnableAlignmentFaultFixup,
(PVOID) &EnableAlignmentFaults,
sizeof(BOOLEAN)
);
ASSERT(NT_SUCCESS(Status));
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
//
// Run the LLS in the foreground.
//
// Several processes which depend on the LLS (like the lanman server)
// run in the foreground. If we don't run in the foreground, they'll
// starve waiting for us.
//
BasePriority = FOREGROUND_BASE_PRIORITY;
Status = NtSetInformationProcess(
NtCurrentProcess(),
ProcessBasePriority,
&BasePriority,
sizeof(BasePriority)
);
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize the Registry values...
RegistryInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize the Registry values...
ConfigInfoInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize the Service Table
LicenseListInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize the Service Table
MasterServiceListInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize the Service Table
LocalServiceListInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize the Service Table
ServiceListInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize the Service Table
MappingListInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize the Per-Seat Table
UserListInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize the Service Table
ServerListInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize the Certificate Database
CertDbInit();
//
// Report the status to the service control manager - need a bit longer
// to read in all the data files.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 15000)) // wait hint
goto Cleanup;
// Load data files
LoadAll();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize RPC Stuff...
LLSRpcInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize Replication...
ReplicationInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize scavenger thread...
ScavengerInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 3000)) // wait hint
goto Cleanup;
// Initialize RegistryMonitor thread...
RegistryStartMonitor();
//
// End of initialization
//
////////////////////////////////////////////////////////
//
// Tell SCM we are up and running!
//
if (!ReportStatusToSCMgr( SERVICE_RUNNING, NO_ERROR, 0)) // wait hint
goto Cleanup;
////////////////////////////////////////////////////////
//
// Service is now running, perform work until shutdown
//
dwWait = WaitForSingleObject(hServerStopEvent, INFINITE);
Cleanup:
if (hServerStopEvent)
CloseHandle(hServerStopEvent);
if (sshStatusHandle)
ReportStatusToSCMgr( SERVICE_STOPPED, NO_ERROR, 0);
} // ServiceStart
/////////////////////////////////////////////////////////////////////////
VOID ServiceStop()
/*++
Routine Description:
Stops the service.
If a ServiceStop procedure is going to take longer than 3 seconds to
execute, it should spawn a thread to execute the stop code, and return.
Otherwise, the ServiceControlManager will believe that the service has
stopped responding.
Arguments:
None.
Return Values:
None.
--*/
{
if ( hServerStopEvent )
SetEvent(hServerStopEvent);
} // ServiceStop
#if DBG
/////////////////////////////////////////////////////////////////////////
VOID
ConfigInfoDebugDump( )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
RtlEnterCriticalSection(&ConfigInfoLock);
dprintf(TEXT("License Logging Service - Version: 0x%lX\n"), ConfigInfo.Version);
dprintf(TEXT(" Started: %u-%u-%u @ %u:%u:%u\n"),
(UINT) ConfigInfo.Started.wDay,
(UINT) ConfigInfo.Started.wMonth,
(UINT) ConfigInfo.Started.wYear,
(UINT) ConfigInfo.Started.wHour,
(UINT) ConfigInfo.Started.wMinute,
(UINT) ConfigInfo.Started.wSecond );
dprintf(TEXT(" Replication\n"));
dprintf(TEXT(" +--------------+\n"));
if (ConfigInfo.IsMaster)
dprintf(TEXT(" Master Server\n"));
else
dprintf(TEXT(" NOT Master Server\n"));
if (ConfigInfo.Replicate)
dprintf(TEXT(" Replicates\n"));
else
dprintf(TEXT(" Does not Replicate\n"));
if (ConfigInfo.IsReplicating)
dprintf(TEXT(" Currently Replicating\n"));
else
dprintf(TEXT(" NOT Currently Replicating\n"));
dprintf(TEXT(" Replicates To: %s\n"), ConfigInfo.ReplicateTo);
dprintf(TEXT(" Enterprise Server: %s\n"), ConfigInfo.EnterpriseServer);
if (ConfigInfo.ReplicationType == REPLICATE_DELTA)
dprintf(TEXT(" Replicate Every: %lu Seconds\n"), ConfigInfo.ReplicationTime );
else
dprintf(TEXT(" Replicate @: %lu\n"), ConfigInfo.ReplicationTime );
dprintf(TEXT("\n Last Replicated: %u-%u-%u @ %u:%u:%u\n\n"),
(UINT) ConfigInfo.LastReplicated.wDay,
(UINT) ConfigInfo.LastReplicated.wMonth,
(UINT) ConfigInfo.LastReplicated.wYear,
(UINT) ConfigInfo.LastReplicated.wHour,
(UINT) ConfigInfo.LastReplicated.wMinute,
(UINT) ConfigInfo.LastReplicated.wSecond );
dprintf(TEXT(" Number Servers Currently Replicating: %lu\n"), ConfigInfo.NumReplicating);
dprintf(TEXT(" Current Backoff Time Delta: %lu\n"), ConfigInfo.BackoffTime);
dprintf(TEXT(" Current Replication Speed: %lu\n"), ConfigInfo.ReplicationSpeed);
RtlLeaveCriticalSection(&ConfigInfoLock);
} // ConfigInfoDebugDump
#endif