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.
2341 lines
74 KiB
2341 lines
74 KiB
/*
|
|
IisRestart.cpp
|
|
|
|
Implementation of CIisRestart ( IIisServiceControl )
|
|
|
|
FILE HISTORY:
|
|
Phillich 06-Oct-1998 Created
|
|
|
|
*/
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "IisRsta.h"
|
|
#include "IisRstam.h"
|
|
#include "IisRestart.h"
|
|
#include "common.h"
|
|
|
|
#define MAX_TASKS 8
|
|
#define SLEEP_INTERVAL 1000
|
|
|
|
typedef BOOL (*PFNQUERYSERVICECONFIG2)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD) ;
|
|
typedef BOOL (*PFNCHANGESERVICECONFIG2)(SC_HANDLE,DWORD,LPVOID);
|
|
|
|
//
|
|
// control block for control command requests
|
|
//
|
|
|
|
typedef struct {
|
|
HRESULT hres;
|
|
LONG lRefCount;
|
|
DWORD dwCmd;
|
|
SC_HANDLE hServiceHandle;
|
|
} SERVICE_COMMAND_CONTROL_BLOCK;
|
|
|
|
|
|
|
|
//
|
|
// Global functions
|
|
//
|
|
BOOL
|
|
W3SVCandHTTPFilter(
|
|
DWORD currentIndex,
|
|
ENUM_SERVICE_STATUS* pessRoot,
|
|
DWORD dwNumServices
|
|
);
|
|
|
|
VOID EnableShutdownPrivilege(
|
|
VOID
|
|
);
|
|
|
|
HRESULT
|
|
EnumStartServices(
|
|
SC_HANDLE schSCM,
|
|
LPTSTR pszRoot,
|
|
DWORD dwTargetState,
|
|
LPBYTE abServiceList,
|
|
DWORD dwInitializeServiceListSize,
|
|
LPBYTE* ppbServiceList,
|
|
LPDWORD pdwNumServices,
|
|
BOOL fAddIisadmin
|
|
);
|
|
|
|
HRESULT
|
|
SerializeEnumServiceBuffer(
|
|
LPENUM_SERVICE_STATUS pessDependentServices,
|
|
DWORD dwNumServices,
|
|
LPBYTE pbBuffer,
|
|
DWORD dwBufferSize,
|
|
LPDWORD pdwMDRequiredBufferSize
|
|
);
|
|
|
|
BOOL
|
|
IsEnableRemote(
|
|
);
|
|
|
|
HRESULT
|
|
StopIIsAdmin(
|
|
DWORD dwTimeoutMsecs
|
|
);
|
|
|
|
HRESULT
|
|
StartStopAll(
|
|
LPTSTR pszRoot,
|
|
BOOL fStart,
|
|
DWORD dwTimeoutMsecs
|
|
);
|
|
|
|
BOOL
|
|
WaitForServiceStatus(
|
|
SC_HANDLE schDependent,
|
|
DWORD dwDesiredServiceState,
|
|
DWORD dwTimeoutMsecs
|
|
);
|
|
|
|
HRESULT
|
|
KillTaskByName(
|
|
LPTSTR pname,
|
|
LPSTR pszMandatoryModule
|
|
);
|
|
|
|
VOID
|
|
ReportStatus(
|
|
DWORD dwId,
|
|
DWORD dwStatus
|
|
);
|
|
|
|
HRESULT
|
|
SendControlToService(
|
|
SC_HANDLE hServiceHandle,
|
|
DWORD dwCmd,
|
|
LPDWORD pdwTimeoutOutMsecs
|
|
);
|
|
|
|
StartStopAllRecursive(
|
|
SC_HANDLE schSCM,
|
|
ENUM_SERVICE_STATUS* pessRoot,
|
|
DWORD dwNumServices,
|
|
BOOL fStart,
|
|
BOOL fForceDemandStart,
|
|
LPDWORD pdwTimeoutMsecs
|
|
);
|
|
|
|
HRESULT
|
|
WhoAmI(
|
|
LPTSTR* pPrincipal
|
|
);
|
|
|
|
BOOL
|
|
CloseSystemExceptionHandler(
|
|
LPCTSTR pszWindowName
|
|
);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CIisRestart
|
|
|
|
|
|
STDMETHODIMP
|
|
CIisRestart::Stop(
|
|
DWORD dwTimeoutMsecs,
|
|
DWORD dwForce
|
|
)
|
|
/*++
|
|
|
|
Stop
|
|
|
|
Stop all internet services ( services dependent on IISADMIN )
|
|
first using SCM then optionaly using TerminateProcess if failure
|
|
|
|
Arguments:
|
|
|
|
dwTimeoutMsecs - timeout for status check ( in ms )
|
|
dwForce - !0 to force TerminateProcess if failure to stop services using SCM
|
|
|
|
Returns:
|
|
ERROR_RESOURCE_DISABLED if remote access to IIisRestart disabled
|
|
ERROR_SERVICE_REQUEST_TIMEOUT if timeout waiting for all internet services status
|
|
to be stopped
|
|
otherwise COM status
|
|
|
|
--*/
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
if ( !IsEnableRemote() )
|
|
{
|
|
hres = HRESULT_FROM_WIN32( ERROR_RESOURCE_DISABLED );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Always kill Dr Watson, as the Dr Watson window may be still present after inetinfo process
|
|
// was terminated after an exception, and in this case the Dr Watson process apparently still owns
|
|
// some sockets resources preventing inetinfo to properly restart ( specifically binding TCP/IP sockets
|
|
// fails during inetinfo restart )
|
|
//
|
|
|
|
KillTaskByName(_T("drwtsn32"), NULL);
|
|
|
|
hres = StartStopAll( _T("IISADMIN"), FALSE, dwTimeoutMsecs );
|
|
if ( dwForce && FAILED( hres ) )
|
|
{
|
|
ReportStatus( IRSTAM_KILL_DUE_TO_FORCE, hres );
|
|
hres = Kill();
|
|
}
|
|
}
|
|
|
|
ReportStatus( IRSTAM_STOP, hres );
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CIisRestart::Start(
|
|
DWORD dwTimeoutMsecs
|
|
)
|
|
/*++
|
|
|
|
Start
|
|
|
|
Start all internet services ( services dependent on IISADMIN )
|
|
using SCM
|
|
|
|
Arguments:
|
|
|
|
dwTimeoutMsecs - timeout for status check ( in ms )
|
|
|
|
Returns:
|
|
ERROR_RESOURCE_DISABLED if remote access to IIisRestart disabled
|
|
ERROR_SERVICE_REQUEST_TIMEOUT if timeout waiting for all internet services status
|
|
to be started
|
|
otherwise COM status
|
|
|
|
--*/
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
if ( !IsEnableRemote() )
|
|
{
|
|
hres = HRESULT_FROM_WIN32( ERROR_RESOURCE_DISABLED );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// In 6.0 we will use IIS Reset /Start to bring up the
|
|
// service again without stopping the services that can
|
|
// keep running. We still want to kill any dr watson's
|
|
// thou. This should be harmless on a regular start.
|
|
//
|
|
|
|
//
|
|
// Always kill Dr Watson, as the Dr Watson window may be still present after inetinfo process
|
|
// was terminated after an exception, and in this case the Dr Watson process apparently still owns
|
|
// some sockets resources preventing inetinfo to properly restart ( specifically binding TCP/IP sockets
|
|
// fails during inetinfo restart )
|
|
//
|
|
|
|
KillTaskByName(_T("drwtsn32"), NULL);
|
|
|
|
hres = StartStopAll( _T("IISADMIN"), TRUE, dwTimeoutMsecs );
|
|
}
|
|
|
|
ReportStatus( IRSTAM_START, hres );
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CIisRestart::Reboot(
|
|
DWORD dwTimeoutMsecs,
|
|
DWORD dwForceAppsClosed
|
|
)
|
|
/*++
|
|
|
|
Reboot
|
|
|
|
Reboot the computer
|
|
|
|
Arguments:
|
|
|
|
dwTimeoutMsecs - timeout for apps to be closed by user ( in ms )
|
|
dwForceAppsClosed - force apps to be closed if hung
|
|
|
|
Returns:
|
|
ERROR_RESOURCE_DISABLED if remote access to IIisRestart disabled
|
|
otherwise COM status
|
|
|
|
--*/
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
if ( !IsEnableRemote() )
|
|
{
|
|
hres = HRESULT_FROM_WIN32( ERROR_RESOURCE_DISABLED );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If this fails then we will get an error back from ExitWindowsEx()
|
|
//
|
|
|
|
EnableShutdownPrivilege();
|
|
|
|
//
|
|
// Make sure we will always reboot even if process(es) stuck
|
|
//
|
|
|
|
TCHAR* pPrincipal;
|
|
TCHAR* pBuf;
|
|
|
|
//
|
|
// Format message to operator, includes name of user requesting shutdown.
|
|
//
|
|
|
|
if ( SUCCEEDED( hres = WhoAmI( &pPrincipal ) ) )
|
|
{
|
|
if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
(LPCVOID)NULL, // no handle to module so this module's resource will be used.
|
|
IRSTAM_SYSSHUT,
|
|
0,
|
|
(LPTSTR)&pBuf,
|
|
1,
|
|
(va_list *)&pPrincipal ) )
|
|
{
|
|
if (InitiateSystemShutdownEx( NULL,
|
|
pBuf,
|
|
dwTimeoutMsecs/1000, // timeout in seconds
|
|
dwForceAppsClosed,
|
|
TRUE,
|
|
SHTDN_REASON_FLAG_PLANNED |
|
|
SHTDN_REASON_MAJOR_OPERATINGSYSTEM |
|
|
SHTDN_REASON_MINOR_RECONFIG) == 0)
|
|
{
|
|
hres = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
LocalFree( (LPVOID)pBuf );
|
|
}
|
|
|
|
LocalFree( pPrincipal );
|
|
}
|
|
|
|
}
|
|
|
|
ReportStatus( IRSTAM_REBOOT, hres );
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CIisRestart::Kill(
|
|
)
|
|
/*++
|
|
|
|
Kill
|
|
|
|
Kill all internet services ( services dependent on IISADMIN )
|
|
using TerminateProcess()
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
ERROR_RESOURCE_DISABLED if remote access to IIisRestart disabled
|
|
otherwise COM status
|
|
|
|
--*/
|
|
{
|
|
HRESULT hres = S_OK;
|
|
HRESULT hresReapply = S_OK;
|
|
HRESULT hresKill = S_OK;
|
|
BYTE abServiceList[2048];
|
|
LPBYTE pbServiceList = NULL;
|
|
DWORD dwNumServices = 0;
|
|
SC_HANDLE schSCM = NULL;
|
|
SC_HANDLE schSrv;
|
|
LPBYTE* ppInfo = NULL;
|
|
LPENUM_SERVICE_STATUS pessDependentServices = NULL;
|
|
DWORD dwNeeded;
|
|
HINSTANCE hAdvapi;
|
|
PFNQUERYSERVICECONFIG2 pfnQueryServiceConfig2 = NULL;
|
|
PFNCHANGESERVICECONFIG2 pfnChangeServiceConfig2 = NULL;
|
|
SERVICE_FAILURE_ACTIONS sfaNoAction;
|
|
SC_ACTION saNoAction[3];
|
|
DWORD i;
|
|
BYTE abTemp[64]; // work-around for NT5 bug
|
|
DWORD* adwPid = NULL;
|
|
SERVICE_STATUS_PROCESS status;
|
|
DWORD cbNeeded = 0;
|
|
|
|
if ( !IsEnableRemote() )
|
|
{
|
|
return HRESULT_FROM_WIN32( ERROR_RESOURCE_DISABLED );
|
|
}
|
|
|
|
//
|
|
// Take a snapshot of Restart configuration
|
|
// If unable to get ptr to service config2 API then consider this a success:
|
|
// there is nothing to preserve.
|
|
//
|
|
|
|
hAdvapi = LoadLibrary(_T("ADVAPI32.DLL"));
|
|
if ( hAdvapi != NULL )
|
|
{
|
|
pfnQueryServiceConfig2 = (PFNQUERYSERVICECONFIG2)GetProcAddress( hAdvapi, "QueryServiceConfig2W" );
|
|
pfnChangeServiceConfig2 = (PFNCHANGESERVICECONFIG2)GetProcAddress( hAdvapi, "ChangeServiceConfig2W" );
|
|
}
|
|
|
|
if ( pfnQueryServiceConfig2
|
|
&& pfnChangeServiceConfig2 )
|
|
{
|
|
schSCM = OpenSCManager(NULL,
|
|
NULL,
|
|
SC_MANAGER_ENUMERATE_SERVICE);
|
|
if ( schSCM == NULL )
|
|
{
|
|
hres = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Setup control block for no restart action.
|
|
// We will replace existing actions with this control block
|
|
//
|
|
|
|
sfaNoAction.dwResetPeriod = INFINITE;
|
|
sfaNoAction.lpCommand = _T("");
|
|
sfaNoAction.lpRebootMsg = _T("");
|
|
sfaNoAction.cActions = 3;
|
|
sfaNoAction.lpsaActions = saNoAction;
|
|
|
|
saNoAction[0].Type = SC_ACTION_NONE;
|
|
saNoAction[0].Delay = 0;
|
|
saNoAction[1].Type = SC_ACTION_NONE;
|
|
saNoAction[1].Delay = 0;
|
|
saNoAction[2].Type = SC_ACTION_NONE;
|
|
saNoAction[2].Delay = 0;
|
|
|
|
//
|
|
// Enumerate all services dependent on IISADMIN ( including itself )
|
|
//
|
|
|
|
hres = EnumStartServices( schSCM,
|
|
_T("IISADMIN"),
|
|
SERVICE_STATE_ALL,
|
|
abServiceList,
|
|
sizeof(abServiceList),
|
|
&pbServiceList,
|
|
&dwNumServices,
|
|
TRUE );
|
|
|
|
if ( SUCCEEDED( hres ) )
|
|
{
|
|
//
|
|
// Store existing info in ppInfo array
|
|
//
|
|
adwPid = new DWORD[ dwNumServices ];
|
|
// we don't check the adwPid here because
|
|
// we will only use it below if we succeeded in allocating it.
|
|
if ( adwPid )
|
|
{
|
|
memset ( adwPid, 0, sizeof(DWORD) * dwNumServices );
|
|
}
|
|
|
|
ppInfo = (LPBYTE*)LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT, sizeof(LPBYTE) * dwNumServices );
|
|
|
|
if ( ppInfo )
|
|
{
|
|
pessDependentServices = (LPENUM_SERVICE_STATUS)pbServiceList;
|
|
|
|
for ( i = 0 ;
|
|
(i < dwNumServices) && SUCCEEDED(hres) ;
|
|
++i )
|
|
{
|
|
schSrv = OpenService( schSCM,
|
|
pessDependentServices[i].lpServiceName,
|
|
SERVICE_QUERY_CONFIG |
|
|
SERVICE_CHANGE_CONFIG |
|
|
SERVICE_QUERY_STATUS );
|
|
|
|
if ( schSrv )
|
|
{
|
|
|
|
if ( adwPid )
|
|
{
|
|
if ( QueryServiceStatusEx( schSrv,
|
|
SC_STATUS_PROCESS_INFO,
|
|
(LPBYTE)&status,
|
|
sizeof( status ),
|
|
&cbNeeded ) )
|
|
{
|
|
adwPid[i] = status.dwProcessId;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 1st query config size, then alloc buffer and retrieve
|
|
// config. Note than ppInfo[] may be NULL is no config
|
|
// associated with this service.
|
|
//
|
|
// WARNING: must specify ptr to writable buffer even if specified
|
|
// buffer size is 0 due to bug in NT5 implementation of
|
|
// QueryServiceConfig2. Not sure about minimum buffer size
|
|
// ( sizeof(SERVICE_FAILURE_ACTIONS) ) ?
|
|
//
|
|
|
|
if ( !pfnQueryServiceConfig2( schSrv,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
(LPBYTE)abTemp,
|
|
0,
|
|
&dwNeeded ) )
|
|
{
|
|
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
// ppInfo is an array of ptrs to bytes.
|
|
ppInfo[i] = (LPBYTE)LocalAlloc( LMEM_FIXED, dwNeeded );
|
|
if ( ppInfo[i] != NULL )
|
|
{
|
|
if ( !pfnQueryServiceConfig2( schSrv,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
ppInfo[i],
|
|
dwNeeded,
|
|
&dwNeeded ) )
|
|
{
|
|
|
|
hres = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED( hres ) )
|
|
{
|
|
if ( !pfnChangeServiceConfig2( schSrv,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
&sfaNoAction ) )
|
|
{
|
|
hres = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
|
|
CloseServiceHandle( schSrv );
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
} // Close of the for loop
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
}
|
|
|
|
CloseServiceHandle( schSCM );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Graceful exit failed, kill the IIS processes.
|
|
// First, kill inetinfo, then kill the WAM instances.
|
|
//
|
|
|
|
// Issue: Not sure why we do this, and if we need to do it for other exe's.
|
|
CloseSystemExceptionHandler( _T("inetinfo.exe") );
|
|
|
|
//
|
|
// Always kill Dr Watson, as the Dr Watson window may be still present after inetinfo process
|
|
// was terminated after an exception, and in this case the Dr Watson process apparently still owns
|
|
// some sockets resources preventing inetinfo to properly restart ( specifically binding TCP/IP sockets
|
|
// fails during inetinfo restart )
|
|
//
|
|
|
|
// If we removed all the SCM config above then
|
|
// we will attempt the kills
|
|
if ( SUCCEEDED ( hres ) )
|
|
{
|
|
HRESULT hresKillTemp = S_OK;
|
|
|
|
KillTaskByName(_T("drwtsn32"), NULL);
|
|
|
|
hresKillTemp = KillTaskByName(_T("SVCHOST"), "iisw3adm.dll"); // MTS WAM containers
|
|
if ( SUCCEEDED ( hresKill ) )
|
|
{
|
|
hresKill = hresKillTemp;
|
|
}
|
|
|
|
hresKillTemp = KillTaskByName(_T("W3WP"), NULL); // MTS WAM containers
|
|
if ( SUCCEEDED ( hresKill ) )
|
|
{
|
|
hresKill = hresKillTemp;
|
|
}
|
|
|
|
hresKillTemp = KillTaskByName(_T("INETINFO"), NULL);
|
|
if ( SUCCEEDED ( hresKill ) )
|
|
{
|
|
hresKill = hresKillTemp;
|
|
}
|
|
|
|
hresKillTemp = KillTaskByName(_T("DLLHOST"),"wam.dll"); // COM+ WAM Containers
|
|
if ( SUCCEEDED ( hresKill ) )
|
|
{
|
|
hresKill = hresKillTemp;
|
|
}
|
|
|
|
hresKillTemp = KillTaskByName(_T("ASPNET_WP"), NULL); // ASP + Processes.
|
|
if ( SUCCEEDED ( hresKill ) )
|
|
{
|
|
hresKill = hresKillTemp;
|
|
}
|
|
|
|
hresKillTemp = KillTaskByName(_T("DAVCDATA"), NULL); // Dav support process.
|
|
if ( SUCCEEDED ( hresKill ) )
|
|
{
|
|
hresKill = hresKillTemp;
|
|
}
|
|
|
|
|
|
// the following code will check the IISAdmin registry parameters for
|
|
// a KillProcsOnFailure MULTI_SZ. Any process names in this list will
|
|
// be killed.
|
|
|
|
HKEY hKey;
|
|
DWORD dwType;
|
|
DWORD dwSize;
|
|
TCHAR achBuffer[1024];
|
|
|
|
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
TEXT("system\\CurrentControlSet\\services\\IISAdmin"),
|
|
0,
|
|
KEY_READ,
|
|
&hKey ) == ERROR_SUCCESS )
|
|
{
|
|
DWORD Success = ERROR_SUCCESS;
|
|
|
|
dwSize = sizeof( achBuffer );
|
|
|
|
Success = RegQueryValueEx( hKey,
|
|
TEXT("KillProcsOnFailure"),
|
|
0,
|
|
&dwType,
|
|
(LPBYTE)achBuffer,
|
|
&dwSize );
|
|
if ( Success == ERROR_SUCCESS &&
|
|
dwType == REG_MULTI_SZ &&
|
|
dwSize > 2 )
|
|
{
|
|
|
|
TCHAR *pT = achBuffer;
|
|
|
|
// parse the multisz. The format is NULL Terminated strings
|
|
// with an extra null terminator after the list.
|
|
|
|
while (*pT)
|
|
{
|
|
|
|
hresKillTemp = KillTaskByName(pT, NULL);
|
|
if ( SUCCEEDED ( hresKill ) )
|
|
{
|
|
hresKill = hresKillTemp;
|
|
}
|
|
|
|
// _tcsnbcnt figures out how many bytes are in the
|
|
// the first number of characters that _tcslen declares.
|
|
// So this calculation works out to be the number of bytes
|
|
// that we just looked at plus the null terminator.
|
|
dwSize -= (DWORD) _tcsnbcnt(pT,_tcslen(pT)) + sizeof(TCHAR);
|
|
|
|
pT += _tcslen(pT) + 1;
|
|
|
|
}
|
|
} // end of successfull opening of the key
|
|
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
}
|
|
|
|
hresReapply = S_OK;
|
|
|
|
//
|
|
// Reapply restart configuration
|
|
//
|
|
|
|
//
|
|
// At this point pessDependentServices if pessDependentServices
|
|
// is null then we didn't touch the services so don't reset.
|
|
//
|
|
if ( ppInfo && pessDependentServices )
|
|
{
|
|
schSCM = OpenSCManager(NULL,
|
|
NULL,
|
|
SC_MANAGER_ENUMERATE_SERVICE);
|
|
if ( schSCM == NULL )
|
|
{
|
|
hresReapply = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
else
|
|
{
|
|
for ( i = 0 ; i < dwNumServices ; ++i )
|
|
{
|
|
if ( ppInfo[i] )
|
|
{
|
|
schSrv = OpenService( schSCM,
|
|
pessDependentServices[i].lpServiceName,
|
|
SERVICE_QUERY_CONFIG |
|
|
SERVICE_CHANGE_CONFIG |
|
|
SERVICE_QUERY_STATUS |
|
|
SERVICE_START );
|
|
|
|
if ( schSrv )
|
|
{
|
|
// OutputDebugStringW(L"Service = ");
|
|
// OutputDebugStringW(pessDependentServices[i].lpServiceName);
|
|
// OutputDebugStringW(L"\n");
|
|
|
|
//
|
|
// If any of these things are not true, then we want to wait
|
|
// for the pid to change, or the service to become stopped
|
|
// before adding back in the changes that we removed. If these
|
|
// things are all true, then adding back in the actions won't really
|
|
// matter because the SCM won't do anything with the actions.
|
|
//
|
|
if ( ((LPSERVICE_FAILURE_ACTIONS) ppInfo[i])->cActions != 3 ||
|
|
((LPSERVICE_FAILURE_ACTIONS) ppInfo[i])->lpsaActions == NULL ||
|
|
((LPSERVICE_FAILURE_ACTIONS) ppInfo[i])->lpsaActions[0].Type != SC_ACTION_NONE ||
|
|
((LPSERVICE_FAILURE_ACTIONS) ppInfo[i])->lpsaActions[1].Type != SC_ACTION_NONE ||
|
|
((LPSERVICE_FAILURE_ACTIONS) ppInfo[i])->lpsaActions[2].Type != SC_ACTION_NONE )
|
|
{
|
|
// Wait for the service to be marked as stopped,
|
|
// just for a certain amount of time.
|
|
for ( DWORD x = 0; x < 10; x++ )
|
|
{
|
|
if ( QueryServiceStatusEx( schSrv,
|
|
SC_STATUS_PROCESS_INFO,
|
|
(LPBYTE)&status,
|
|
sizeof( status ),
|
|
&cbNeeded ) )
|
|
{
|
|
if ( adwPid && status.dwProcessId != adwPid[i] )
|
|
{
|
|
// pid didn't match, not the same
|
|
// process we were looking at when
|
|
// we went to kill.
|
|
break;
|
|
}
|
|
|
|
if ( status.dwCurrentState == SERVICE_STOPPED )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
Sleep ( 100 );
|
|
}
|
|
}
|
|
|
|
if ( !pfnChangeServiceConfig2( schSrv,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
ppInfo[i] ) )
|
|
{
|
|
hresReapply = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
CloseServiceHandle( schSrv );
|
|
}
|
|
else
|
|
{
|
|
hresReapply = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
}
|
|
|
|
CloseServiceHandle( schSCM );
|
|
}
|
|
}
|
|
|
|
// If we tried the kills and they failed then
|
|
// we want to report back that error. Note that
|
|
// we check that the setup phase worked before
|
|
// we even try the kill phase, so we can just
|
|
// assume that.
|
|
if ( FAILED(hresKill) )
|
|
{
|
|
hres = hresKill;
|
|
}
|
|
|
|
if ( SUCCEEDED(hres) && FAILED(hresReapply) )
|
|
{
|
|
hres = hresReapply;
|
|
}
|
|
|
|
ReportStatus( IRSTAM_KILL, hres );
|
|
|
|
if ( hAdvapi )
|
|
{
|
|
FreeLibrary( hAdvapi );
|
|
}
|
|
|
|
//
|
|
// cleanup
|
|
//
|
|
|
|
if ( ppInfo )
|
|
{
|
|
for ( i = 0 ; i < dwNumServices ; ++i )
|
|
{
|
|
if ( ppInfo[i] )
|
|
{
|
|
LocalFree( ppInfo[i] );
|
|
}
|
|
}
|
|
LocalFree( ppInfo );
|
|
}
|
|
|
|
if ( pbServiceList != NULL
|
|
&& pbServiceList != abServiceList )
|
|
{
|
|
LocalFree( pbServiceList );
|
|
}
|
|
|
|
if ( adwPid )
|
|
{
|
|
delete [] adwPid;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
//
|
|
// Helper functions
|
|
//
|
|
|
|
VOID
|
|
EnableShutdownPrivilege(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
EnableShutdownPrivilege
|
|
|
|
Enable shutdown privilege ( required to call ExitWindowsEx )
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
Nothing. If error enabling the privilege the dependent operation
|
|
will fail.
|
|
|
|
--*/
|
|
{
|
|
HANDLE ProcessHandle;
|
|
HANDLE TokenHandle = NULL;
|
|
BOOL Result;
|
|
LUID ShutdownValue;
|
|
TOKEN_PRIVILEGES TokenPrivileges;
|
|
|
|
ProcessHandle = OpenProcess(
|
|
PROCESS_QUERY_INFORMATION,
|
|
FALSE,
|
|
GetCurrentProcessId()
|
|
);
|
|
|
|
if ( ProcessHandle == NULL ) {
|
|
|
|
//
|
|
// This should not happen
|
|
//
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
Result = OpenProcessToken (
|
|
ProcessHandle,
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&TokenHandle
|
|
);
|
|
|
|
if ( !Result ) {
|
|
|
|
//
|
|
// This should not happen
|
|
//
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Find out the value of Shutdown privilege
|
|
//
|
|
|
|
|
|
Result = LookupPrivilegeValue(
|
|
NULL,
|
|
SE_SHUTDOWN_NAME,
|
|
&ShutdownValue
|
|
);
|
|
|
|
if ( !Result ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set up the privilege set we will need
|
|
//
|
|
|
|
TokenPrivileges.PrivilegeCount = 1;
|
|
TokenPrivileges.Privileges[0].Luid = ShutdownValue;
|
|
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
(VOID) AdjustTokenPrivileges (
|
|
TokenHandle,
|
|
FALSE,
|
|
&TokenPrivileges,
|
|
sizeof(TokenPrivileges),
|
|
NULL,
|
|
NULL
|
|
);
|
|
Cleanup:
|
|
|
|
if ( TokenHandle )
|
|
{
|
|
CloseHandle( TokenHandle );
|
|
}
|
|
|
|
if ( ProcessHandle )
|
|
{
|
|
CloseHandle( ProcessHandle );
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
StartStopAll(
|
|
LPTSTR pszRoot,
|
|
BOOL fStart,
|
|
DWORD dwTimeoutMsecs
|
|
)
|
|
/*++
|
|
|
|
StartStopAll
|
|
|
|
start or stop services dependency tree starting with specified root service
|
|
|
|
Arguments:
|
|
|
|
pszRoot - root of the service tree
|
|
fStart - TRUE to start services, FALSE to stop
|
|
dwTimeoutMsecs - timeout for status check ( in ms )
|
|
|
|
Returns:
|
|
COM status
|
|
|
|
--*/
|
|
{
|
|
SC_HANDLE schSCM = NULL;
|
|
SC_HANDLE schRoot = NULL;
|
|
HRESULT hresReturn = S_OK;
|
|
ENUM_SERVICE_STATUS ess;
|
|
|
|
|
|
schSCM = OpenSCManager(NULL,
|
|
NULL,
|
|
SC_MANAGER_CONNECT);
|
|
if ( schSCM == NULL )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
else
|
|
{
|
|
schRoot = OpenService( schSCM,
|
|
pszRoot,
|
|
SERVICE_ALL_ACCESS );
|
|
if ( schRoot != NULL )
|
|
{
|
|
if ( !QueryServiceStatus( schRoot, &ess.ServiceStatus ) )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
CloseServiceHandle( schRoot );
|
|
|
|
if ( SUCCEEDED( hresReturn )
|
|
&& ( fStart
|
|
|| ess.ServiceStatus.dwCurrentState != SERVICE_STOPPED) )
|
|
{
|
|
ess.lpServiceName = pszRoot;
|
|
|
|
// if it's stopped, then whack the dllhosts that have wam.dll loaded
|
|
|
|
if (ess.ServiceStatus.dwCurrentState == SERVICE_STOPPED)
|
|
{
|
|
KillTaskByName(_T("DLLHOST"),"wam.dll"); // COM+ WAM Containers
|
|
}
|
|
|
|
hresReturn = StartStopAllRecursive( schSCM, &ess, 1, fStart, TRUE, &dwTimeoutMsecs );
|
|
|
|
}
|
|
|
|
// check out the current state of the service
|
|
|
|
schRoot = OpenService( schSCM, pszRoot, SERVICE_ALL_ACCESS );
|
|
if ( schRoot != NULL )
|
|
{
|
|
if ( QueryServiceStatus( schRoot, &ess.ServiceStatus ) )
|
|
{
|
|
// if it's stopped, then whack the dllhosts that have wam.dll loaded
|
|
|
|
if (ess.ServiceStatus.dwCurrentState == SERVICE_STOPPED)
|
|
{
|
|
KillTaskByName(_T("DLLHOST"),"wam.dll"); // COM+ WAM Containers
|
|
}
|
|
}
|
|
|
|
CloseServiceHandle( schRoot );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
CloseServiceHandle( schSCM );
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
StartStopAllRecursive(
|
|
SC_HANDLE schSCM,
|
|
ENUM_SERVICE_STATUS* pessRoot,
|
|
DWORD dwNumServices,
|
|
BOOL fStart,
|
|
BOOL fForceDemandStart,
|
|
LPDWORD pdwTimeoutMsecs
|
|
)
|
|
/*++
|
|
|
|
StartStopAllRecursive
|
|
|
|
start or stop services dependency tree starting with specified root service
|
|
|
|
Arguments:
|
|
|
|
schSCM - handle to SCM
|
|
pessRoot - list of services to start/stop recursively
|
|
fStart - TRUE to start services, FALSE to stop
|
|
fForceDemandStart - for start requests: TRUE to force start
|
|
if SERVICE_DEMAND_START. Otherwise only start if service
|
|
is auto start ( including boot & system start )
|
|
dwTimeoutMsecs - timeout for status check ( in ms )
|
|
|
|
Returns:
|
|
COM status
|
|
|
|
--*/
|
|
{
|
|
DWORD dwBytesNeeded;
|
|
DWORD dwNumRecServices = 0;
|
|
HRESULT hresReturn = S_OK;
|
|
BYTE abServiceList[2048];
|
|
LPBYTE pbServiceList = NULL;
|
|
BYTE abServiceConfig[1024];
|
|
LPQUERY_SERVICE_CONFIG pServiceConfig = NULL;
|
|
SC_HANDLE* phServiceHandle = NULL;
|
|
DWORD i;
|
|
DWORD dwServiceConfigSize;
|
|
SERVICE_STATUS ServiceStatus;
|
|
DWORD dwSleepInterval = SLEEP_INTERVAL;
|
|
|
|
if ( dwNumServices != 0 &&
|
|
( pessRoot == NULL ||
|
|
pdwTimeoutMsecs == NULL ) )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( (phServiceHandle = (SC_HANDLE*)LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT,
|
|
dwNumServices * sizeof(SC_HANDLE) )) == NULL )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
if ( SUCCEEDED(hresReturn) )
|
|
{
|
|
//
|
|
// All services will be started/stopped at once
|
|
// then periodically checked for status until all of them are running/stopped
|
|
// or some error occured or timeout
|
|
//
|
|
|
|
if ( dwNumServices != 0 )
|
|
{
|
|
pServiceConfig = (LPQUERY_SERVICE_CONFIG)abServiceConfig;
|
|
dwServiceConfigSize = sizeof( abServiceConfig );
|
|
|
|
//
|
|
// Open handles and send service control start command
|
|
//
|
|
|
|
for ( i = 0 ;
|
|
i < dwNumServices && SUCCEEDED(hresReturn) ;
|
|
i++)
|
|
{
|
|
//
|
|
// Send command to Services
|
|
//
|
|
|
|
phServiceHandle[i] = OpenService( schSCM,
|
|
pessRoot[i].lpServiceName,
|
|
SERVICE_ALL_ACCESS );
|
|
|
|
if ( phServiceHandle[i] != NULL )
|
|
{
|
|
if ( fStart )
|
|
{
|
|
//
|
|
// Query service config to check if service should be started
|
|
// based on its Start Type.
|
|
//
|
|
|
|
if ( !QueryServiceConfig( phServiceHandle[i],
|
|
(LPQUERY_SERVICE_CONFIG)abServiceConfig,
|
|
dwServiceConfigSize,
|
|
&dwBytesNeeded ) )
|
|
{
|
|
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
// If we are re-allocating and we all ready allocated once
|
|
// before first free up the memory.
|
|
|
|
if ( pServiceConfig != (LPQUERY_SERVICE_CONFIG) abServiceConfig )
|
|
{
|
|
LocalFree( pServiceConfig );
|
|
}
|
|
|
|
if ( (pServiceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(
|
|
LMEM_FIXED,
|
|
dwBytesNeeded )) == NULL )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
else
|
|
{
|
|
dwServiceConfigSize = dwBytesNeeded;
|
|
|
|
if ( !QueryServiceConfig( phServiceHandle[i],
|
|
(LPQUERY_SERVICE_CONFIG)pServiceConfig,
|
|
dwServiceConfigSize,
|
|
&dwBytesNeeded ) )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED(hresReturn) )
|
|
{
|
|
//
|
|
// Check if service auto start except if fForceDemandStart
|
|
// specified. ForceDemandStart will only be specified for
|
|
// the service that the command is directly issued on. This
|
|
// means that it will only be specified for IISADMIN.
|
|
//
|
|
|
|
if ( ( fForceDemandStart && pServiceConfig->dwStartType == SERVICE_DEMAND_START )
|
|
|| ( pServiceConfig->dwStartType == SERVICE_BOOT_START ||
|
|
pServiceConfig->dwStartType == SERVICE_SYSTEM_START ||
|
|
pServiceConfig->dwStartType == SERVICE_AUTO_START ) )
|
|
{
|
|
StartService( phServiceHandle[i], 0, NULL );
|
|
|
|
//
|
|
// Ask for only the services that are inactive. So, for instance,
|
|
// if we are attempting to restart the iisadmin service,
|
|
// and W3SVC is still active, we won't send it a command to restart.
|
|
//
|
|
hresReturn = EnumStartServices( schSCM,
|
|
pessRoot[i].lpServiceName,
|
|
SERVICE_INACTIVE,
|
|
abServiceList,
|
|
sizeof(abServiceList),
|
|
&pbServiceList,
|
|
&dwNumRecServices,
|
|
FALSE );
|
|
|
|
if ( SUCCEEDED( hresReturn ) )
|
|
{
|
|
hresReturn = StartStopAllRecursive( schSCM,
|
|
(ENUM_SERVICE_STATUS*)pbServiceList,
|
|
dwNumRecServices,
|
|
fStart,
|
|
FALSE,
|
|
pdwTimeoutMsecs );
|
|
|
|
if ( pbServiceList != NULL
|
|
&& pbServiceList != abServiceList )
|
|
{
|
|
LocalFree( pbServiceList );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Don't want to start this service, so mark it
|
|
// as already running
|
|
//
|
|
|
|
if (wcscmp(pessRoot[i].lpServiceName,_T("IISADMIN")) == 0)
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE);
|
|
}
|
|
else
|
|
{
|
|
pessRoot[i].ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // handle stopping the service
|
|
{
|
|
if ( W3SVCandHTTPFilter(i, pessRoot, dwNumServices) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Remember if the service was stopped to start with.
|
|
BOOL fServiceWasStoppedToStartWith = ( pessRoot[i].ServiceStatus.dwCurrentState == SERVICE_STOPPED );
|
|
|
|
// We will also need to stop dependent services if the are started all ready.
|
|
BOOL fHasDependentServices = FALSE;
|
|
|
|
if ( !fServiceWasStoppedToStartWith )
|
|
{
|
|
//
|
|
// if the service was not stopped to start with
|
|
// we need to tell the service to stop.
|
|
//
|
|
|
|
hresReturn = SendControlToService( phServiceHandle[i],
|
|
SERVICE_CONTROL_STOP,
|
|
pdwTimeoutMsecs );
|
|
|
|
if ( hresReturn == HRESULT_FROM_WIN32( ERROR_SERVICE_REQUEST_TIMEOUT ) )
|
|
{
|
|
//
|
|
// WARNING!
|
|
//
|
|
// We're in trouble. Service did not respond in a timely fashion,
|
|
// and further attempt to use this handle ( including closing it )
|
|
// will also hang, so cancel the handle and leak it
|
|
//
|
|
|
|
phServiceHandle[i] = NULL;
|
|
}
|
|
else if ( hresReturn == HRESULT_FROM_WIN32( ERROR_DEPENDENT_SERVICES_RUNNING ) )
|
|
{
|
|
fHasDependentServices = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it was stopped to start with, or if it was not but it couldn't
|
|
// be stopped because it has dependent services. Go ahead and stop
|
|
// the dependent services.
|
|
//
|
|
if ( fHasDependentServices || fServiceWasStoppedToStartWith )
|
|
{
|
|
|
|
//
|
|
// Get the services that are active because we
|
|
// are only interested in stopping services that
|
|
// are actually running.
|
|
//
|
|
hresReturn = EnumStartServices( schSCM,
|
|
pessRoot[i].lpServiceName,
|
|
SERVICE_ACTIVE,
|
|
abServiceList,
|
|
sizeof(abServiceList),
|
|
&pbServiceList,
|
|
&dwNumRecServices,
|
|
FALSE );
|
|
|
|
if ( SUCCEEDED( hresReturn ) )
|
|
{
|
|
hresReturn = StartStopAllRecursive( schSCM,
|
|
(ENUM_SERVICE_STATUS*)pbServiceList,
|
|
dwNumRecServices,
|
|
fStart,
|
|
FALSE,
|
|
pdwTimeoutMsecs );
|
|
|
|
if ( pbServiceList != NULL
|
|
&& pbServiceList != abServiceList )
|
|
{
|
|
LocalFree( pbServiceList );
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED( hresReturn ) )
|
|
{
|
|
//
|
|
// If the service itself is not all ready stopped, then stop
|
|
// the service. It could be that it is stopped ( due to a crash )
|
|
// and the other services that were dependent on them are still
|
|
// running.
|
|
//
|
|
if ( !fServiceWasStoppedToStartWith )
|
|
{
|
|
|
|
hresReturn = SendControlToService( phServiceHandle[i],
|
|
SERVICE_CONTROL_STOP,
|
|
pdwTimeoutMsecs );
|
|
|
|
// if we can hang above we could hang here...
|
|
if ( hresReturn == HRESULT_FROM_WIN32( ERROR_SERVICE_REQUEST_TIMEOUT ) )
|
|
{
|
|
//
|
|
// WARNING!
|
|
//
|
|
// We're in trouble. Service did not respond in a timely fashion,
|
|
// and further attempt to use this handle ( including closing it )
|
|
// will also hang, so cancel the handle and leak it
|
|
//
|
|
|
|
phServiceHandle[i] = NULL;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( FAILED( hresReturn ) )
|
|
{
|
|
break;
|
|
}
|
|
} // end of stopping code
|
|
} // end of valid service handle
|
|
} // end of loop
|
|
|
|
//
|
|
// Check service running
|
|
//
|
|
|
|
if ( (*pdwTimeoutMsecs < dwSleepInterval) && *pdwTimeoutMsecs )
|
|
{
|
|
dwSleepInterval = *pdwTimeoutMsecs;
|
|
}
|
|
|
|
for ( ;
|
|
SUCCEEDED( hresReturn );
|
|
)
|
|
{
|
|
for ( i = 0 ;
|
|
i < dwNumServices;
|
|
i++)
|
|
{
|
|
//
|
|
// Only query status for services known to be not running
|
|
//
|
|
|
|
if ( pessRoot[i].ServiceStatus.dwCurrentState
|
|
!= (DWORD)(fStart ? SERVICE_RUNNING : SERVICE_STOPPED) )
|
|
{
|
|
if ( QueryServiceStatus( phServiceHandle[i], &ServiceStatus ) )
|
|
{
|
|
//
|
|
// remember status
|
|
//
|
|
|
|
pessRoot[i].ServiceStatus.dwCurrentState = ServiceStatus.dwCurrentState;
|
|
|
|
if ( fStart && ServiceStatus.dwCurrentState == SERVICE_STOPPED )
|
|
{
|
|
//
|
|
// Service died during startup. no point keeping polling
|
|
// for service state : return an error
|
|
//
|
|
|
|
hresReturn = HRESULT_FROM_WIN32( ERROR_SERVICE_NOT_ACTIVE );
|
|
break;
|
|
}
|
|
|
|
if ( ServiceStatus.dwCurrentState != (DWORD)(fStart ? SERVICE_RUNNING : SERVICE_STOPPED) )
|
|
{
|
|
//
|
|
// will keep looping waiting for target service state
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( GetLastError() );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// if we did not checked all services then at least one of them
|
|
// is not running ( or some error occured )
|
|
//
|
|
|
|
if ( SUCCEEDED( hresReturn ) && i != dwNumServices )
|
|
{
|
|
if ( dwSleepInterval > *pdwTimeoutMsecs )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( ERROR_SERVICE_REQUEST_TIMEOUT );
|
|
}
|
|
else
|
|
{
|
|
Sleep( dwSleepInterval );
|
|
|
|
*pdwTimeoutMsecs -= dwSleepInterval;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// close service handles
|
|
//
|
|
|
|
for ( i = 0 ;
|
|
i < dwNumServices;
|
|
i++)
|
|
{
|
|
if ( phServiceHandle[i] != NULL )
|
|
{
|
|
CloseServiceHandle( phServiceHandle[i] );
|
|
}
|
|
}
|
|
}
|
|
|
|
LocalFree( phServiceHandle );
|
|
}
|
|
|
|
if ( pServiceConfig != NULL
|
|
&& pServiceConfig != (LPQUERY_SERVICE_CONFIG)abServiceConfig )
|
|
{
|
|
LocalFree( pServiceConfig );
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
extern "C"
|
|
DWORD WINAPI
|
|
ControlServiceThread(
|
|
LPVOID p
|
|
)
|
|
/*++
|
|
|
|
ControlServiceThread
|
|
|
|
Send a command to a service
|
|
|
|
Arguments:
|
|
|
|
p - ptr to SERVICE_COMMAND_CONTROL_BLOCK
|
|
|
|
Returns:
|
|
0
|
|
|
|
--*/
|
|
{
|
|
SERVICE_STATUS ssStatus;
|
|
SERVICE_COMMAND_CONTROL_BLOCK* pCB = (SERVICE_COMMAND_CONTROL_BLOCK*)p;
|
|
|
|
if ( pCB == NULL )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( !ControlService( pCB->hServiceHandle, pCB->dwCmd, &ssStatus ) )
|
|
{
|
|
DWORD err = GetLastError();
|
|
|
|
// do not report error if try to stop a stopped service
|
|
if (err == ERROR_SERVICE_NOT_ACTIVE && pCB->dwCmd == SERVICE_CONTROL_STOP)
|
|
{
|
|
pCB->hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
pCB->hres = HRESULT_FROM_WIN32( err );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCB->hres = S_OK;
|
|
}
|
|
|
|
//nasty side affect of this function, if the count hit's
|
|
//zero we delete it here. Leaving P to point off, however
|
|
//p does hold a ref count for itself so this should actually work fine.
|
|
if ( InterlockedDecrement( &pCB->lRefCount ) == 0 )
|
|
{
|
|
delete pCB;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SendControlToService(
|
|
SC_HANDLE hServiceHandle,
|
|
DWORD dwCmd,
|
|
LPDWORD pdwTimeoutMsecs
|
|
)
|
|
/*++
|
|
|
|
ControlServiceThread
|
|
|
|
Send a command to a service with timeout
|
|
|
|
Arguments:
|
|
|
|
hServiceHandle - service to control
|
|
dwCmd - command to send to service
|
|
pdwTimeoutMsecs - timeout ( in ms ). updated on output based on time
|
|
spent waiting for service status
|
|
|
|
Returns:
|
|
ERROR_SERVICE_REQUEST_TIMEOUT if timeout
|
|
otherwise COM status
|
|
|
|
--*/
|
|
{
|
|
HANDLE hT;
|
|
DWORD dwID;
|
|
DWORD dwBefore;
|
|
DWORD dwAfter;
|
|
SERVICE_COMMAND_CONTROL_BLOCK* pCB;
|
|
DWORD dwTimeoutMsecs;
|
|
HRESULT hres;
|
|
|
|
if ( pdwTimeoutMsecs == NULL )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
dwTimeoutMsecs = *pdwTimeoutMsecs;
|
|
|
|
//
|
|
// Default timeout for ControlService is 120s, which is too long for us
|
|
// so we create a thread to call ControlService and wait for thread
|
|
// termination.
|
|
// Communication between threads is handled by a refcounted control block
|
|
//
|
|
pCB = new SERVICE_COMMAND_CONTROL_BLOCK;
|
|
if ( pCB != NULL )
|
|
{
|
|
pCB->lRefCount = 2; // 1 for caller, 1 for callee
|
|
pCB->dwCmd = dwCmd;
|
|
pCB->hServiceHandle = hServiceHandle;
|
|
pCB->hres = S_OK;
|
|
|
|
dwBefore = GetTickCount();
|
|
|
|
hT = CreateThread( NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)ControlServiceThread,
|
|
(LPVOID)pCB,
|
|
0,
|
|
&dwID );
|
|
if ( hT != NULL )
|
|
{
|
|
if ( WaitForSingleObject( hT, dwTimeoutMsecs ) == WAIT_OBJECT_0 )
|
|
{
|
|
hres = pCB->hres;
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32( ERROR_SERVICE_REQUEST_TIMEOUT );
|
|
}
|
|
|
|
CloseHandle( hT );
|
|
|
|
if ( InterlockedDecrement( &pCB->lRefCount ) == 0 )
|
|
{
|
|
delete pCB;
|
|
}
|
|
|
|
//
|
|
// Update caller's timeout
|
|
//
|
|
|
|
dwAfter = GetTickCount();
|
|
|
|
if ( dwAfter > dwBefore )
|
|
{
|
|
if ( dwAfter - dwBefore <= dwTimeoutMsecs )
|
|
{
|
|
*pdwTimeoutMsecs -= dwAfter - dwBefore;
|
|
}
|
|
else
|
|
{
|
|
*pdwTimeoutMsecs = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete pCB;
|
|
|
|
hres = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SerializeEnumServiceBuffer(
|
|
LPENUM_SERVICE_STATUS pessDependentServices,
|
|
DWORD dwNumServices,
|
|
LPBYTE pbBuffer,
|
|
DWORD dwBufferSize,
|
|
LPDWORD pdwMDRequiredBufferSize
|
|
)
|
|
/*++
|
|
|
|
SerializeEnumServiceBuffer
|
|
|
|
Serialize array of ENUM_SERVICE_STATUS to buffer,
|
|
replacing ptr by offset in buffer
|
|
|
|
Arguments:
|
|
|
|
pessDependentServices - array of ENUM_SERVICE_STATUS to serialize
|
|
dwNumServices - # of entries in pessDependentServices
|
|
pbBuffer - buffer filled with serialized status as array of SERIALIZED_ENUM_SERVICE_STATUS
|
|
dwBufferSize - maximum size of pbBuffer
|
|
pdwMDRequiredBufferSize - updated with required size if dwBufferSize too small
|
|
|
|
Returns:
|
|
ERROR_INSUFFICIENT_BUFFER if dwBufferSize too small
|
|
otherwise COM status
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = S_OK;
|
|
DWORD dwMinSize = 0;
|
|
UINT i;
|
|
|
|
if ( dwNumServices != 0 &&
|
|
pessDependentServices == NULL )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( !pbBuffer )
|
|
{
|
|
dwBufferSize = 0;
|
|
}
|
|
|
|
//
|
|
// size of output buffer is based on size of array of SERIALIZED_ENUM_SERVICE_STATUS
|
|
// plus size of all strings : service name & display name for each entry
|
|
//
|
|
|
|
dwMinSize = sizeof(SERIALIZED_ENUM_SERVICE_STATUS) * dwNumServices;
|
|
|
|
for ( i = 0 ;
|
|
i < dwNumServices ;
|
|
++i )
|
|
{
|
|
UINT cServiceName = (DWORD) _tcslen( pessDependentServices[i].lpServiceName ) + 1;
|
|
UINT cDisplayName = (DWORD) _tcslen( pessDependentServices[i].lpDisplayName ) + 1;
|
|
|
|
//
|
|
// do not update if output buffer is too small, but keep looping to determine
|
|
// total size
|
|
//
|
|
|
|
if ( dwBufferSize >= dwMinSize + (cServiceName + cDisplayName) * sizeof(TCHAR) )
|
|
{
|
|
//
|
|
// copy service status as is
|
|
//
|
|
|
|
((SERIALIZED_ENUM_SERVICE_STATUS*)pbBuffer)[i].ServiceStatus =
|
|
pessDependentServices[i].ServiceStatus;
|
|
|
|
//
|
|
// copy string and convert ptr to string to index in output buffer
|
|
//
|
|
|
|
memcpy( pbBuffer + dwMinSize, pessDependentServices[i].lpServiceName, cServiceName * sizeof(TCHAR) );
|
|
((SERIALIZED_ENUM_SERVICE_STATUS*)pbBuffer)[i].iServiceName = dwMinSize ;
|
|
|
|
memcpy( pbBuffer + dwMinSize + cServiceName * sizeof(TCHAR), pessDependentServices[i].lpDisplayName, cDisplayName * sizeof(TCHAR) );
|
|
((SERIALIZED_ENUM_SERVICE_STATUS*)pbBuffer)[i].iDisplayName = dwMinSize + cServiceName * sizeof(TCHAR) ;
|
|
}
|
|
|
|
dwMinSize += (cServiceName + cDisplayName) * sizeof(TCHAR) ;
|
|
}
|
|
|
|
if ( dwBufferSize < dwMinSize )
|
|
{
|
|
if ( pdwMDRequiredBufferSize )
|
|
{
|
|
*pdwMDRequiredBufferSize = dwMinSize;
|
|
}
|
|
|
|
hresReturn = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CIisRestart::Status(
|
|
DWORD dwBufferSize,
|
|
unsigned char * pbBuffer,
|
|
DWORD * pdwMDRequiredBufferSize,
|
|
DWORD * pdwNumServices
|
|
)
|
|
/*++
|
|
|
|
Status
|
|
|
|
Return status of all internet services as array of ENUM_SERVICE_STATUS
|
|
|
|
Arguments:
|
|
|
|
dwBufferSize - maximum size of pbBuffer
|
|
pbBuffer - buffer filled with serialized status as array of SERIALIZED_ENUM_SERVICE_STATUS
|
|
pdwMDRequiredBufferSize - updated with required size if dwBufferSize too small
|
|
pdwNumServices - updated with number of entries stored in pbBuffer
|
|
|
|
Returns:
|
|
ERROR_RESOURCE_DISABLED if access to restart commands disabled
|
|
ERROR_INSUFFICIENT_BUFFER if dwBufferSize too small
|
|
otherwise COM status
|
|
|
|
--*/
|
|
{
|
|
SC_HANDLE schSCM = NULL;
|
|
HRESULT hresReturn = E_FAIL;
|
|
BYTE abServiceList[2048];
|
|
LPBYTE pbServiceList = NULL;
|
|
LPENUM_SERVICE_STATUS pessDependentServices;
|
|
|
|
if ( pdwNumServices == NULL )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( !IsEnableRemote() )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( ERROR_RESOURCE_DISABLED );
|
|
}
|
|
else
|
|
{
|
|
schSCM = OpenSCManager(NULL,
|
|
NULL,
|
|
SC_MANAGER_CONNECT);
|
|
if ( schSCM == NULL )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
else
|
|
{
|
|
hresReturn = EnumStartServices( schSCM,
|
|
_T("IISADMIN"),
|
|
SERVICE_STATE_ALL,
|
|
abServiceList,
|
|
sizeof(abServiceList),
|
|
&pbServiceList,
|
|
pdwNumServices,
|
|
FALSE );
|
|
|
|
if ( SUCCEEDED(hresReturn) )
|
|
{
|
|
pessDependentServices = (LPENUM_SERVICE_STATUS)pbServiceList;
|
|
|
|
hresReturn = SerializeEnumServiceBuffer( (LPENUM_SERVICE_STATUS)pbServiceList,
|
|
*pdwNumServices,
|
|
pbBuffer,
|
|
dwBufferSize,
|
|
pdwMDRequiredBufferSize );
|
|
|
|
if ( pbServiceList != NULL
|
|
&& pbServiceList != abServiceList )
|
|
{
|
|
LocalFree( pbServiceList );
|
|
}
|
|
}
|
|
|
|
CloseServiceHandle(schSCM);
|
|
}
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
EnumStartServices(
|
|
SC_HANDLE schSCM,
|
|
LPTSTR pszRoot,
|
|
DWORD dwTargetState,
|
|
LPBYTE abServiceList,
|
|
DWORD dwInitializeServiceListSize,
|
|
LPBYTE* ppbServiceList,
|
|
LPDWORD pdwNumServices,
|
|
BOOL fAddIisadmin
|
|
)
|
|
/*++
|
|
|
|
EnumStartServices
|
|
|
|
Enumerate dependent services to output buffer as array of ENUM_SERVICE_STATUS
|
|
|
|
Arguments:
|
|
|
|
schSCM - handle to SCM
|
|
pszRoot - service for which to enumerate dependencies
|
|
dwTargetState - dwServiceState for call to EnumDependentServices()
|
|
abServiceList - initial output buffer
|
|
dwInitializeServiceListSize - maximum size of abServiceList
|
|
ppbServiceList - updated with output buffer, may be abServiceList if long enough
|
|
otherwise returned buffer is to be freed using LocalFree()
|
|
pdwNumServices - updated with number of entries stored in pbBuffer
|
|
fAddIisadmin - TRUE to add IISADMIN to list of dependent services
|
|
|
|
Returns:
|
|
COM status
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = S_OK;
|
|
SC_HANDLE schIISADMIN = NULL;
|
|
DWORD dwBytesNeeded;
|
|
DWORD dwAddSize = 0;
|
|
DWORD dwOffsetSize = 0;
|
|
|
|
|
|
if ( ppbServiceList == NULL ||
|
|
pdwNumServices == NULL )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*ppbServiceList = NULL;
|
|
|
|
schIISADMIN = OpenService(schSCM,
|
|
pszRoot,
|
|
STANDARD_RIGHTS_REQUIRED |
|
|
SERVICE_ENUMERATE_DEPENDENTS);
|
|
if (schIISADMIN == NULL)
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
else
|
|
{
|
|
if ( fAddIisadmin )
|
|
{
|
|
//
|
|
// if initial size too small for Iisadmin description then fail
|
|
//
|
|
|
|
dwOffsetSize = sizeof(ENUM_SERVICE_STATUS );
|
|
dwAddSize = dwOffsetSize;
|
|
if ( dwAddSize > dwInitializeServiceListSize )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Use global static name for IISADMIN, no need to copy it to output buffer
|
|
//
|
|
|
|
((LPENUM_SERVICE_STATUS)abServiceList)->lpDisplayName = _T("IISADMIN");
|
|
((LPENUM_SERVICE_STATUS)abServiceList)->lpServiceName = _T("IISADMIN");
|
|
|
|
//
|
|
// don't want to check service status at this point as it may be stuck
|
|
// so assume RUNNING.
|
|
//
|
|
|
|
((LPENUM_SERVICE_STATUS)abServiceList)->ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
}
|
|
|
|
if (!EnumDependentServices( schIISADMIN,
|
|
dwTargetState,
|
|
(LPENUM_SERVICE_STATUS)(abServiceList + dwOffsetSize),
|
|
dwInitializeServiceListSize - dwAddSize,
|
|
&dwBytesNeeded,
|
|
pdwNumServices))
|
|
{
|
|
if (GetLastError() == ERROR_MORE_DATA)
|
|
{
|
|
if ( (*ppbServiceList = (LPBYTE)LocalAlloc( LMEM_FIXED,
|
|
dwBytesNeeded + dwAddSize )) == NULL )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
else
|
|
{
|
|
// dwOffsetSize is set to what dwAddSize was set to, so it is fine
|
|
// to memcpy this data, since we allocated more than dwAddSize above.
|
|
memcpy( *ppbServiceList, abServiceList, dwOffsetSize );
|
|
|
|
if (!EnumDependentServices( schIISADMIN,
|
|
SERVICE_INACTIVE,
|
|
(LPENUM_SERVICE_STATUS)(*ppbServiceList + dwOffsetSize),
|
|
dwBytesNeeded,
|
|
&dwBytesNeeded,
|
|
pdwNumServices))
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( GetLastError() );
|
|
LocalFree( *ppbServiceList );
|
|
*ppbServiceList = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppbServiceList = abServiceList;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if ( schIISADMIN )
|
|
{
|
|
CloseServiceHandle( schIISADMIN );
|
|
}
|
|
|
|
if ( fAddIisadmin && SUCCEEDED( hresReturn ) )
|
|
{
|
|
++*pdwNumServices;
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsEnableRemote(
|
|
)
|
|
/*++
|
|
|
|
IsEnableRemote
|
|
|
|
Check if restart I/F enabled
|
|
( based on HKLM\SOFTWARE\Microsoft\INetStp::EnableRestart::REG_DWORD )
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
TRUE if enabled, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
HKEY hKey;
|
|
DWORD dwValue;
|
|
DWORD dwType;
|
|
DWORD dwSize;
|
|
|
|
|
|
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\INetStp"),
|
|
0,
|
|
KEY_READ,
|
|
&hKey ) == ERROR_SUCCESS )
|
|
{
|
|
dwSize = sizeof( dwValue );
|
|
if ( RegQueryValueEx( hKey,
|
|
TEXT("EnableRestart"),
|
|
0,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwSize ) == ERROR_SUCCESS )
|
|
{
|
|
if ( dwType == REG_DWORD )
|
|
{
|
|
fSt = dwValue == 1;
|
|
}
|
|
else
|
|
{
|
|
fSt = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fSt = TRUE;
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CloseSystemExceptionHandler(
|
|
LPCTSTR pszWindowName
|
|
)
|
|
/*++
|
|
|
|
CloseSystemExceptionHandler
|
|
|
|
Send a close ( e.g. terminate apps without debugging ) command to the window
|
|
created by NT when a debugger is not configured to automatically start after app exception.
|
|
This window stays on screen until interactive user select either OK or debug app, which is
|
|
a problem for automated restart.
|
|
So we locate this window and send it a command requesting stop w/o debugging.
|
|
We locate the window by enumerating all windows and checking for window name beginning with the name
|
|
of the application that raised an exception, e.g. "inetinfo.exe"
|
|
|
|
Arguments:
|
|
|
|
pszWindowName - window name where to send terminate command
|
|
|
|
Returns:
|
|
TRUE if SUCCESS, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
DWORD dwPid = 0;
|
|
HWND hwnd;
|
|
|
|
GetPidFromTitle( &dwPid, &hwnd, pszWindowName );
|
|
|
|
if ( dwPid )
|
|
{
|
|
|
|
//
|
|
// WARNING: major hack: turns out that WM_COMMAND 1 is the command to send to
|
|
// the exception handler to ask it to close application w/o debugging
|
|
// This works for NT5, may change in the future...
|
|
//
|
|
|
|
PostMessage( hwnd, WM_COMMAND, 1, 0 );
|
|
|
|
Sleep( 1000 );
|
|
|
|
}
|
|
else
|
|
{
|
|
fSt = TRUE;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
KillTaskByName(
|
|
LPTSTR pname,
|
|
LPSTR pszMandatoryModule
|
|
)
|
|
/*++
|
|
|
|
KillTaskByName
|
|
|
|
Kill a process by name
|
|
Most of the code was taken from the Platform SDK kill,c sample, and
|
|
utilizes the common.c module included in this project.
|
|
Works only on NT platforms ( NOT Win 9x )
|
|
|
|
Arguments:
|
|
|
|
pname - name of process to kill ( name of executable w/o extension )
|
|
pszMandatoryModule - module name to look for, e.g. "wam.dll"
|
|
can be NULL for unconditional kill
|
|
|
|
Returns:
|
|
COM status
|
|
|
|
--*/
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
//
|
|
// Obtain the ability to manipulate other processes
|
|
//
|
|
|
|
EnableDebugPrivNT();
|
|
|
|
//
|
|
// get the task list for the system
|
|
//
|
|
|
|
hres = KillTask( pname, pszMandatoryModule );
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
VOID
|
|
ReportStatus(
|
|
DWORD dwId,
|
|
DWORD dwStatus
|
|
)
|
|
/*++
|
|
|
|
ReportStatus
|
|
|
|
Log status event
|
|
|
|
Arguments:
|
|
|
|
dwId - ID of event to log ( source is "IISCTLS" , SYSTEM log )
|
|
dwStatus - status of operation ( HRESULT )
|
|
|
|
Returns:
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
HANDLE hLog;
|
|
LPTSTR aParams[1];
|
|
|
|
if ( (hLog = RegisterEventSource( NULL, _T("IISCTLS") )) != NULL )
|
|
{
|
|
if ( SUCCEEDED( WhoAmI( aParams + 0 ) ) )
|
|
{
|
|
ReportEvent( hLog,
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
0,
|
|
dwId,
|
|
NULL,
|
|
1,
|
|
sizeof(DWORD),
|
|
(LPCTSTR*)aParams,
|
|
&dwStatus );
|
|
LocalFree( aParams[0] );
|
|
}
|
|
|
|
DeregisterEventSource( hLog );
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
WhoAmI(
|
|
LPTSTR* ppPrincipal
|
|
)
|
|
/*++
|
|
|
|
WhoAmI
|
|
|
|
Return currently impersonated user
|
|
As this is a COM server running under the identity of the invoker
|
|
this means we access the process token. So we might end up getting
|
|
the wrong user name if the object is invoked in close succession
|
|
( within the 5s server exit timeout ) by different users.
|
|
|
|
Arguments:
|
|
|
|
ppPrincipal - update with ptr to string containing user name ( domain\acct )
|
|
must be freed using LocalFree()
|
|
|
|
Returns:
|
|
Error status
|
|
|
|
--*/
|
|
{
|
|
TCHAR* pPrincipal;
|
|
TCHAR achUserName[512];
|
|
TCHAR achDomain[512];
|
|
DWORD dwLen;
|
|
DWORD dwDomainLen;
|
|
SID_NAME_USE SIDtype = SidTypeUser;
|
|
HRESULT hres = E_FAIL;
|
|
|
|
|
|
|
|
//
|
|
// So we have to access the process token and retrieve account & user name
|
|
// by using LookupAccountSid()
|
|
//
|
|
|
|
HANDLE hAccTok = NULL;
|
|
|
|
if ( OpenProcessToken( GetCurrentProcess(),
|
|
TOKEN_EXECUTE|TOKEN_QUERY,
|
|
&hAccTok ) )
|
|
{
|
|
BYTE abSidAndInfo[512];
|
|
DWORD dwReq;
|
|
|
|
//
|
|
// provide a reasonably sized buffer. If this fails we don't
|
|
// retry with a bigger one.
|
|
//
|
|
|
|
if ( GetTokenInformation( hAccTok,
|
|
TokenUser,
|
|
(LPVOID)abSidAndInfo,
|
|
sizeof(abSidAndInfo),
|
|
&dwReq) )
|
|
{
|
|
dwLen = sizeof( achUserName ) / sizeof(TCHAR);
|
|
dwDomainLen = sizeof(achDomain) / sizeof(TCHAR);
|
|
|
|
//
|
|
// provide a reasonably sized buffer. If this fails we don't
|
|
// retry with a bigger one.
|
|
//
|
|
|
|
if ( LookupAccountSid( NULL,
|
|
((SID_AND_ATTRIBUTES*)abSidAndInfo)->Sid,
|
|
achUserName,
|
|
&dwLen,
|
|
achDomain,
|
|
&dwDomainLen,
|
|
&SIDtype) )
|
|
{
|
|
//
|
|
// We return a LocalAlloc'ed buffer
|
|
//
|
|
|
|
dwLen = (DWORD) _tcslen( achUserName );
|
|
dwDomainLen = (DWORD) _tcslen( achDomain );
|
|
|
|
pPrincipal = (LPTSTR)LocalAlloc( LMEM_FIXED,
|
|
(dwLen + 1 + dwDomainLen + 1 ) * sizeof(TCHAR) );
|
|
if ( pPrincipal != NULL )
|
|
{
|
|
memcpy( pPrincipal,
|
|
achDomain,
|
|
sizeof(TCHAR)*dwDomainLen );
|
|
pPrincipal[dwDomainLen] = '\\';
|
|
memcpy( pPrincipal + dwDomainLen + 1,
|
|
achUserName,
|
|
sizeof(TCHAR)*(dwLen+1) );
|
|
*ppPrincipal = pPrincipal;
|
|
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
CloseHandle( hAccTok );
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
BOOL
|
|
W3SVCandHTTPFilter(
|
|
DWORD currentIndex,
|
|
ENUM_SERVICE_STATUS* pessRoot,
|
|
DWORD dwNumServices
|
|
)
|
|
{
|
|
/*++
|
|
|
|
W3SVCandHTTPFilter
|
|
|
|
Return currently impersonated user
|
|
As this is a COM server running under the identity of the invoker
|
|
this means we access the process token. So we might end up getting
|
|
the wrong user name if the object is invoked in close succession
|
|
( within the 5s server exit timeout ) by different users.
|
|
|
|
Arguments:
|
|
|
|
DWORD currentIndex - index of the service we are deciding if we should process.
|
|
ENUM_SERVICE_STATUS* pessRoot - the set of services we are working on.
|
|
DWORD dwNumServices - the number of services in the set.
|
|
|
|
Returns:
|
|
TRUE if we found the w3svc and HTTPFilter on the same line and we are looking at the w3svc
|
|
|
|
|
|
--*/
|
|
|
|
BOOL bResult = FALSE;
|
|
|
|
// check if we are looking at the w3svc. If we are find out if the
|
|
// HTTPFilter is on the same level. Note the HTTPFilter will always be listed
|
|
// after the w3svc.
|
|
if ( _wcsicmp( pessRoot[currentIndex].lpServiceName, L"w3svc" ) == 0 )
|
|
{
|
|
for ( DWORD i = currentIndex + 1;
|
|
( i < dwNumServices ) && ( bResult == FALSE );
|
|
i++ )
|
|
{
|
|
if ( _wcsicmp( pessRoot[i].lpServiceName, L"HTTPFilter" ) == 0 )
|
|
{
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|