|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
loopmgr.c
Abstract:
This module contains all of the code to drive the Loop Manager of IPSecSPD Service.
Author:
abhisheV 30-September-1999
Environment
User Level: Win32
Revision History:
--*/
#include "precomp.h"
#ifdef TRACE_ON
#include "loopmgr.tmh"
#endif
enum { SERVICE_STOP_EVENT = 0, INTERFACE_CHANGE_EVENT, NEW_LOCAL_POLICY_EVENT, NEW_DS_POLICY_EVENT, FORCED_POLICY_RELOAD_EVENT, GPUPDATE_REFRESH_EVENT, WAIT_EVENT_COUNT, };
DWORD ServiceWait( ) {
// ASSERT: All the following are true at this point:
// . Persistent policy has not been defined or if persistent policy has been
// defined, then it has been applied successfully.
// . IKE is up.
// . Driver is up.
// If persistent policy application failed, IKE init failed, or driver op failed,
// then service would have shutdown with driver in block mode if possible.
DWORD dwError = 0; HANDLE hWaitForEvents[WAIT_EVENT_COUNT]; BOOL bDoneWaiting = FALSE; DWORD dwWaitMilliseconds = 0; DWORD dwStatus = 0; time_t LastTimeOutTime = 0; AuditEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, IPSECSVC_SUCCESSFUL_START, NULL, TRUE, TRUE );
hWaitForEvents[SERVICE_STOP_EVENT] = ghServiceStopEvent; hWaitForEvents[INTERFACE_CHANGE_EVENT] = GetInterfaceChangeEvent(); hWaitForEvents[NEW_LOCAL_POLICY_EVENT] = ghNewLocalPolicyEvent; hWaitForEvents[NEW_DS_POLICY_EVENT] = ghNewDSPolicyEvent; hWaitForEvents[FORCED_POLICY_RELOAD_EVENT] = ghForcedPolicyReloadEvent; hWaitForEvents[GPUPDATE_REFRESH_EVENT] = ghGpupdateRefreshEvent;
//
// First load the default main mode policy.
//
(VOID) LoadDefaultISAKMPInformation( gpszDefaultISAKMPPolicyDN );
//
// Call the Polling Manager for the first time.
//
(VOID) StartStatePollingManager( gpIpsecPolicyState );
NotifyIpsecPolicyChange();
ComputeRelativePollingTime( LastTimeOutTime, TRUE, gdwRetryCount, &dwWaitMilliseconds );
time(&LastTimeOutTime);
TRACE(TRC_INFORMATION, (L"Completed startup routines. Entering service wait loop.")); while (!bDoneWaiting) {
dwStatus = WaitForMultipleObjects( WAIT_EVENT_COUNT, hWaitForEvents, FALSE, dwWaitMilliseconds );
PADeleteInUsePolicies();
switch (dwStatus) {
case SERVICE_STOP_EVENT: TRACE(TRC_INFORMATION, (L"Service stop event signaled"));
dwError = ERROR_SUCCESS; bDoneWaiting = TRUE; break;
case INTERFACE_CHANGE_EVENT: TRACE(TRC_INFORMATION, (L"Interface changed event signaled")); (VOID) OnInterfaceChangeEvent( ); (VOID) IKEInterfaceChange(); break;
case NEW_LOCAL_POLICY_EVENT: TRACE(TRC_INFORMATION, (L"New local policy event signaled")); ResetEvent(ghNewLocalPolicyEvent); if ((gpIpsecPolicyState->CurrentState != SPD_STATE_DS_APPLY_SUCCESS) && (gpIpsecPolicyState->CurrentState != SPD_STATE_CACHE_APPLY_SUCCESS)) { (VOID) ProcessLocalPolicyPollState( gpIpsecPolicyState ); NotifyIpsecPolicyChange(); } break;
case NEW_DS_POLICY_EVENT: TRACE(TRC_INFORMATION, (L"New DS policy event signaled")); ResetEvent(ghNewDSPolicyEvent); (VOID) OnPolicyChanged( gpIpsecPolicyState ); NotifyIpsecPolicyChange(); break;
case GPUPDATE_REFRESH_EVENT: TRACE(TRC_INFORMATION, (L"Group policy refresh event signaled")); ResetEvent(ghGpupdateRefreshEvent); dwError = ProcessDirectoryPolicyPollState( gpIpsecPolicyState ); break; case FORCED_POLICY_RELOAD_EVENT: TRACE(TRC_INFORMATION, (L"Forced policy reload event signaled")); ResetEvent(ghForcedPolicyReloadEvent); (VOID) OnPolicyChanged( gpIpsecPolicyState ); NotifyIpsecPolicyChange(); AuditEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FORCED_POLICY_RELOAD, NULL, TRUE, TRUE ); break;
case WAIT_TIMEOUT: TRACE(TRC_INFORMATION, (L"Polling event signaled")); time(&LastTimeOutTime); (VOID) OnPolicyPoll( gpIpsecPolicyState ); (VOID) OnSpecialAddrsChange(); break;
case WAIT_FAILED:
dwError = GetLastError(); TRACE(TRC_ERROR, (L"Failed service wait WaitForMultipleObjects %!winerr!: ", dwError)); bDoneWaiting = TRUE; break;
default:
dwError = ERROR_INVALID_EVENT_COUNT; bDoneWaiting = TRUE; break;
}
ComputeRelativePollingTime( LastTimeOutTime, FALSE, gdwRetryCount, &dwWaitMilliseconds );
if (InAcceptableState(gpIpsecPolicyState->CurrentState)) { // Polling is not going to retry anymore since we've reached an
// acceptable state. So reset gdwRetryCount for NEXT time
// in case we reach an unacceptable state.
gdwRetryCount = 0; TRACE( TRC_INFORMATION, ("Policy Agent now in state %d", (DWORD) gpIpsecPolicyState->CurrentState) ); } #ifdef TRACE_ON
else { TRACE( TRC_INFORMATION, ("Policy Agent in error state %d, retry count is %d ", (DWORD) gpIpsecPolicyState->CurrentState, gdwRetryCount) ); } #endif
}
if (!dwError) { AuditEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, IPSECSVC_SUCCESSFUL_SHUTDOWN, NULL, TRUE, TRUE ); } else { AuditOneArgErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, IPSECSVC_ERROR_SHUTDOWN, dwError, FALSE, TRUE );
TRACE(TRC_ERROR, (L"Failed and exiting service wait %!winerr!: ", dwError)); }
return (dwError); }
VOID ComputeRelativePollingTime( IN time_t LastTimeOutTime, IN BOOL bInitialLoad, IN DWORD dwRetryCount, IN PDWORD pWaitMilliseconds ) { DWORD WaitMilliseconds = 0; DWORD DSReconnectMilliseconds = 0; time_t NextTimeOutTime = 0; time_t PresentTime = 0; long WaitSeconds = gDefaultPollingInterval; DWORD64 NewPollingIntervalSeconds = 0;
if (!InAcceptableState(gpIpsecPolicyState->CurrentState)) { // Exponentially back-off polling interval until
// we hit default polling interval.
// Polling interval increases as (dwRetryCount+1)^2
NewPollingIntervalSeconds = (dwRetryCount+1) * (dwRetryCount+1) * 60; if (NewPollingIntervalSeconds < gDefaultPollingInterval) { gCurrentPollingInterval = (DWORD) NewPollingIntervalSeconds; } else { gCurrentPollingInterval = gDefaultPollingInterval; } }
WaitMilliseconds = gCurrentPollingInterval * 1000;
if (!WaitMilliseconds) { WaitMilliseconds = INFINITE; }
if (!bInitialLoad && WaitMilliseconds != INFINITE) {
//
// LastTimeOutTime is the snapshot time value in the past when
// we timed out waiting for multiple events.
// Ideally, the time for the next time out, NextTimeOutTime, is
// the time value in future which is sum of the last time when
// we timed out + the current waiting time value.
//
NextTimeOutTime = LastTimeOutTime + (WaitMilliseconds/1000);
//
// However, the last time we may not have timed out waiting
// for multiple events but rather came out because one of the
// events other than WAIT_TIMEOUT happened.
// However, on that event we may not have done a policy
// poll to figure out whether there was a policy change or
// not. If we again wait for WaitMilliseconds, then we are
// un-knowingly making our net time for policy poll greater
// than the alloted time interval value = WaitMilliseconds.
// So, we need to adjust the WaitMilliseconds to such a value
// that no matter what happens, we always do a policy poll
// atmost every WaitMilliseconds time interval value.
// The current time is PresentTime.
//
time(&PresentTime);
WaitSeconds = (long) (NextTimeOutTime - PresentTime);
if (WaitSeconds < 0) { WaitMilliseconds = 0; } else { WaitMilliseconds = WaitSeconds * 1000; }
}
*pWaitMilliseconds = WaitMilliseconds; }
VOID NotifyIpsecPolicyChange( ) { PulseEvent(ghPolicyChangeNotifyEvent);
SendPschedIoctl();
ResetEvent(ghPolicyChangeNotifyEvent);
return; }
VOID SendPschedIoctl( ) { HANDLE hPschedDriverHandle = NULL; ULONG uBytesReturned = 0; BOOL bIOStatus = FALSE;
#define DriverName TEXT("\\\\.\\PSCHED")
#define IOCTL_PSCHED_ZAW_EVENT CTL_CODE( \
FILE_DEVICE_NETWORK, \ 20, \ METHOD_BUFFERED, \ FILE_ANY_ACCESS \ )
hPschedDriverHandle = CreateFile( DriverName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
if (hPschedDriverHandle != INVALID_HANDLE_VALUE) {
bIOStatus = DeviceIoControl( hPschedDriverHandle, IOCTL_PSCHED_ZAW_EVENT, NULL, 0, NULL, 0, &uBytesReturned, NULL );
CloseHandle(hPschedDriverHandle);
} }
VOID PADeleteInUsePolicies( ) { DWORD dwError = 0;
TRACE(TRC_INFORMATION, (L"Deleting policy components no longer in use")); dwError = PADeleteInUseMMPolicies();
dwError = PADeleteInUseMMAuthMethods();
dwError = PADeleteInUseQMPolicies();
return; }
|