windows-nt/Source/XPSP1/NT/termsrv/license/tlserver/server/service.cpp

1629 lines
40 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996-1998
//
// File: service.c
//
// Contents: Hydra License Server Service Control Manager Interface
//
// History: 12-09-97 HueiWang Modified from MSDN RPC Service Sample
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#include <winsock2.h>
#include <ws2tcpip.h>
#include "server.h"
#include "globals.h"
#include "init.h"
#include "postsrv.h"
#include "tlsbkup.h"
#define SERVICE_WAITHINT 60*1000 // WaitHint 1 mins.
#define SERVICE_SHUTDOWN_WAITTIME 15*60*1000 // must have shutdown already.
//---------------------------------------------------------------------------
//
// internal function prototypes
//
BOOL
ReportStatusToSCMgr(
DWORD,
DWORD,
DWORD
);
DWORD
ServiceStart(
DWORD,
LPTSTR *,
BOOL bDebug=FALSE
);
VOID WINAPI
ServiceCtrl(
DWORD
);
VOID WINAPI
ServiceMain(
DWORD,
LPTSTR *
);
VOID
CmdDebugService(
int,
char **,
BOOL
);
BOOL WINAPI
ControlHandler(
DWORD
);
extern "C" VOID
ServiceStop();
VOID
ServicePause();
VOID
ServiceContinue();
HANDLE hRpcPause=NULL;
///////////////////////////////////////////////////////////
//
// internal variables
//
SERVICE_STATUS_HANDLE sshStatusHandle;
DWORD ssCurrentStatus; // current status of the service
BOOL g_bReportToSCM = TRUE;
HANDLE gSafeToTerminate=NULL;
HRESULT hrStatus = NULL;
DEFINE_GUID(TLS_WRITER_GUID, 0x5382579c, 0x98df, 0x47a7, 0xac, 0x6c, 0x98, 0xa6, 0xd7, 0x10, 0x6e, 0x9);
GUID idWriter = TLS_WRITER_GUID;
CVssJetWriter *g_pWriter = NULL;
SERVICE_TABLE_ENTRY dispatchTable[] =
{
{ _TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)ServiceMain },
{ NULL, NULL }
};
//-----------------------------------------------------------------
// Internal routine
//-----------------------------------------------------------------
void print_usage()
{
_ftprintf(
stdout,
_TEXT("Usage : %s can't be run as a console app\n"),
_TEXT(SZAPPNAME)
);
return;
}
//-----------------------------------------------------------------
DWORD
AddNullSessionPipe(
IN LPTSTR szPipeName
)
/*++
Abstract:
Add our RPC namedpipe into registry to allow unrestricted access.
Parameter:
szPipeName : name of the pipe to append.
Returns:
ERROR_SUCCESS or error code
--*/
{
LPTSTR lpszKey=L"SYSTEM\\CurrentControlSet\\Services\\LanmanServer\\Parameters";
LPTSTR lpszValue=L"NullSessionPipes";
HKEY hKey;
DWORD dwStatus;
LPTSTR pbData=NULL, pbOrg=NULL;
DWORD cbData = 0;
dwStatus = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
lpszKey,
0,
KEY_ALL_ACCESS,
&hKey
);
if(dwStatus != ERROR_SUCCESS)
return dwStatus;
dwStatus = RegQueryValueEx(
hKey,
lpszValue,
NULL,
NULL,
NULL,
&cbData
);
if(dwStatus != ERROR_MORE_DATA && dwStatus != ERROR_SUCCESS)
return dwStatus;
// pre-allocate our pipe name
if(!(pbData = (LPTSTR)AllocateMemory(cbData + (_tcslen(szPipeName) + 1) * sizeof(TCHAR))))
return GetLastError();
dwStatus = RegQueryValueEx(
hKey,
lpszValue,
NULL,
NULL,
(LPBYTE)pbData,
&cbData
);
BOOL bAddPipe=TRUE;
pbOrg = pbData;
// check pipe name
while(*pbData)
{
if(!_tcsicmp(pbData, szPipeName))
{
bAddPipe=FALSE;
break;
}
pbData += _tcslen(pbData) + 1;
}
if(bAddPipe)
{
_tcscat(pbData, szPipeName);
cbData += (_tcslen(szPipeName) + 1) * sizeof(TCHAR);
dwStatus = RegSetValueEx(
hKey,
lpszValue,
0,
REG_MULTI_SZ,
(PBYTE)pbOrg,
cbData
);
}
FreeMemory(pbOrg);
RegCloseKey(hKey);
return dwStatus;
}
//-----------------------------------------------------------------
void __cdecl
trans_se_func(
unsigned int u,
_EXCEPTION_POINTERS* pExp
)
/*++
--*/
{
#if DBG
OutputDebugString(_TEXT("Translating SE exception...\n"));
#endif
throw SE_Exception( u );
}
//-----------------------------------------------------------------
int __cdecl
handle_new_failed(
size_t size
)
/*++
--*/
{
#if DBG
OutputDebugString(_TEXT("handle_new_failed() invoked...\n"));
#endif
//
// Raise exception here, STL does not check return pointer
//
RaiseException(
ERROR_OUTOFMEMORY,
0,
0,
NULL
);
//
// stop memory allocation attemp.
//
return 0;
}
//-----------------------------------------------------------------
void _cdecl
main(
int argc,
char **argv
)
/*++
Abstract
Entry point.
++*/
{
// LARGE_INTEGER Time = USER_SHARED_DATA->SystemExpirationDate;
_set_new_handler(handle_new_failed);
_set_new_mode(1);
gSafeToTerminate = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
);
if(gSafeToTerminate == NULL)
{
TLSLogErrorEvent(TLS_E_ALLOCATE_RESOURCE);
// out of resource.
return;
}
for(int i=1; i < argc; i++)
{
if(*argv[i] == '-' || *argv[i] == '/')
{
if(!_stricmp("noservice", argv[i]+1))
{
g_bReportToSCM = FALSE;
}
else if(!_stricmp("cleanup", argv[i]+1))
{
CleanSetupLicenseServer();
exit(0);
}
else
{
print_usage();
exit(0);
}
}
}
if(g_bReportToSCM == FALSE)
{
CmdDebugService(
argc,
argv,
!g_bReportToSCM
);
}
else if(!StartServiceCtrlDispatcher(dispatchTable))
{
TLSLogErrorEvent(TLS_E_SC_CONNECT);
}
WaitForSingleObject(gSafeToTerminate, INFINITE);
CloseHandle(gSafeToTerminate);
}
//-----------------------------------------------------------------
void WINAPI
ServiceMain(
IN DWORD dwArgc,
IN LPTSTR *lpszArgv
)
/*++
Abstract:
To perform actual initialization of the service
Parameter:
dwArgc - number of command line arguments
lpszArgv - array of command line arguments
Returns:
none
++*/
{
DWORD dwStatus;
// register our service control handler:
sshStatusHandle = RegisterServiceCtrlHandler(
_TEXT(SZSERVICENAME),
ServiceCtrl
);
if (sshStatusHandle)
{
ssCurrentStatus=SERVICE_START_PENDING;
// report the status to the service control manager.
//
if(ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
SERVICE_WAITHINT)) // wait hint
{
dwStatus = ServiceStart(
dwArgc,
lpszArgv
);
if(dwStatus != ERROR_SUCCESS)
{
ReportStatusToSCMgr(
SERVICE_STOPPED,
dwStatus,
0
);
}
else
{
ReportStatusToSCMgr(
SERVICE_STOPPED,
NO_ERROR,
0
);
}
}
}
else
{
dwStatus = GetLastError();
TLSLogErrorEvent(TLS_E_SC_CONNECT);
}
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_INIT,
DBGLEVEL_FUNCTION_TRACE,
_TEXT("Service terminated...\n")
);
return;
}
//-------------------------------------------------------------
VOID WINAPI
ServiceCtrl(
IN DWORD dwCtrlCode
)
/*+++
Abstract:
This function is called by the SCM whenever
ControlService() is called on this service.
Parameter:
dwCtrlCode - type of control requested from SCM.
+++*/
{
// Handle the requested control code.
//
switch(dwCtrlCode)
{
// Stop the service.
//
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
NO_ERROR,
0
);
ServiceStop();
break;
// We don't really accept pause and continue
case SERVICE_CONTROL_PAUSE:
ReportStatusToSCMgr(
SERVICE_PAUSED,
NO_ERROR,
0
);
ServicePause();
break;
case SERVICE_CONTROL_CONTINUE:
ReportStatusToSCMgr(
SERVICE_RUNNING,
NO_ERROR,
0
);
ServiceContinue();
break;
// Update the service status.
case SERVICE_CONTROL_INTERROGATE:
ReportStatusToSCMgr(
ssCurrentStatus,
NO_ERROR,
0
);
break;
// invalid control code
default:
break;
}
}
//------------------------------------------------------------------
DWORD
ServiceShutdownThread(
void *p
)
/*++
Abstract:
Entry point into thread that shutdown server (mainly database).
Parameter:
Ignore
++*/
{
ServerShutdown();
ExitThread(ERROR_SUCCESS);
return ERROR_SUCCESS;
}
//------------------------------------------------------------------
DWORD
RPCServiceStartThread(
void *p
)
/*++
Abstract:
Entry point to thread that startup RPC.
Parameter:
None.
Return:
Thread exit code.
++*/
{
RPC_BINDING_VECTOR *pbindingVector = NULL;
RPC_STATUS status = RPC_S_OK;
WCHAR *pszEntryName = _TEXT(RPC_ENTRYNAME);
DWORD dwNumSuccessRpcPro=0;
do {
//
// local procedure call
//
status = RpcServerUseProtseq(
_TEXT(RPC_PROTOSEQLPC),
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
NULL // &SecurityDescriptor
);
if(status == RPC_S_OK)
{
dwNumSuccessRpcPro++;
}
//
// NT4 backward compatible issue, let NT4 termsrv serivce
// client connect so still set security descriptor
//
// 11/10/98 Tested on NT4 and NT5
//
//
// Namedpipe
//
status = RpcServerUseProtseqEp(
_TEXT(RPC_PROTOSEQNP),
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
_TEXT(LSNAMEPIPE),
NULL //&SecurityDescriptor
);
if(status == RPC_S_OK)
{
dwNumSuccessRpcPro++;
}
//
// TCP/IP
//
status = RpcServerUseProtseq(
_TEXT(RPC_PROTOSEQTCP),
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
NULL //&SecurityDescriptor
);
if(status == RPC_S_OK)
{
dwNumSuccessRpcPro++;
}
// Must have at least one protocol.
if(dwNumSuccessRpcPro == 0)
{
status = TLS_E_RPC_PROTOCOL;
break;
}
// Get server binding handles
status = RpcServerInqBindings(&pbindingVector);
if (status != RPC_S_OK)
{
status = TLS_E_RPC_INQ_BINDING;
break;
}
// Register interface(s) and binding(s) (endpoints) with
// the endpoint mapper.
status = RpcEpRegister(
TermServLicensing_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector,
NULL, // &export_uuid,
L""
);
if (status != RPC_S_OK)
{
status = TLS_E_RPC_EP_REGISTER;
break;
}
status = RpcServerRegisterIf(
TermServLicensing_v1_0_s_ifspec,
NULL,
NULL);
if(status != RPC_S_OK)
{
status = TLS_E_RPC_REG_INTERFACE;
break;
}
// Register interface(s) and binding(s) (endpoints) with
// the endpoint mapper.
status = RpcEpRegister(
HydraLicenseService_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector,
NULL, // &export_uuid,
L"");
if (status != RPC_S_OK)
{
status = TLS_E_RPC_EP_REGISTER;
break;
}
status = RpcServerRegisterIf(
HydraLicenseService_v1_0_s_ifspec,
NULL,
NULL);
if(status != RPC_S_OK)
{
status = TLS_E_RPC_REG_INTERFACE;
break;
}
// Register interface(s) and binding(s) (endpoints) with
// the endpoint mapper.
status = RpcEpRegister(
TermServLicensingBackup_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector,
NULL, // &export_uuid,
L"");
if (status != RPC_S_OK)
{
status = TLS_E_RPC_EP_REGISTER;
break;
}
status = RpcServerRegisterIf(
TermServLicensingBackup_v1_0_s_ifspec,
NULL,
NULL);
if(status != RPC_S_OK)
{
status = TLS_E_RPC_REG_INTERFACE;
break;
}
// Enable NT LM Security Support Provider (NtLmSsp service)
status = RpcServerRegisterAuthInfo(0,
RPC_C_AUTHN_WINNT,
0,
0);
if (status != RPC_S_OK)
{
status = TLS_E_RPC_SET_AUTHINFO;
break;
}
} while(FALSE);
if(status != RPC_S_OK)
{
TLSLogEvent(
EVENTLOG_ERROR_TYPE,
TLS_E_SERVICEINIT,
TLS_E_INITRPC,
status
);
status = TLS_E_SERVICE_STARTUP;
}
ExitThread(status);
return status;
}
//------------------------------------------------------------------------
unsigned int __stdcall
GetLServerRoleInDomain(
PVOID pData
)
/*++
--*/
{
SERVER_ROLE_IN_DOMAIN* srvRole = (SERVER_ROLE_IN_DOMAIN *)pData;
if(pData != NULL)
{
*srvRole = GetServerRoleInDomain(NULL);
}
_endthreadex(0);
return 0;
}
//------------------------------------------------------------------------
DWORD
ServiceStart(
IN DWORD dwArgc,
IN LPTSTR *lpszArgv,
IN BOOL bDebug
)
/*
*/
{
RPC_BINDING_VECTOR *pbindingVector = NULL;
WCHAR *pszEntryName = _TEXT(RPC_ENTRYNAME);
HANDLE hInitThread=NULL;
HANDLE hRpcThread=NULL;
HANDLE hMailslotThread=NULL;
HANDLE hShutdownThread=NULL;
DWORD dump;
HANDLE hEvent=NULL;
DWORD dwStatus=ERROR_SUCCESS;
WORD wVersionRequested;
WSADATA wsaData;
int err;
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING,
NO_ERROR,
SERVICE_WAITHINT))
{
// resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS;
goto cleanup;
}
hrStatus = CoInitializeEx (NULL, COINIT_MULTITHREADED);
if (FAILED (hrStatus))
{
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_INIT,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("CoInitializeEx failed with error code %08x...\n"),
hrStatus
);
}
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING,
NO_ERROR,
SERVICE_WAITHINT))
{
// resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS;
goto cleanup;
}
if (SUCCEEDED (hrStatus))
{
hrStatus = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_CONNECT,
RPC_C_IMP_LEVEL_IDENTIFY,
NULL,
EOAC_NONE,
NULL
);
}
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING,
NO_ERROR,
SERVICE_WAITHINT))
{
// resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS;
goto cleanup;
}
if (SUCCEEDED (hrStatus))
{
g_pWriter = new CVssJetWriter;
if (NULL == g_pWriter)
{
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_INIT,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("new CVssJetWriter failed...\n")
);
hrStatus = HRESULT_FROM_WIN32 (ERROR_NOT_ENOUGH_MEMORY);
}
}
// Report the status to the service control manager.
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING,
NO_ERROR,
SERVICE_WAITHINT))
{
// resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS;
goto cleanup;
}
{
DWORD dwConsole;
DWORD dwDbLevel;
DWORD dwType;
DWORD dwSize = sizeof(dwConsole);
DWORD status;
HKEY hKey=NULL;
status = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
LSERVER_PARAMETERS_KEY,
0,
KEY_ALL_ACCESS,
&hKey);
if(status == ERROR_SUCCESS)
{
if(RegQueryValueEx(
hKey,
LSERVER_PARAMETERS_CONSOLE,
NULL,
&dwType,
(LPBYTE)&dwConsole,
&dwSize
) != ERROR_SUCCESS)
{
dwConsole = 0;
}
dwSize = sizeof(dwDbLevel);
if(RegQueryValueEx(
hKey,
LSERVER_PARAMETERS_LOGLEVEL,
NULL,
&dwType,
(LPBYTE)&dwDbLevel,
&dwSize
) == ERROR_SUCCESS)
{
InitDBGPrintf(
dwConsole != 0,
_TEXT(SZSERVICENAME),
dwDbLevel
);
}
RegCloseKey(hKey);
}
}
// Report the status to the service control manager.
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING,
NO_ERROR,
SERVICE_WAITHINT))
{
// resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS;
goto cleanup;
}
do {
// setup should have done this but just to make sure we have our
// pipe in NullSessionPipe to allow service to connect
AddNullSessionPipe(_TEXT(HLSPIPENAME));
AddNullSessionPipe(_TEXT(SZSERVICENAME));
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup(
wVersionRequested,
&wsaData
);
if(err != 0)
{
// None critical error
TLSLogWarningEvent(
TLS_E_SERVICE_WSASTARTUP
);
}
else
{
char hostname[(MAXTCPNAME+1)*sizeof(TCHAR)];
err=gethostname(hostname, MAXTCPNAME*sizeof(TCHAR));
if(err == 0)
{
struct addrinfo *paddrinfo;
struct addrinfo hints;
memset(&hints,0,sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = PF_UNSPEC;
if (0 == getaddrinfo(hostname,NULL,&hints,&paddrinfo))
{
err = (MultiByteToWideChar(
GetACP(),
MB_ERR_INVALID_CHARS,
paddrinfo->ai_canonname,
-1,
g_szHostName,
g_cbHostName) == 0) ? -1 : 0;
}
else
{
err = -1;
}
freeaddrinfo(paddrinfo);
}
}
if(err != 0)
{
if(GetComputerName(g_szHostName, &g_cbHostName) == FALSE)
{
dwStatus = GetLastError();
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_INIT,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("GetComputerName() failed with %d...\n"),
dwStatus
);
// this shoule not happen...
TLSLogErrorEvent(TLS_E_INIT_GENERAL);
break;
}
}
if(GetComputerName(g_szComputerName, &g_cbComputerName) == FALSE)
{
dwStatus = GetLastError();
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_INIT,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("GetComputerName() failed with %d...\n"),
dwStatus
);
// this shoule not happen...
TLSLogErrorEvent(TLS_E_INIT_GENERAL);
break;
}
hRpcPause=CreateEvent(NULL, TRUE, TRUE, NULL);
if(!hRpcPause)
{
TLSLogErrorEvent(TLS_E_ALLOCATE_RESOURCE);
dwStatus = TLS_E_ALLOCATE_RESOURCE;
break;
}
//
// start up general server and RPC initialization thread
//
hInitThread=ServerInit(bDebug);
if(hInitThread==NULL)
{
TLSLogErrorEvent(TLS_E_SERVICE_STARTUP_CREATE_THREAD);
dwStatus = TLS_E_SERVICE_STARTUP_CREATE_THREAD;
break;
}
dwStatus = ERROR_SUCCESS;
//
// Wait for general server init. thread to terminate
//
while(WaitForSingleObject( hInitThread, 100 ) == WAIT_TIMEOUT)
{
// Report the status to the service control manager.
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING,
NO_ERROR,
SERVICE_WAITHINT))
{
// resource leak but something went wrong already.
dwStatus = TLS_E_SC_REPORT_STATUS;
break;
}
}
if(dwStatus != ERROR_SUCCESS)
{
break;
}
// Check thread exit code.
GetExitCodeThread(
hInitThread,
&dwStatus
);
if(dwStatus != ERROR_SUCCESS)
{
//
// Server init. thread logs its own error
//
dwStatus = TLS_E_SERVICE_STARTUP_INIT_THREAD_ERROR;
break;
}
CloseHandle(hInitThread);
hInitThread=NULL;
// timing, if we startup RPC init thread but database init thread
// can't initialize, service will be in forever stop state.
hRpcThread=CreateThread(
NULL,
0,
RPCServiceStartThread,
ULongToPtr(bDebug),
0,
&dump
);
if(hRpcThread == NULL)
{
TLSLogErrorEvent(TLS_E_SERVICE_STARTUP_CREATE_THREAD);
dwStatus=TLS_E_SERVICE_STARTUP_CREATE_THREAD;
break;
}
dwStatus = ERROR_SUCCESS;
//
// Wait for RPC init. thread to terminate
//
while(WaitForSingleObject( hRpcThread, 100 ) == WAIT_TIMEOUT)
{
// Report the status to the service control manager.
if (!ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
SERVICE_WAITHINT)) // wait hint
{
dwStatus = TLS_E_SC_REPORT_STATUS;
break;
}
}
if(dwStatus != ERROR_SUCCESS)
{
break;
}
// Check thread exit code.
GetExitCodeThread(hRpcThread, &dwStatus);
if(dwStatus != ERROR_SUCCESS)
{
dwStatus = TLS_E_SERVICE_STARTUP_RPC_THREAD_ERROR;
break;
}
CloseHandle(hRpcThread);
hRpcThread=NULL;
//
// Tell server control manager that we are ready.
//
if (!ReportStatusToSCMgr(
SERVICE_RUNNING, // service state
NO_ERROR, // exit code
SERVICE_WAITHINT // wait hint
))
{
dwStatus = TLS_E_SC_REPORT_STATUS;
break;
}
//
// Post service init. load self-signed certificate and init. crypt.
// this is needed after reporting service running status back to
// service control manager because it may need to manually call
// StartService() to startup protected storage service.
//
if(InitCryptoAndCertificate() != ERROR_SUCCESS)
{
dwStatus = TLS_E_SERVICE_STARTUP_POST_INIT;
break;
}
TLSLogInfoEvent(TLS_I_SERVICE_START);
// RpcMgmtWaitServerListen() will block until the server has
// stopped listening. If this service had something better to
// do with this thread, it would delay this call until
// ServiceStop() had been called. (Set an event in ServiceStop()).
//
BOOL bOtherServiceStarted = FALSE;
do {
WaitForSingleObject(hRpcPause, INFINITE);
if(ssCurrentStatus == SERVICE_STOP_PENDING)
{
break;
}
// Start accepting client calls.PostServiceInit
dwStatus = RpcServerListen(
RPC_MINIMUMCALLTHREADS,
RPC_MAXIMUMCALLTHREADS,
TRUE
);
if(dwStatus != RPC_S_OK)
{
TLSLogErrorEvent(TLS_E_RPC_LISTEN);
dwStatus = TLS_E_SERVICE_RPC_LISTEN;
break;
}
//
// Initialize all policy module
//
if(bOtherServiceStarted == FALSE)
{
dwStatus = PostServiceInit();
if(dwStatus != ERROR_SUCCESS)
{
// faild to initialize.
break;
}
//ServiceInitPolicyModule();
}
bOtherServiceStarted = TRUE;
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_INIT,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("Ready to accept request...\n")
);
dwStatus = RpcMgmtWaitServerListen();
assert(dwStatus == RPC_S_OK);
} while(TRUE);
// tell service control manager we are stopping
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
NO_ERROR,
SERVICE_WAITHINT
);
//
// Terminate - ignore all error here on
//
dwStatus = RpcServerUnregisterIf(
TermServLicensingBackup_v1_0_s_ifspec,
NULL,
TRUE
);
// tell service control manager we are stopping
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
NO_ERROR,
SERVICE_WAITHINT
);
dwStatus = RpcServerUnregisterIf(
HydraLicenseService_v1_0_s_ifspec,
NULL,
TRUE
);
// tell service control manager we are stopping
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
NO_ERROR,
SERVICE_WAITHINT
);
dwStatus = RpcServerUnregisterIf(
TermServLicensing_v1_0_s_ifspec, // from rpcsvc.h
NULL,
TRUE
);
// tell service control manager we are stopping
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
NO_ERROR,
SERVICE_WAITHINT
);
// Remove entries from the endpoint mapper database.
dwStatus = RpcEpUnregister(
HydraLicenseService_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector,
NULL
);
// tell service control manager we are stopping
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
NO_ERROR,
SERVICE_WAITHINT
);
// Remove entries from the endpoint mapper database.
dwStatus = RpcEpUnregister(
TermServLicensing_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector,
NULL
);
// tell service control manager we are stopping
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
NO_ERROR,
SERVICE_WAITHINT
);
// Remove entries from the endpoint mapper database.
dwStatus = RpcEpUnregister(
TermServLicensingBackup_v1_0_s_ifspec, // from rpcsvc.h
pbindingVector,
NULL
);
// Get server binding handles
dwStatus = RpcServerInqBindings(
&pbindingVector
);
if(dwStatus == ERROR_SUCCESS)
{
dwStatus = RpcBindingVectorFree(
&pbindingVector
);
}
// Create entry name in name database first
// Only work for NT 5.0
// status = RpcNsMgmtEntryDelete(RPC_C_NS_SYNTAX_DEFAULT, pszEntryName);
// try to report the stopped status to the service control manager.
//
// Initialize Crypto.
} while(FALSE);
if(hInitThread != NULL)
{
CloseHandle(hInitThread);
}
if(hRpcThread != NULL)
{
CloseHandle(hRpcThread);
}
if(hMailslotThread != NULL)
{
CloseHandle(hMailslotThread);
}
if(hEvent != NULL)
{
CloseHandle(hEvent);
}
if(hRpcPause != NULL)
{
CloseHandle(hRpcPause);
}
if(err == 0)
{
WSACleanup();
}
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
dwStatus, //NO_ERROR,
SERVICE_WAITHINT
);
//
// Create another thread to shutdown server.
//
hShutdownThread=CreateThread(
NULL,
0,
ServiceShutdownThread,
(VOID *)NULL,
0,
&dump
);
if(hShutdownThread == NULL)
{
// Report the status to the service control manager with
// long wait hint time.
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
NO_ERROR,
SERVICE_SHUTDOWN_WAITTIME
);
//
// can't create thread, just call shutdown directory
//
ServerShutdown();
}
else
{
//
// report in 5 second interval to SC.
//
DWORD dwMaxWaitTime = SERVICE_SHUTDOWN_WAITTIME / 5000;
DWORD dwTimes=0;
//
// Wait for general server shutdown thread to terminate
// Gives max 1 mins to shutdown
//
while(WaitForSingleObject( hShutdownThread, SC_WAITHINT ) == WAIT_TIMEOUT &&
dwTimes++ < dwMaxWaitTime)
{
// Report the status to the service control manager.
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
NO_ERROR,
SERVICE_WAITHINT
);
}
CloseHandle(hShutdownThread);
}
cleanup:
if (NULL != g_pWriter)
{
g_pWriter->Uninitialize();
delete g_pWriter;
g_pWriter = NULL;
}
CoUninitialize( );
// Signal we are safe to shutting down
SetEvent(gSafeToTerminate);
return dwStatus;
}
//-----------------------------------------------------------------
VOID
ServiceStop()
/*++
++*/
{
ReportStatusToSCMgr(
SERVICE_STOP_PENDING,
NO_ERROR,
0
);
// Stop's the server, wakes the main thread.
SetEvent(hRpcPause);
//
// Signal currently waiting RPC call to terminate
//
ServiceSignalShutdown();
// this is the actual time we receive shutdown request.
SetServiceLastShutdownTime();
(VOID)RpcMgmtStopServerListening(NULL);
TLSLogInfoEvent(TLS_I_SERVICE_STOP);
}
//-----------------------------------------------------------------
VOID
ServicePause()
/*++
++*/
{
ResetEvent(hRpcPause);
(VOID)RpcMgmtStopServerListening(NULL);
TLSLogInfoEvent(TLS_I_SERVICE_PAUSED);
}
//-----------------------------------------------------------------
VOID
ServiceContinue()
/*++
++*/
{
SetEvent(hRpcPause);
TLSLogInfoEvent(TLS_I_SERVICE_CONTINUE);
}
//-----------------------------------------------------------------
BOOL
ReportStatusToSCMgr(
IN DWORD dwCurrentState,
IN DWORD dwExitCode,
IN DWORD dwWaitHint
)
/*++
Abstract:
Sets the current status of the service and reports it
to the Service Control Manager
Parameter:
dwCurrentState - the state of the service
dwWin32ExitCode - error code to report
dwWaitHint - worst case estimate to next checkpoint
Returns:
TRUE if success, FALSE otherwise
*/
{
BOOL fResult=TRUE;
if(g_bReportToSCM == TRUE)
{
SERVICE_STATUS ssStatus;
static DWORD dwCheckPoint = 1;
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
//
// global - current status of process
//
ssCurrentStatus = dwCurrentState;
if (dwCurrentState == SERVICE_START_PENDING)
{
ssStatus.dwControlsAccepted = 0;
}
else
{
ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_CONTROL_SHUTDOWN;
}
ssStatus.dwCurrentState = dwCurrentState;
if(dwExitCode != NO_ERROR)
{
ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
ssStatus.dwServiceSpecificExitCode = dwExitCode;
}
else
{
ssStatus.dwWin32ExitCode = dwExitCode;
}
ssStatus.dwWaitHint = dwWaitHint;
if(dwCurrentState == SERVICE_RUNNING || dwCurrentState == SERVICE_STOPPED)
{
ssStatus.dwCheckPoint = 0;
}
else
{
ssStatus.dwCheckPoint = dwCheckPoint++;
}
// Report the status of the service to the service control manager.
//
fResult = SetServiceStatus(
sshStatusHandle,
&ssStatus
);
if(fResult == FALSE)
{
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_INIT,
DBGLEVEL_FUNCTION_TRACE,
_TEXT("Failed to set service status %d...\n"),
GetLastError()
);
TLSLogErrorEvent(TLS_E_SC_REPORT_STATUS);
}
}
return fResult;
}
///////////////////////////////////////////////////////////////////
//
// The following code is for running the service as a console app
//
void
CmdDebugService(
IN int argc,
IN char ** argv,
IN BOOL bDebug
)
/*
*/
{
int dwArgc;
LPTSTR *lpszArgv;
#ifdef UNICODE
lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
#else
dwArgc = (DWORD) argc;
lpszArgv = argv;
#endif
_tprintf(
_TEXT("Debugging %s.\n"),
_TEXT(SZSERVICEDISPLAYNAME)
);
SetConsoleCtrlHandler(
ControlHandler,
TRUE
);
ServiceStart(
dwArgc,
lpszArgv,
bDebug
);
}
//------------------------------------------------------------------
BOOL WINAPI
ControlHandler(
IN DWORD dwCtrlType
)
/*++
Abstract:
Parameter:
IN dwCtrlType : control type
Return:
++*/
{
switch( dwCtrlType )
{
case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
_tprintf(
_TEXT("Stopping %s.\n"),
_TEXT(SZSERVICEDISPLAYNAME)
);
ssCurrentStatus = SERVICE_STOP_PENDING;
ServiceStop();
return TRUE;
break;
}
return FALSE;
}