windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/common/waitsvc/waitsvc.cpp

386 lines
10 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: wiatsvc.cpp
//
// Contents: wait for service to start
//
// History: 19-Jun-00 reidk created
//
//--------------------------------------------------------------------------
#include <windows.h>
#include "unicode.h"
#include "errlog.h"
#include "waitsvc.h"
#define WAITSVC_LOGERR_LASTERR(x) if (x) \
{ \
ErrLog_LogError(NULL, \
ERRLOG_CLIENT_ID_WAITSVC, \
__LINE__, \
0, \
FALSE, \
FALSE); \
}
BOOL
WaitForCryptService(
IN LPWSTR pwszService,
IN BOOL *pfDone,
IN BOOL fLogErrors
)
/*++
This routine determines if the protected storage service is
pending start. If the service is pending start, this routine
waits until the service is running before returning to the
caller.
If the Service is running when this routine returns, the
return value is TRUE.
If the service is not running, or an error occurred, the
return value is FALSE.
When the return value is FALSE, the value is only advisory, and may not
indicate the current state of the service. The reasoning here is that
if the service did not start the first time this call is made, is will
not likely be running the next time around, and hence we avoid checking
on subsequent calls.
For current situations, the caller should ignore the return value; when
the return value is FALSE, the caller should just try making the call
into the service. If the service is still down, the call into it will fail
appropriately.
--*/
{
SC_HANDLE schSCM;
SC_HANDLE schService = NULL;
DWORD dwStopCount = 0;
static BOOL fSuccess = FALSE;
BOOL fCheckDisabled = TRUE;
HANDLE hToken = NULL;
BOOL fSystemAccount = FALSE;
BOOL fStartServiceCalled = FALSE;
DWORD dwErr = ERROR_SUCCESS;
if( !FIsWinNT() )
return TRUE;
if( *pfDone )
return fSuccess;
schSCM = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
if(schSCM == NULL)
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
return FALSE;
}
//
// open the protected storage service so we can query it's
// current state.
//
schService = OpenServiceW(schSCM, pwszService, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
if(schService == NULL)
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
fCheckDisabled = FALSE;
schService = OpenServiceW(schSCM, pwszService, SERVICE_QUERY_STATUS);
}
if(schService == NULL)
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
goto cleanup;
}
//
// check if calling process is SYSTEM account.
// if it is, use a larger timeout value.
//
if( OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ) ) {
do {
BYTE FastBuffer[ 256 ];
PTOKEN_USER TokenInformation;
DWORD cbTokenInformation;
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
PSID psidLocalSystem;
TokenInformation = (PTOKEN_USER)FastBuffer;
cbTokenInformation = sizeof(FastBuffer);
if(!GetTokenInformation(
hToken,
TokenUser,
TokenInformation,
cbTokenInformation,
&cbTokenInformation
))
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
break;
}
if(!AllocateAndInitializeSid(
&sia,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&psidLocalSystem
))
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
break;
}
fSystemAccount = EqualSid(
psidLocalSystem,
TokenInformation->User.Sid
);
FreeSid( psidLocalSystem );
} while (FALSE);
CloseHandle( hToken );
}
//
// number of seconds to Sleep per loop interation.
//
#define SLEEP_SECONDS (5)
if( fSystemAccount ) {
//
// 15 minutes for SYSTEM account.
//
dwStopCount = 900 / SLEEP_SECONDS;
} else {
//
//
// loop checking the service status every 5 seconds, for up to 2 minutes
// total (120 seconds, 5*24=120)
//
dwStopCount = 120 / SLEEP_SECONDS;
}
for( ; dwStopCount != 0 ; dwStopCount--, Sleep(SLEEP_SECONDS*1000) ) {
SERVICE_STATUS sServiceStatus;
DWORD dwWaitForStatus = 0;
//
// check if the service is disabled. If it is, bailout.
//
if( fCheckDisabled ) {
LPQUERY_SERVICE_CONFIG pServiceConfig;
BYTE TempBuffer[ 1024 ];
DWORD cbServiceConfig;
pServiceConfig = (LPQUERY_SERVICE_CONFIG)TempBuffer;
cbServiceConfig = sizeof(TempBuffer);
if(QueryServiceConfig( schService, pServiceConfig, cbServiceConfig, &cbServiceConfig )) {
if( pServiceConfig->dwStartType == SERVICE_DISABLED )
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
goto cleanup;
}
}
}
//
// find out current service status
//
if(!QueryServiceStatus( schService, &sServiceStatus ))
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
break;
}
//
// if service is running, indicate success
//
if( sServiceStatus.dwCurrentState == SERVICE_RUNNING ) {
if (fStartServiceCalled)
{
ErrLog_LogString(
NULL,
L"WAITSVC: Service is running: ",
pwszService,
TRUE);
}
fSuccess = TRUE;
break;
}
if( sServiceStatus.dwCurrentState == SERVICE_STOP_PENDING )
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
// Wait until stopped
continue;
}
if( sServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING )
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
// Wait until paused
continue;
}
//
// if start pending, wait and re-query.
//
if( sServiceStatus.dwCurrentState == SERVICE_START_PENDING )
{
// Wait until started
continue;
}
if(SERVICE_STOPPED == sServiceStatus.dwCurrentState)
{
// Attempt to start the service
SC_HANDLE schManualStartService = NULL;
DWORD dwError = ERROR_SUCCESS;
// The service is manual start
// so attempt to start it.
schManualStartService = OpenServiceW(schSCM,
pwszService,
SERVICE_START);
if(NULL == schManualStartService)
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
goto cleanup;
}
ErrLog_LogString(
NULL,
L"WAITSVC: Calling StartService(): ",
pwszService,
TRUE);
fStartServiceCalled = TRUE;
if(!StartService(schManualStartService, 0, NULL))
{
dwError = GetLastError();
}
if(ERROR_SERVICE_ALREADY_RUNNING == dwError)
{
dwError = ERROR_SUCCESS;
}
CloseServiceHandle(schManualStartService);
if(ERROR_SUCCESS != dwError)
{
SetLastError(dwError);
WAITSVC_LOGERR_LASTERR(fLogErrors)
goto cleanup;
}
continue;
}
if(SERVICE_PAUSED == sServiceStatus.dwCurrentState)
{
// Attempt to start the service
SC_HANDLE schManualStartService = NULL;
DWORD dwError = ERROR_SUCCESS;
// The service is manual start
// so attempt to start it.
schManualStartService = OpenServiceW(schSCM,
pwszService,
SERVICE_PAUSE_CONTINUE);
if(NULL == schManualStartService)
{
WAITSVC_LOGERR_LASTERR(fLogErrors)
goto cleanup;
}
if(!ControlService(schManualStartService, SERVICE_CONTROL_CONTINUE, &sServiceStatus))
{
dwError = GetLastError();
}
if(ERROR_SERVICE_ALREADY_RUNNING == dwError)
{
dwError = ERROR_SUCCESS;
}
CloseServiceHandle(schManualStartService);
if(ERROR_SUCCESS != dwError)
{
SetLastError(dwError);
WAITSVC_LOGERR_LASTERR(fLogErrors)
goto cleanup;
}
continue;
}
//
// bail out on any other dwCurrentState
// eg: service stopped, error condition, etc.
//
break;
}
*pfDone = TRUE;
cleanup:
dwErr = GetLastError();
if(schService)
CloseServiceHandle(schService);
CloseServiceHandle(schSCM);
SetLastError(dwErr);
return fSuccess;
}