/*++ Copyright (c) 1999 Microsoft Corporation Module Name: ipsecspd.c Abstract: This module contains all of the code to drive the IPSecSPD Service. Author: abhisheV 30-September-1999 Environment User Level: Win32 Revision History: --*/ #include "precomp.h" #ifdef TRACE_ON #include "ipsecspd.tmh" #endif SERVICE_STATUS IPSecSPDStatus; SERVICE_STATUS_HANDLE IPSecSPDStatusHandle = NULL; #define IPSECSPD_SERVICE L"PolicyAgent" void WINAPI SPDServiceMain( IN DWORD dwArgc, IN LPTSTR * lpszArgv ) { DWORD dwError = 0; DWORD dwTempError = 0; WPP_INIT_TRACING(SPD_WPP_APPNAME); // Sleep(30000); InitMiscGlobals(); dwError = InitAuditing(); BAIL_ON_WIN32_ERROR(dwError); InitSPDThruRegistry(); // // Open the IPSec Driver first, so that if we bail on error later, // we can still set driver in block mode. // dwError = SPDOpenIPSecDriver( &ghIPSecDriver ); if (dwError) { AuditOneArgErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, IPSECSVC_DRIVER_INIT_FAILURE, dwError, FALSE, TRUE ); } BAIL_ON_WIN32_ERROR(dwError); // Initialize all the status fields so that the subsequent calls // to SetServiceStatus need to only update fields that changed. IPSecSPDStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; IPSecSPDStatus.dwCurrentState = SERVICE_START_PENDING; IPSecSPDStatus.dwControlsAccepted = 0; IPSecSPDStatus.dwCheckPoint = 1; IPSecSPDStatus.dwWaitHint = 5000; IPSecSPDStatus.dwWin32ExitCode = NO_ERROR; IPSecSPDStatus.dwServiceSpecificExitCode = 0; // Initialize the workstation to receive service requests // by registering the service control handler. IPSecSPDStatusHandle = RegisterServiceCtrlHandlerExW( IPSECSPD_SERVICE, IPSecSPDControlHandler, NULL ); if (IPSecSPDStatusHandle == (SERVICE_STATUS_HANDLE) NULL) { dwError = ERROR_INVALID_HANDLE; BAIL_ON_WIN32_ERROR(dwError); } (void) IPSecSPDUpdateStatus(); dwError = InitSPDGlobals(); BAIL_ON_WIN32_ERROR(dwError); IPSecSPDStatus.dwCurrentState = SERVICE_RUNNING; IPSecSPDStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT; IPSecSPDStatus.dwCheckPoint = 0; IPSecSPDStatus.dwWaitHint = 0; IPSecSPDStatus.dwWin32ExitCode = NO_ERROR; IPSecSPDStatus.dwServiceSpecificExitCode = 0; (void) IPSecSPDUpdateStatus(); // // Get the current list of active interfaces on the machine. // (VOID) CreateInterfaceList( &gpInterfaceList ); // // Get a list of DNS, DHCP, etc servers. // (VOID) GetSpecialAddrsList( &gpSpecialAddrsList ); gpIpsecPolicyState->PersIncarnationNumber = 0; dwError = LoadPersistedIPSecInformation(); BAIL_ON_WIN32_ERROR(dwError); dwError = SPDSetIPSecDriverOpMode( (DWORD) IPSEC_SECURE_MODE ); if (dwError) { AuditOneArgErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, IPSECSVC_DRIVER_INIT_FAILURE, dwError, FALSE, TRUE ); } BAIL_ON_WIN32_ERROR(dwError); dwError = SPDRegisterIPSecDriverProtocols( (DWORD) IPSEC_REGISTER_PROTOCOLS ); if (dwError) { AuditOneArgErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, IPSECSVC_DRIVER_INIT_FAILURE, dwError, FALSE, TRUE ); } BAIL_ON_WIN32_ERROR(dwError); // // Start IKE Service. // dwError = IKEInit(); if (dwError) { AuditOneArgErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, IPSECSVC_IKE_INIT_FAILURE, dwError, FALSE, TRUE ); TRACE(TRC_ERROR, (L"Failed to initialize IKE: %!winerr!", dwError)); } BAIL_ON_WIN32_ERROR(dwError); gbIsIKEUp = TRUE; gbIKENotify = TRUE; // // Start the RPC Server. // dwError = SPDStartRPCServer( ); if (dwError) { AuditOneArgErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, IPSECSVC_RPC_INIT_FAILURE, dwError, FALSE, TRUE ); TRACE(TRC_ERROR, (L"Failed to start RPC server: %!winerr!", dwError)); } BAIL_ON_WIN32_ERROR(dwError); dwError = ServiceWait(); error: #ifdef TRACE_ON if (dwError) { TRACE(TRC_ERROR, (L"Failed to start IPSec PolicyAgent: %!winerr!", dwError)); } #endif if (dwError && ghIPSecDriver != INVALID_HANDLE_VALUE) { dwTempError = SPDSetIPSecDriverOpMode( (DWORD) IPSEC_BLOCK_MODE ); if (gbAuditingInitialized) { AuditOneArgErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, IPSECSVC_SET_DRIVER_BLOCK, dwError, FALSE, TRUE ); } } IPSecSPDShutdown(dwError); return; } DWORD IPSecSPDUpdateStatus( ) { DWORD dwError = 0; if (!SetServiceStatus(IPSecSPDStatusHandle, &IPSecSPDStatus)) { dwError = GetLastError(); } return (dwError); } DWORD IPSecSPDControlHandler( IN DWORD dwOpCode, IN DWORD dwEventType, IN LPVOID lpEventData, IN LPVOID lpContext ) { DWORD dwErr = ERROR_SUCCESS; switch (dwOpCode) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: if (dwOpCode == SERVICE_CONTROL_SHUTDOWN) { gdwShutdownFlags = SPD_SHUTDOWN_MACHINE; } else { gdwShutdownFlags = SPD_SHUTDOWN_SERVICE; } if (IPSecSPDStatus.dwCurrentState != SERVICE_STOP_PENDING) { IPSecSPDStatus.dwCurrentState = SERVICE_STOP_PENDING; IPSecSPDStatus.dwCheckPoint = 1; IPSecSPDStatus.dwWaitHint = 60000; (void) IPSecSPDUpdateStatus(); SetEvent(ghServiceStopEvent); return dwErr; } break; case SERVICE_CONTROL_NEW_LOCAL_POLICY: SetEvent(ghNewLocalPolicyEvent); break; case SERVICE_CONTROL_FORCED_POLICY_RELOAD: SetEvent(ghForcedPolicyReloadEvent); break; case SERVICE_CONTROL_INTERROGATE: break; case SERVICE_CONTROL_POWEREVENT: switch ( dwEventType ) { case PBT_APMRESUMEAUTOMATIC: case PBT_APMRESUMECRITICAL: case PBT_APMRESUMESUSPEND: // Notify IKE of power event, ignore error if (gbIKENotify) { IKENotifyPolicyChange(NULL,POLICY_GUID_POWEREVENT_RESUME); } break; default: break; } } (void) IPSecSPDUpdateStatus(); return (dwErr); } VOID IPSecSPDShutdown( IN DWORD dwErrorCode ) { BOOL bMachineShutdown = FALSE; TRACE(TRC_INFORMATION, (L"PolicyAgent shutting down.")); bMachineShutdown = gdwShutdownFlags & SPD_SHUTDOWN_MACHINE; gbIKENotify = FALSE; (VOID) DeleteAllPolicyInformation(); ClearPolicyStateBlock( gpIpsecPolicyState ); if (gbLoadedISAKMPDefaults) { UnLoadDefaultISAKMPInformation(gpszDefaultISAKMPPolicyDN); } ClearPAStoreGlobals(); // // Service stop still pending. // Increment checkpoint counter and update // the status with the Service Control Manager. // (IPSecSPDStatus.dwCheckPoint)++; (void) IPSecSPDUpdateStatus(); if (gbSPDRPCServerUp) { gbSPDRPCServerUp = FALSE; SPDStopRPCServer(); } if (gbIsIKEUp) { gbIsIKEUp = FALSE; if (bMachineShutdown) { IKEShutdown(SPD_SHUTDOWN_MACHINE); } else { IKEShutdown(SPD_SHUTDOWN_SERVICE); } } if (gpIniMMPolicy) { FreeIniMMPolicyList(gpIniMMPolicy); gpIniMMPolicy = NULL; } if (gpIniMMAuthMethods) { FreeIniMMAuthMethodsList(gpIniMMAuthMethods); gpIniMMAuthMethods = NULL; } if (gpIniQMPolicy) { FreeIniQMPolicyList(gpIniQMPolicy); gpIniQMPolicy = NULL; } if (gpIniMMSFilter) { FreeIniMMSFilterList(gpIniMMSFilter); gpIniMMSFilter = NULL; } if (gpMMFilterHandle) { FreeMMFilterHandleList(gpMMFilterHandle); gpMMFilterHandle = NULL; } if (gpIniMMFilter) { FreeIniMMFilterList(gpIniMMFilter); gpIniMMFilter = NULL; } if (gpIniTxSFilter) { // Following call will check gShutdownFlags and // not delete ipsec filters if shutting down machine (VOID) DeleteTransportFiltersFromIPSec(gpIniTxSFilter); FreeIniTxSFilterList(gpIniTxSFilter); gpIniTxSFilter = NULL; } if (gpTxFilterHandle) { FreeTxFilterHandleList(gpTxFilterHandle); gpTxFilterHandle = NULL; } if (gpIniTxFilter) { FreeIniTxFilterList(gpIniTxFilter); gpIniTxFilter = NULL; } if (gpIniTnSFilter) { // Following call will check gShutdownFlags and // not delete ipsec filters if shutting down machine (VOID) DeleteTunnelFiltersFromIPSec(gpIniTnSFilter); FreeIniTnSFilterList(gpIniTnSFilter); gpIniTnSFilter = NULL; } if (gpTnFilterHandle) { FreeTnFilterHandleList(gpTnFilterHandle); gpTnFilterHandle = NULL; } if (gpIniTnFilter) { FreeIniTnFilterList(gpIniTnFilter); gpIniTnFilter = NULL; } if (!bMachineShutdown) { (VOID) SPDRegisterIPSecDriverProtocols( (DWORD) IPSEC_DEREGISTER_PROTOCOLS ); } if (ghIPSecDriver != INVALID_HANDLE_VALUE) { SPDCloseIPSecDriver(ghIPSecDriver); ghIPSecDriver = INVALID_HANDLE_VALUE; } if (gpInterfaceList) { DestroyInterfaceList( gpInterfaceList ); gpInterfaceList = NULL; } if (gpSpecialAddrsList) { FreeSpecialAddrList( &gpSpecialAddrsList ); gpSpecialAddrsList = NULL; } ClearSPDGlobals(); IPSecSPDStatus.dwCurrentState = SERVICE_STOPPED; IPSecSPDStatus.dwControlsAccepted = 0; IPSecSPDStatus.dwCheckPoint = 0; IPSecSPDStatus.dwWaitHint = 0; IPSecSPDStatus.dwWin32ExitCode = dwErrorCode; IPSecSPDStatus.dwServiceSpecificExitCode = 0; (void) IPSecSPDUpdateStatus(); WPP_CLEANUP(); return; } VOID ClearSPDGlobals( ) { DestroyInterfaceChangeEvent(); if (gbSPDSection) { DeleteCriticalSection(&gcSPDSection); } if (gbServerListenSection == TRUE) { DeleteCriticalSection(&gcServerListenSection); } if (ghServiceStopEvent) { CloseHandle(ghServiceStopEvent); ghServiceStopEvent = NULL; } if (ghNewDSPolicyEvent) { CloseHandle(ghNewDSPolicyEvent); ghNewDSPolicyEvent = NULL; } if (ghNewLocalPolicyEvent) { CloseHandle(ghNewLocalPolicyEvent); ghNewLocalPolicyEvent = NULL; } if (ghForcedPolicyReloadEvent) { CloseHandle(ghForcedPolicyReloadEvent); ghForcedPolicyReloadEvent = NULL; } if (ghPolicyChangeNotifyEvent) { CloseHandle(ghPolicyChangeNotifyEvent); ghPolicyChangeNotifyEvent = NULL; } if (ghGpupdateRefreshEvent) { CloseHandle(ghGpupdateRefreshEvent); ghGpupdateRefreshEvent = NULL; } if (gbSPDAuditSection) { DeleteCriticalSection(&gcSPDAuditSection); } gbAuditingInitialized = FALSE; if (gpSPDSD) { LocalFree(gpSPDSD); gpSPDSD = NULL; } } VOID ClearPAStoreGlobals( ) { if (gpMMFilterState) { PAFreeMMFilterStateList(gpMMFilterState); gpMMFilterState = NULL; } if (gpMMPolicyState) { PAFreeMMPolicyStateList(gpMMPolicyState); gpMMPolicyState = NULL; } if (gpMMAuthState) { PAFreeMMAuthStateList(gpMMAuthState); gpMMAuthState = NULL; } if (gpTxFilterState) { PAFreeTxFilterStateList(gpTxFilterState); gpTxFilterState = NULL; } if (gpTnFilterState) { PAFreeTnFilterStateList(gpTnFilterState); gpTnFilterState = NULL; } if (gpQMPolicyState) { PAFreeQMPolicyStateList(gpQMPolicyState); gpQMPolicyState = NULL; } } VOID InitMiscGlobals( ) { // // Init globals that aren't cleared on service stop to make sure // everything's in a known state on start. This allows us to // stop/restart without having our DLL unloaded/reloaded first. // gbSPDRPCServerUp = FALSE; ghServiceStopEvent = NULL; gdwServersListening = 0; gbServerListenSection = FALSE; gpInterfaceList = NULL; gpSpecialAddrsList = NULL; gbwsaStarted = FALSE; gIfChangeEventSocket = INVALID_SOCKET; ghIfChangeEvent = NULL; ghOverlapEvent = NULL; gpIniTxFilter = NULL; gpIniTxSFilter = NULL; gpTxFilterHandle = NULL; gbSPDSection = FALSE; gpIniQMPolicy = NULL; gpIniDefaultQMPolicy = NULL; gpIniMMPolicy = NULL; gpIniDefaultMMPolicy = NULL; gpIniMMFilter = NULL; gpIniMMSFilter = NULL; gpMMFilterHandle = NULL; gpIniMMAuthMethods = NULL; gpIniDefaultMMAuthMethods = NULL; gpIpsecPolicyState = &gIpsecPolicyState; gCurrentPollingInterval = 0; gDefaultPollingInterval = 166*60; // (seconds). gdwRetryCount = 0; gpszIpsecDSPolicyKey = L"SOFTWARE\\Policies\\Microsoft\\Windows\\IPSec\\GPTIPSECPolicy"; gpszIpsecLocalPolicyKey = L"SOFTWARE\\Policies\\Microsoft\\Windows\\IPSec\\Policy\\Local"; gpszIpsecPersistentPolicyKey = L"SOFTWARE\\Policies\\Microsoft\\Windows\\IPSec\\Policy\\Persistent"; gpszIpsecCachePolicyKey = L"SOFTWARE\\Policies\\Microsoft\\Windows\\IPSec\\Policy\\Cache"; gpszDefaultISAKMPPolicyDN = L"SOFTWARE\\Policies\\Microsoft\\Windows\\IPSec\\Policy\\Local\\ipsecISAKMPPolicy{72385234-70FA-11D1-864C-14A300000000}"; gpszLocPolicyAgent = L"SYSTEM\\CurrentControlSet\\Services\\PolicyAgent"; ghNewDSPolicyEvent = NULL; ghNewLocalPolicyEvent = NULL; ghForcedPolicyReloadEvent = NULL; ghPolicyChangeNotifyEvent = NULL; ghGpupdateRefreshEvent = NULL; gbLoadedISAKMPDefaults = FALSE; gpMMPolicyState = NULL; gpMMAuthState = NULL; gpMMFilterState = NULL; gdwMMPolicyCounter = 0; gdwMMFilterCounter = 0; gpQMPolicyState = NULL; gdwQMPolicyCounter = 0; gpTxFilterState = NULL; gdwTxFilterCounter = 0; gpIniTnFilter = NULL; gpIniTnSFilter = NULL; gpTnFilterHandle = NULL; gpTnFilterState = NULL; gdwTnFilterCounter = 0; gbIsIKEUp = FALSE; gpSPDSD = NULL; gbIKENotify = FALSE; ghIPSecDriver = INVALID_HANDLE_VALUE; gbSPDAuditSection = FALSE; ghIpsecServerModule = NULL; gbAuditingInitialized = FALSE; gbIsIoctlPended = FALSE; gbBackwardSoftSA = FALSE; gdwShutdownFlags = 0; gbPersistentPolicyApplied = FALSE; return; } DWORD QuerySpdPolicyState( LPWSTR pServerName, DWORD dwVersion, PSPD_POLICY_STATE * ppSpdPolicyState, LPVOID pvReserved ) { DWORD dwError = 0; PSPD_POLICY_STATE pSpdPolicyState = NULL; dwError = SPDApiBufferAllocate( sizeof(SPD_POLICY_STATE), &pSpdPolicyState ); BAIL_ON_WIN32_ERROR(dwError); ENTER_SPD_SECTION(); dwError = ValidateSecurity( SPD_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL ); BAIL_ON_LOCK_ERROR(dwError); pSpdPolicyState->PolicyLoadState = gpIpsecPolicyState->CurrentState; switch (gpIpsecPolicyState->CurrentState) { case SPD_STATE_DS_APPLY_SUCCESS: pSpdPolicyState->dwWhenChanged = gpIpsecPolicyState->DSIncarnationNumber; break; case SPD_STATE_LOCAL_APPLY_SUCCESS: case SPD_STATE_CACHE_APPLY_SUCCESS: pSpdPolicyState->dwWhenChanged = gpIpsecPolicyState->RegIncarnationNumber; break; case SPD_STATE_PERSISTENT_APPLY_SUCCESS: pSpdPolicyState->dwWhenChanged = gpIpsecPolicyState->PersIncarnationNumber; break; default: pSpdPolicyState->dwWhenChanged = 0; break; } LEAVE_SPD_SECTION(); *ppSpdPolicyState = pSpdPolicyState; return (dwError); lock: LEAVE_SPD_SECTION(); error: if (pSpdPolicyState) { SPDApiBufferFree(pSpdPolicyState); } *ppSpdPolicyState = NULL; return (dwError); } DWORD SetSpdStateOnError( DWORD dwPolicySource, SPD_ACTION SpdAction, DWORD ActionError, SPD_STATE * pSpdState ) { SPD_STATE SpdPolicyState = 0; DWORD dwError = ERROR_SUCCESS; if (!pSpdState) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } // Collapse triplet into one flag: // Long-winded, but by doing it like this we simplify readability // of other parts of code. if (!ActionError) { if (SpdAction == SPD_POLICY_APPLY) { switch(dwPolicySource) { case IPSEC_SOURCE_PERSISTENT: SpdPolicyState = SPD_STATE_PERSISTENT_APPLY_SUCCESS; break; case IPSEC_SOURCE_LOCAL: SpdPolicyState = SPD_STATE_LOCAL_APPLY_SUCCESS; break; case IPSEC_SOURCE_DOMAIN: SpdPolicyState = SPD_STATE_DS_APPLY_SUCCESS; break; case IPSEC_SOURCE_CACHE: SpdPolicyState = SPD_STATE_CACHE_APPLY_SUCCESS; break; } } else if (SpdAction == SPD_POLICY_LOAD) { switch(dwPolicySource) { case IPSEC_SOURCE_PERSISTENT: SpdPolicyState = SPD_STATE_PERSISTENT_LOAD_SUCCESS; break; case IPSEC_SOURCE_LOCAL: SpdPolicyState = SPD_STATE_LOCAL_LOAD_SUCCESS; break; case IPSEC_SOURCE_DOMAIN: SpdPolicyState = SPD_STATE_DS_LOAD_SUCCESS; break; case IPSEC_SOURCE_CACHE: SpdPolicyState = SPD_STATE_CACHE_LOAD_SUCCESS; break; } } } else { if (SpdAction == SPD_POLICY_APPLY) { switch(dwPolicySource) { case IPSEC_SOURCE_PERSISTENT: SpdPolicyState = SPD_STATE_PERSISTENT_APPLY_FAIL; break; case IPSEC_SOURCE_LOCAL: SpdPolicyState = SPD_STATE_LOCAL_APPLY_FAIL; break; case IPSEC_SOURCE_DOMAIN: SpdPolicyState = SPD_STATE_DS_APPLY_FAIL; break; case IPSEC_SOURCE_CACHE: SpdPolicyState = SPD_STATE_CACHE_APPLY_FAIL; break; } } else if (SpdAction == SPD_POLICY_LOAD) { switch(dwPolicySource) { case IPSEC_SOURCE_PERSISTENT: SpdPolicyState = SPD_STATE_PERSISTENT_LOAD_FAIL; break; case IPSEC_SOURCE_LOCAL: SpdPolicyState = SPD_STATE_LOCAL_LOAD_FAIL; break; case IPSEC_SOURCE_DOMAIN: SpdPolicyState = SPD_STATE_DS_LOAD_FAIL; break; case IPSEC_SOURCE_CACHE: SpdPolicyState = SPD_STATE_CACHE_LOAD_FAIL; break; } } } (*pSpdState) = SpdPolicyState; error: return ERROR_SUCCESS; } BOOL InAcceptableState( SPD_STATE SpdState ) { BOOL AcceptableState = FALSE; switch (SpdState) { case SPD_STATE_LOCAL_APPLY_SUCCESS: case SPD_STATE_DS_APPLY_SUCCESS: case SPD_STATE_PERSISTENT_APPLY_SUCCESS: case SPD_STATE_INITIAL: AcceptableState = TRUE; break; } return AcceptableState; }