#include "precomp.h" #ifdef TRACE_ON #include "pastore.tmh" #endif VOID InitializePolicyStateBlock( PIPSEC_POLICY_STATE pIpsecPolicyState ) { memset(pIpsecPolicyState, 0, sizeof(IPSEC_POLICY_STATE)); pIpsecPolicyState->DefaultPollingInterval = gDefaultPollingInterval; } DWORD StartStatePollingManager( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; if (IsDirectoryPolicySpecified()) { dwError = PlumbDirectoryPolicy( pIpsecPolicyState ); if (dwError) { dwError = PlumbCachePolicy( pIpsecPolicyState ); } } else if (IsLocalPolicySpecified()) { dwError = PlumbLocalPolicy( pIpsecPolicyState ); BAIL_ON_WIN32_ERROR(dwError); } #ifdef TRACE_ON else { TRACE(TRC_INFORMATION, ("Pastore did not detect any local or domain policy assigned.")); } #endif // // The new polling interval has been set by either the // registry code or the DS code or remains at initialized value. // gCurrentPollingInterval = pIpsecPolicyState->CurrentPollingInterval; TRACE( TRC_INFORMATION, ("Set global polling interval to %d", gCurrentPollingInterval) ); return (dwError); error: return (dwError); } DWORD PlumbDirectoryPolicy( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; LPWSTR pszDirectoryPolicyDN = NULL; PIPSEC_POLICY_OBJECT pIpsecPolicyObject = NULL; PIPSEC_POLICY_DATA pIpsecPolicyData = NULL; DWORD dwStoreType = IPSEC_DIRECTORY_PROVIDER; DWORD dwSlientErrorCode = 0; BOOL bIsActivePolicy = FALSE; SPD_ACTION SpdAction = SPD_POLICY_LOAD; TRACE(TRC_INFORMATION, (L"Plumbing directory policy")); dwError = GetDirectoryPolicyDN( &pszDirectoryPolicyDN ); BAIL_ON_WIN32_ERROR(dwError); bIsActivePolicy = TRUE; dwError = LoadDirectoryPolicy( pszDirectoryPolicyDN, &pIpsecPolicyObject ); BAIL_ON_WIN32_ERROR(dwError); dwError = ProcessNFAs( pIpsecPolicyObject, dwStoreType, &dwSlientErrorCode, &pIpsecPolicyData ); BAIL_ON_WIN32_ERROR(dwError); AuditIPSecPolicyEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_LOAD_DS_POLICY_SUCCESS, pIpsecPolicyData->pszIpsecName, TRUE, TRUE ); SpdAction = SPD_POLICY_APPLY; if (pIpsecPolicyState->pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyState->pIpsecPolicyObject); } if (pIpsecPolicyState->pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyState->pIpsecPolicyData); } if (pIpsecPolicyState->pszDirectoryPolicyDN) { FreeSPDStr(pIpsecPolicyState->pszDirectoryPolicyDN); } pIpsecPolicyState->pIpsecPolicyObject = pIpsecPolicyObject; pIpsecPolicyObject = NULL; pIpsecPolicyState->pIpsecPolicyData = pIpsecPolicyData; pIpsecPolicyData = NULL; pIpsecPolicyState->pszDirectoryPolicyDN = pszDirectoryPolicyDN; pszDirectoryPolicyDN = NULL; // // Plumb the DS policy. // dwError = ApplyLoadedDirectoryPolicy( pIpsecPolicyState ); // If error rollback. Ignoring rollback errors, because nothing can be done. // if (dwError) { TRACE(TRC_INFORMATION, ("Pastore rolling back policy application due to previous errors")); (VOID) DeletePolicyInformation( pIpsecPolicyState->pIpsecPolicyData ); } BAIL_ON_WIN32_ERROR(dwError); dwError = ERROR_SUCCESS; if (dwSlientErrorCode) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_SOME_NFA_APPLICATION, pIpsecPolicyState->pIpsecPolicyData->pszIpsecName, dwSlientErrorCode, FALSE, TRUE ); TRACE( TRC_WARNING, ("Pastore failed to process one or more NFAs. Please compare active policy in SPD with static policy in storage: %!winerr!", dwSlientErrorCode) ); } return (dwError); error: SetSpdStateOnError( IPSEC_SOURCE_DOMAIN, SpdAction, dwError, &pIpsecPolicyState->CurrentState ); // // Audit if we had an error loading policy (ApplyLoadedDirectoryPolicy handles // auditing for policy pplication) // if (bIsActivePolicy && pszDirectoryPolicyDN && SpdAction == SPD_POLICY_LOAD) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_LOAD_DS_POLICY_FAIL, pszDirectoryPolicyDN, dwError, FALSE, TRUE ); } if (pszDirectoryPolicyDN) { FreeSPDStr(pszDirectoryPolicyDN); } if (pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyObject); } if (pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyData); } // ASSERT: if ApplyLoadedDirectoryPolicy failed, then pIpsecPolicyState->pIpsecPolicyObject, are set to the // pIpsecPolicyState->pIpsecPolicyData and pIpsecPolicyState->pszCachePolicyDN are filled // with the values of the loaded BUT Unapplied policy. return (dwError); } DWORD GetDirectoryPolicyDN( LPWSTR * ppszDirectoryPolicyDN ) { DWORD dwError = 0; HKEY hPolicyKey = NULL; LPWSTR pszIpsecPolicyName = NULL; DWORD dwSize = 0; LPWSTR pszPolicyDN = NULL; LPWSTR pszDirectoryPolicyDN = NULL; *ppszDirectoryPolicyDN = NULL; dwError = RegOpenKeyExW( HKEY_LOCAL_MACHINE, gpszIpsecDSPolicyKey, 0, KEY_ALL_ACCESS, &hPolicyKey ); BAIL_ON_WIN32_ERROR(dwError); dwError = RegstoreQueryValue( hPolicyKey, L"DSIPSECPolicyPath", REG_SZ, (LPBYTE *)&pszIpsecPolicyName, &dwSize ); BAIL_ON_WIN32_ERROR(dwError); // // Move by LDAP:// to get the real DN and allocate // this string. // Fix this by fixing the gpo extension. // pszPolicyDN = pszIpsecPolicyName + wcslen(L"LDAP://"); pszDirectoryPolicyDN = AllocSPDStr(pszPolicyDN); if (!pszDirectoryPolicyDN) { dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32_ERROR(dwError); } *ppszDirectoryPolicyDN = pszDirectoryPolicyDN; error: #ifdef TRACE_ON if (dwError) { TRACE(TRC_ERROR, ("Failed to determine directory policy DN: %!winerr!", dwError)); } #endif if (pszIpsecPolicyName) { FreeSPDStr(pszIpsecPolicyName); } if (hPolicyKey) { CloseHandle(hPolicyKey); } return (dwError); } DWORD LoadDirectoryPolicy( LPWSTR pszDirectoryPolicyDN, PIPSEC_POLICY_OBJECT * ppIpsecPolicyObject ) { DWORD dwError = 0; LPWSTR pszDefaultDirectory = NULL; HLDAP hLdapBindHandle = NULL; PIPSEC_POLICY_OBJECT pIpsecPolicyObject = NULL; TRACE(TRC_INFORMATION, (L"Loading directory policy.")); dwError = ComputeDefaultDirectory( &pszDefaultDirectory ); BAIL_ON_WIN32_ERROR(dwError); dwError = OpenDirectoryServerHandle( pszDefaultDirectory, 389, &hLdapBindHandle ); BAIL_ON_WIN32_ERROR(dwError); dwError = ReadPolicyObjectFromDirectory( hLdapBindHandle, pszDirectoryPolicyDN, &pIpsecPolicyObject ); BAIL_ON_WIN32_ERROR(dwError); *ppIpsecPolicyObject = pIpsecPolicyObject; TRACE(TRC_INFORMATION, (L"Loaded directory policy from \"%ls\"", pszDirectoryPolicyDN)); cleanup: if (pszDefaultDirectory) { FreeSPDStr(pszDefaultDirectory); } if (hLdapBindHandle) { CloseDirectoryServerHandle(hLdapBindHandle); } return (dwError); error: TRACE( TRC_ERROR, (L"Failed to load directory policy from \"%ls\": %!winerr!", pszDirectoryPolicyDN, dwError) ); *ppIpsecPolicyObject = NULL; goto cleanup; } DWORD ApplyLoadedDirectoryPolicy( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; PIPSEC_POLICY_DATA pIpsecPolicyData = NULL; TRACE(TRC_INFORMATION, (L"Applying loaded directory policy.")); pIpsecPolicyData = pIpsecPolicyState->pIpsecPolicyData; // // Plumb the DS policy. // dwError = AddPolicyInformation( pIpsecPolicyData, IPSEC_SOURCE_DOMAIN ); BAIL_ON_WIN32_ERROR(dwError); // // Delete the old cache and write the new one in. // DeleteRegistryCache(); CacheDirectorytoRegistry(pIpsecPolicyState->pIpsecPolicyObject); // // Set the state to DS_DOWNLOADED. // SetSpdStateOnError( IPSEC_SOURCE_DOMAIN, SPD_POLICY_APPLY, ERROR_SUCCESS, &pIpsecPolicyState->CurrentState ); // // Compute the new polling interval. // pIpsecPolicyState->CurrentPollingInterval = pIpsecPolicyData->dwPollingInterval; pIpsecPolicyState->DSIncarnationNumber = pIpsecPolicyData->dwWhenChanged; pIpsecPolicyState->RegIncarnationNumber = 0; gCurrentPollingInterval = pIpsecPolicyState->CurrentPollingInterval; TRACE( TRC_INFORMATION, ("Set global polling interval to %d", gCurrentPollingInterval) ); dwError = ERROR_SUCCESS; AuditIPSecPolicyEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_APPLIED_DS_POLICY, pIpsecPolicyData->pszIpsecName, TRUE, TRUE ); TRACE( TRC_INFORMATION, (L"Applied directory policy %ls loaded from %ls", pIpsecPolicyData->pszIpsecName, pIpsecPolicyState->pszDirectoryPolicyDN) ); return (dwError); error: TRACE( TRC_ERROR, (L"Failed to apply directory policy %ls loaded from %ls", pIpsecPolicyData->pszIpsecName, pIpsecPolicyState->pszDirectoryPolicyDN) ); SetSpdStateOnError( IPSEC_SOURCE_DOMAIN, SPD_POLICY_APPLY, dwError, &pIpsecPolicyState->CurrentState ); AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_DS_POLICY_APPLICATION, pIpsecPolicyData->pszIpsecName, dwError, FALSE, TRUE ); return (dwError); } DWORD PlumbCachePolicy( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; LPWSTR pszCachePolicyDN = NULL; PIPSEC_POLICY_OBJECT pIpsecPolicyObject = NULL; PIPSEC_POLICY_DATA pIpsecPolicyData = NULL; DWORD dwStoreType = IPSEC_REGISTRY_PROVIDER; DWORD dwSlientErrorCode = 0; BOOL bIsActivePolicy = FALSE; SPD_ACTION SpdAction = SPD_POLICY_LOAD; TRACE(TRC_INFORMATION, (L"Plumbing cache policy.")); dwError = GetCachePolicyDN( &pszCachePolicyDN ); BAIL_ON_WIN32_ERROR(dwError); bIsActivePolicy = TRUE; dwError = LoadCachePolicy( pszCachePolicyDN, &pIpsecPolicyObject ); BAIL_ON_WIN32_ERROR(dwError); dwError = ProcessNFAs( pIpsecPolicyObject, dwStoreType, &dwSlientErrorCode, &pIpsecPolicyData ); BAIL_ON_WIN32_ERROR(dwError); SpdAction = SPD_POLICY_APPLY; dwError = AddPolicyInformation( pIpsecPolicyData, IPSEC_SOURCE_CACHE ); // If error rollback. Ignoring rollback errors, because nothing can be done. // if (dwError) { TRACE(TRC_INFORMATION, ("Pastore rolling back policy application due to previous errors")); (VOID) DeletePolicyInformation( pIpsecPolicyData ); } BAIL_ON_WIN32_ERROR(dwError); if (pIpsecPolicyState->pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyState->pIpsecPolicyObject); } if (pIpsecPolicyState->pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyState->pIpsecPolicyData); } if (pIpsecPolicyState->pszCachePolicyDN) { FreeSPDStr(pIpsecPolicyState->pszCachePolicyDN); } pIpsecPolicyState->pIpsecPolicyObject = pIpsecPolicyObject; pIpsecPolicyState->pIpsecPolicyData = pIpsecPolicyData; pIpsecPolicyState->pszCachePolicyDN = pszCachePolicyDN; // // Set the state to SPD_STATE_CACHE_APPLY_SUCCESS. // // SetSpdStateOnError( IPSEC_SOURCE_CACHE, SPD_POLICY_APPLY, ERROR_SUCCESS, &pIpsecPolicyState->CurrentState ); // // Compute the new polling interval. // pIpsecPolicyState->CurrentPollingInterval = pIpsecPolicyData->dwPollingInterval; pIpsecPolicyState->DSIncarnationNumber = 0; pIpsecPolicyState->RegIncarnationNumber = pIpsecPolicyData->dwWhenChanged; gCurrentPollingInterval = pIpsecPolicyState->CurrentPollingInterval; TRACE( TRC_INFORMATION, ("Set global polling interval to %d", gCurrentPollingInterval) ); dwError = ERROR_SUCCESS; if (dwSlientErrorCode) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_SOME_NFA_APPLICATION, pIpsecPolicyData->pszIpsecName, dwSlientErrorCode, FALSE, TRUE ); TRACE( TRC_WARNING, ("Pastore failed to process one or more NFAs. Please compare active policy in SPD with policy in storage: %!winerr!", dwSlientErrorCode) ); } AuditIPSecPolicyEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_APPLIED_CACHED_POLICY, pIpsecPolicyData->pszIpsecName, TRUE, TRUE ); TRACE( TRC_INFORMATION, (L"Applied cache policy %ls loaded from %ls", pIpsecPolicyData->pszIpsecName, pIpsecPolicyState->pszCachePolicyDN) ); return (dwError); error: TRACE( TRC_ERROR, (L"Failed to plumb cache policy.") ); SetSpdStateOnError( IPSEC_SOURCE_CACHE, SpdAction, dwError, &pIpsecPolicyState->CurrentState ); // // Check pszCachePolicyDN for non-NULL. // if (bIsActivePolicy && pszCachePolicyDN) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_CACHED_POLICY_APPLICATION, pszCachePolicyDN, dwError, FALSE, TRUE ); } if (pszCachePolicyDN) { FreeSPDStr(pszCachePolicyDN); } if (pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyObject); } if (pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyData); } return (dwError); } DWORD GetCachePolicyDN( LPWSTR * ppszCachePolicyDN ) { DWORD dwError = 0; LPWSTR pszDirectoryPolicyDN = NULL; LPWSTR pszCachePolicyDN = NULL; *ppszCachePolicyDN = NULL; dwError = GetDirectoryPolicyDN( &pszDirectoryPolicyDN ); BAIL_ON_WIN32_ERROR(dwError); dwError = CopyPolicyDSToFQRegString( pszDirectoryPolicyDN, &pszCachePolicyDN ); BAIL_ON_WIN32_ERROR(dwError); *ppszCachePolicyDN = pszCachePolicyDN; error: #ifdef TRACE_ON if (dwError) { TRACE(TRC_ERROR, ("Failed to determine cache policy DN: %!winerr!", dwError)); } #endif if (pszDirectoryPolicyDN) { FreeSPDStr(pszDirectoryPolicyDN); } return (dwError); } DWORD LoadCachePolicy( LPWSTR pszCachePolicyDN, PIPSEC_POLICY_OBJECT * ppIpsecPolicyObject ) { DWORD dwError = 0; HKEY hRegistryKey = NULL; PIPSEC_POLICY_OBJECT pIpsecPolicyObject = NULL; TRACE(TRC_INFORMATION, (L"Loading cache policy.")); dwError = OpenRegistryIPSECRootKey( NULL, gpszIpsecCachePolicyKey, &hRegistryKey ); BAIL_ON_WIN32_ERROR(dwError); dwError = ReadPolicyObjectFromRegistry( hRegistryKey, pszCachePolicyDN, gpszIpsecCachePolicyKey, &pIpsecPolicyObject ); BAIL_ON_WIN32_ERROR(dwError); *ppIpsecPolicyObject = pIpsecPolicyObject; cleanup: if (hRegistryKey) { CloseHandle(hRegistryKey); } return (dwError); error: TRACE( TRC_ERROR, (L"Failed to load cache policy from \"%ls\": %!winerr!", pszCachePolicyDN, dwError) ); *ppIpsecPolicyObject = NULL; goto cleanup; } DWORD PlumbLocalPolicy( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; LPWSTR pszRegistryPolicyDN = NULL; PIPSEC_POLICY_OBJECT pIpsecPolicyObject = NULL; PIPSEC_POLICY_DATA pIpsecPolicyData = NULL; DWORD dwStoreType = IPSEC_REGISTRY_PROVIDER; DWORD dwSlientErrorCode = 0; BOOL bIsActivePolicy = FALSE; SPD_ACTION SpdAction = SPD_POLICY_LOAD; TRACE(TRC_INFORMATION, (L"Plumbing local policy.")); dwError = GetRegistryPolicyDN( &pszRegistryPolicyDN, IPSEC_STORE_LOCAL ); BAIL_ON_WIN32_ERROR(dwError); bIsActivePolicy = TRUE; dwError = LoadRegistryPolicy( pszRegistryPolicyDN, &pIpsecPolicyObject, IPSEC_STORE_LOCAL ); BAIL_ON_WIN32_ERROR(dwError); dwError = ProcessNFAs( pIpsecPolicyObject, dwStoreType, &dwSlientErrorCode, &pIpsecPolicyData ); BAIL_ON_WIN32_ERROR(dwError); AuditIPSecPolicyEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_LOAD_LOCAL_POLICY_SUCCESS, pIpsecPolicyData->pszIpsecName, TRUE, TRUE ); SpdAction = SPD_POLICY_APPLY; if (pIpsecPolicyState->pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyState->pIpsecPolicyObject); } if (pIpsecPolicyState->pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyState->pIpsecPolicyData); } if (pIpsecPolicyState->pszRegistryPolicyDN) { FreeSPDStr(pIpsecPolicyState->pszRegistryPolicyDN); } pIpsecPolicyState->pIpsecPolicyObject = pIpsecPolicyObject; pIpsecPolicyObject = NULL; pIpsecPolicyState->pIpsecPolicyData = pIpsecPolicyData; pIpsecPolicyData = NULL; pIpsecPolicyState->pszRegistryPolicyDN = pszRegistryPolicyDN; pszRegistryPolicyDN = NULL; dwError = ApplyLoadedLocalPolicy( pIpsecPolicyState ); // If error rollback. Ignoring rollback errors, because nothing can be done. // if (dwError) { TRACE(TRC_INFORMATION, ("Pastore rolling back policy application due to previous errors")); (VOID) DeletePolicyInformation( pIpsecPolicyState->pIpsecPolicyData ); } BAIL_ON_WIN32_ERROR(dwError); dwError = ERROR_SUCCESS; if (dwSlientErrorCode) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_SOME_NFA_APPLICATION, pIpsecPolicyState->pIpsecPolicyData->pszIpsecName, dwSlientErrorCode, FALSE, TRUE ); TRACE( TRC_WARNING, ("Pastore failed to process one or more NFAs. Please compare active policy in SPD with policy in storage: %!winerr!", dwSlientErrorCode) ); } return (dwError); error: SetSpdStateOnError( IPSEC_SOURCE_LOCAL, SpdAction, dwError, &pIpsecPolicyState->CurrentState ); // // Audit if we had an error loading policy (ApplyLoadedDirectoryPolicy handles // auditing for policy pplication) // if (bIsActivePolicy && pszRegistryPolicyDN && SpdAction == SPD_POLICY_LOAD) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_LOAD_LOCAL_POLICY_FAIL, pszRegistryPolicyDN, dwError, FALSE, TRUE ); } if (pszRegistryPolicyDN) { FreeSPDStr(pszRegistryPolicyDN); } if (pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyObject); } if (pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyData); } // ASSERT: if ApplyLoadedLocalPolicy failed, then pIpsecPolicyState->pIpsecPolicyObject, are set to the // pIpsecPolicyState->pIpsecPolicyData and pIpsecPolicyState->pszCachePolicyDN are filled // with the values of the loaded BUT Unapplied policy. return (dwError); } DWORD ApplyLoadedLocalPolicy( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; PIPSEC_POLICY_DATA pIpsecPolicyData = NULL; TRACE(TRC_INFORMATION, (L"Applying loaded local policy.")); pIpsecPolicyData = pIpsecPolicyState->pIpsecPolicyData; dwError = AddPolicyInformation( pIpsecPolicyData, IPSEC_SOURCE_LOCAL ); BAIL_ON_WIN32_ERROR(dwError); SetSpdStateOnError( IPSEC_SOURCE_LOCAL, SPD_POLICY_APPLY, ERROR_SUCCESS, &pIpsecPolicyState->CurrentState ); // // Compute the new polling interval. // pIpsecPolicyState->CurrentPollingInterval = pIpsecPolicyData->dwPollingInterval; pIpsecPolicyState->DSIncarnationNumber = 0; pIpsecPolicyState->RegIncarnationNumber = pIpsecPolicyData->dwWhenChanged; gCurrentPollingInterval = pIpsecPolicyState->CurrentPollingInterval; TRACE( TRC_INFORMATION, ("Set global polling interval to %d", gCurrentPollingInterval) ); dwError = ERROR_SUCCESS; AuditIPSecPolicyEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_APPLIED_LOCAL_POLICY, pIpsecPolicyData->pszIpsecName, TRUE, TRUE ); TRACE( TRC_INFORMATION, (L"Applied local policy %ls loaded from %ls", pIpsecPolicyData->pszIpsecName, pIpsecPolicyState->pszRegistryPolicyDN) ); return (dwError); error: TRACE( TRC_ERROR, (L"Failed to apply local policy %ls loaded from %ls", pIpsecPolicyData->pszIpsecName, pIpsecPolicyState->pszDirectoryPolicyDN) ); SetSpdStateOnError( IPSEC_SOURCE_LOCAL, SPD_POLICY_APPLY, dwError, &pIpsecPolicyState->CurrentState ); AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_LOCAL_POLICY_APPLICATION, pIpsecPolicyData->pszIpsecName, dwError, FALSE, TRUE ); return (dwError); } DWORD PlumbPersistentPolicy( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; LPWSTR pszRegistryPolicyDN = NULL; PIPSEC_POLICY_OBJECT pIpsecPolicyObject = NULL; PIPSEC_POLICY_DATA pIpsecPolicyData = NULL; DWORD dwStoreType = IPSEC_REGISTRY_PROVIDER; DWORD dwSlientErrorCode = 0; BOOL bIsActivePolicy = FALSE; SPD_ACTION SpdAction = SPD_POLICY_LOAD; TRACE(TRC_INFORMATION, (L"Plumbing local policy.")); dwError = GetRegistryPolicyDN( &pszRegistryPolicyDN, IPSEC_STORE_PERSISTENT ); BAIL_ON_WIN32_ERROR(dwError); bIsActivePolicy = TRUE; dwError = LoadRegistryPolicy( pszRegistryPolicyDN, &pIpsecPolicyObject, IPSEC_STORE_PERSISTENT ); BAIL_ON_WIN32_ERROR(dwError); dwError = ProcessNFAs( pIpsecPolicyObject, dwStoreType, &dwSlientErrorCode, &pIpsecPolicyData ); BAIL_ON_WIN32_ERROR(dwError); AuditIPSecPolicyEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_LOAD_PERSISTENT_POLICY_SUCCESS, pIpsecPolicyData->pszIpsecName, TRUE, TRUE ); SpdAction = SPD_POLICY_APPLY; dwError = AddPolicyInformation( pIpsecPolicyData, IPSEC_SOURCE_PERSISTENT ); BAIL_ON_WIN32_ERROR(dwError); if (pIpsecPolicyState->pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyState->pIpsecPolicyObject); } if (pIpsecPolicyState->pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyState->pIpsecPolicyData); } if (pIpsecPolicyState->pszRegistryPolicyDN) { FreeSPDStr(pIpsecPolicyState->pszRegistryPolicyDN); } pIpsecPolicyState->pIpsecPolicyObject = pIpsecPolicyObject; pIpsecPolicyState->pIpsecPolicyData = pIpsecPolicyData; pIpsecPolicyState->pszRegistryPolicyDN = pszRegistryPolicyDN; SetSpdStateOnError( IPSEC_SOURCE_PERSISTENT, SPD_POLICY_APPLY, ERROR_SUCCESS, &gpIpsecPolicyState->CurrentState ); gbPersistentPolicyApplied = TRUE; pIpsecPolicyState->PersIncarnationNumber = pIpsecPolicyData->dwWhenChanged; dwError = ERROR_SUCCESS; if (dwSlientErrorCode) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_SOME_NFA_APPLICATION, pIpsecPolicyData->pszIpsecName, dwSlientErrorCode, FALSE, TRUE ); TRACE( TRC_WARNING, ("Pastore failed to process one or more NFAs. Please compare active policy in SPD policy in storage: %!winerr!", dwSlientErrorCode) ); } AuditIPSecPolicyEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_APPLIED_PERSISTENT_POLICY, pIpsecPolicyData->pszIpsecName, TRUE, TRUE ); TRACE(TRC_INFORMATION, ("Plumbed persistent policy")); return (dwError); error: TRACE( TRC_ERROR, (L"Failed to plumb persistent policy.") ); SetSpdStateOnError( IPSEC_SOURCE_PERSISTENT, SpdAction, dwError, &gpIpsecPolicyState->CurrentState ); gbPersistentPolicyApplied = FALSE; // // Check pszRegistryPolicyDN for non-NULL. // if (bIsActivePolicy && pszRegistryPolicyDN && SpdAction == SPD_POLICY_LOAD) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_LOAD_PERSISTENT_POLICY_FAIL, pszRegistryPolicyDN, dwError, FALSE, TRUE ); } else if (SpdAction == SPD_POLICY_APPLY && pIpsecPolicyData) { // (Above pIPsecPolicyData can't be null if SPD_POLICY_APPLY, // but needed check to get prefast off our back) AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_PERSISTENT_POLICY_APPLICATION, pIpsecPolicyData->pszIpsecName, dwError, FALSE, TRUE ); } if (pszRegistryPolicyDN) { FreeSPDStr(pszRegistryPolicyDN); } if (pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyObject); } if (pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyData); } return (dwError); } LPWSTR GetRegPathForStore( IN DWORD dwStore) { if (dwStore == IPSEC_STORE_PERSISTENT) { return gpszIpsecPersistentPolicyKey; } else if (dwStore == IPSEC_STORE_LOCAL) { return gpszIpsecLocalPolicyKey; } return NULL; } DWORD GetRegistryPolicyDN( LPWSTR * ppszRegistryPolicyDN, IN DWORD dwStore ) { DWORD dwError = 0; HKEY hPolicyKey = NULL; LPWSTR pszIpsecPolicyName = NULL; DWORD dwSize = 0; LPWSTR pszRegPath = NULL; pszRegPath = GetRegPathForStore(dwStore); if (pszRegPath == NULL) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } dwError = RegOpenKeyExW( HKEY_LOCAL_MACHINE, pszRegPath, 0, KEY_ALL_ACCESS, &hPolicyKey ); BAIL_ON_WIN32_ERROR(dwError); dwError = RegstoreQueryValue( hPolicyKey, L"ActivePolicy", REG_SZ, (LPBYTE *)&pszIpsecPolicyName, &dwSize ); BAIL_ON_WIN32_ERROR(dwError); if (!pszIpsecPolicyName || !*pszIpsecPolicyName) { dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32_ERROR(dwError); } *ppszRegistryPolicyDN = pszIpsecPolicyName; cleanup: if (hPolicyKey) { CloseHandle(hPolicyKey); } return (dwError); error: TRACE( TRC_ERROR, (L"Failed to get %ls policy DN: %!winerr!", dwStore == IPSEC_STORE_LOCAL ? L"local" : L"persistent", dwError) ); if (pszIpsecPolicyName) { FreeSPDStr(pszIpsecPolicyName); } *ppszRegistryPolicyDN = NULL; goto cleanup; } DWORD LoadRegistryPolicy( LPWSTR pszRegistryPolicyDN, PIPSEC_POLICY_OBJECT * ppIpsecPolicyObject, IN DWORD dwStore ) { DWORD dwError = 0; HKEY hRegistryKey = NULL; PIPSEC_POLICY_OBJECT pIpsecPolicyObject = NULL; LPWSTR pszRegPath = NULL; TRACE(TRC_INFORMATION, (L"Loading registry policy.")); pszRegPath = GetRegPathForStore(dwStore); if (pszRegPath == NULL) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } dwError = OpenRegistryIPSECRootKey( NULL, pszRegPath, &hRegistryKey ); BAIL_ON_WIN32_ERROR(dwError); dwError = ReadPolicyObjectFromRegistry( hRegistryKey, pszRegistryPolicyDN, pszRegPath, &pIpsecPolicyObject ); BAIL_ON_WIN32_ERROR(dwError); *ppIpsecPolicyObject = pIpsecPolicyObject; cleanup: if (hRegistryKey) { CloseHandle(hRegistryKey); } return (dwError); error: TRACE( TRC_ERROR, (L"Failed to load %ls policy from \"%ls\": %!winerr!", dwStore == IPSEC_STORE_LOCAL ? L"local" : L"persistent", pszRegistryPolicyDN, dwError) ); *ppIpsecPolicyObject = NULL; goto cleanup; } DWORD LoadPersistedIPSecInformation( ) { DWORD dwError = ERROR_SUCCESS; IPSEC_POLICY_STATE IpsecPolicyState; // Initialize Policy State Block. // InitializePolicyStateBlock(&IpsecPolicyState); // Load and apply the persisted store // if (IsPersistentPolicySpecified()) { dwError = PlumbPersistentPolicy( &IpsecPolicyState ); BAIL_ON_WIN32_ERROR(dwError); } #ifdef TRACE_ON else { TRACE(TRC_INFORMATION, (L"No persistent policy specified.")); } #endif cleanup: ClearPolicyStateBlock(&IpsecPolicyState); return (dwError); error: goto cleanup; } DWORD AddPolicyInformation( PIPSEC_POLICY_DATA pIpsecPolicyData, IN DWORD dwSource ) { DWORD dwError = 0; BOOL bHardError = FALSE; dwError = AddMMPolicyInformation( pIpsecPolicyData, dwSource ); dwError = AddQMPolicyInformation( pIpsecPolicyData, dwSource, &bHardError ); if (bHardError) { return (dwError); } else { return ERROR_SUCCESS; } } DWORD AddMMPolicyInformation( PIPSEC_POLICY_DATA pIpsecPolicyData, IN DWORD dwSource ) { DWORD dwError = 0; dwError = PAAddMMPolicies( &(pIpsecPolicyData->pIpsecISAKMPData), 1, dwSource ); dwError = PAAddMMAuthMethods( pIpsecPolicyData->ppIpsecNFAData, pIpsecPolicyData->dwNumNFACount, dwSource ); dwError = PAAddMMFilters( pIpsecPolicyData->pIpsecISAKMPData, pIpsecPolicyData->ppIpsecNFAData, pIpsecPolicyData->dwNumNFACount, dwSource ); BAIL_ON_WIN32_ERROR(dwError); error: return (dwError); } DWORD AddQMPolicyInformation( PIPSEC_POLICY_DATA pIpsecPolicyData, IN DWORD dwSource, BOOL * pbHardError ) { DWORD dwError = 0; BOOL bHardError = FALSE; dwError = PAAddQMPolicies( pIpsecPolicyData->ppIpsecNFAData, pIpsecPolicyData->dwNumNFACount, dwSource ); dwError = PAAddQMFilters( pIpsecPolicyData->ppIpsecNFAData, pIpsecPolicyData->dwNumNFACount, dwSource, &bHardError ); BAIL_ON_WIN32_ERROR(dwError); error: *pbHardError = bHardError; return (dwError); } DWORD OnPolicyChanged( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; // // Remove all the old policy that was plumbed. // TRACE(TRC_INFORMATION, ("Pastore deleting existing policy since policy assignment change detected or forced.")); dwError = DeletePolicyInformation( pIpsecPolicyState->pIpsecPolicyData ); ClearPolicyStateBlock( pIpsecPolicyState ); // Don't lose track of the fact that we've loaded Persistent policy. if (gbPersistentPolicyApplied) { SetSpdStateOnError( IPSEC_SOURCE_PERSISTENT, SPD_POLICY_APPLY, ERROR_SUCCESS, &pIpsecPolicyState->CurrentState ); } // // Calling the Initializer again. // dwError = StartStatePollingManager( pIpsecPolicyState ); return (dwError); } DWORD DeletePolicyInformation( PIPSEC_POLICY_DATA pIpsecPolicyData ) { DWORD dwError = 0; if (!pIpsecPolicyData) { dwError = ERROR_SUCCESS; return (dwError); } dwError = DeleteMMPolicyInformation(pIpsecPolicyData); dwError = DeleteQMPolicyInformation(pIpsecPolicyData); dwError = ERROR_SUCCESS; return (dwError); } DWORD DeleteMMPolicyInformation( PIPSEC_POLICY_DATA pIpsecPolicyData ) { DWORD dwError = 0; dwError = PADeleteMMFilters( pIpsecPolicyData->pIpsecISAKMPData, pIpsecPolicyData->ppIpsecNFAData, pIpsecPolicyData->dwNumNFACount ); dwError = PADeleteMMAuthMethods( pIpsecPolicyData->ppIpsecNFAData, pIpsecPolicyData->dwNumNFACount ); dwError = PADeleteMMPolicies( &(pIpsecPolicyData->pIpsecISAKMPData), 1 ); return (dwError); } DWORD DeleteQMPolicyInformation( PIPSEC_POLICY_DATA pIpsecPolicyData ) { DWORD dwError = 0; dwError = PADeleteQMFilters( pIpsecPolicyData->ppIpsecNFAData, pIpsecPolicyData->dwNumNFACount ); dwError = PADeleteQMPolicies( pIpsecPolicyData->ppIpsecNFAData, pIpsecPolicyData->dwNumNFACount ); return (dwError); } DWORD DeleteAllPolicyInformation( ) { DWORD dwError = 0; TRACE(TRC_INFORMATION, (L"Deleting all policy information")); dwError = DeleteAllMMPolicyInformation(); dwError = DeleteAllQMPolicyInformation(); dwError = ERROR_SUCCESS; return (dwError); } DWORD DeleteAllMMPolicyInformation( ) { DWORD dwError = 0; dwError = PADeleteAllMMFilters(); dwError = PADeleteAllMMAuthMethods(); dwError = PADeleteAllMMPolicies(); return (dwError); } DWORD DeleteAllQMPolicyInformation( ) { DWORD dwError = 0; dwError = PADeleteAllTxFilters(); dwError = PADeleteAllTnFilters(); dwError = PADeleteAllQMPolicies(); return (dwError); } VOID ClearPolicyStateBlock( PIPSEC_POLICY_STATE pIpsecPolicyState ) { if (pIpsecPolicyState->pIpsecPolicyObject) { FreeIpsecPolicyObject( pIpsecPolicyState->pIpsecPolicyObject ); pIpsecPolicyState->pIpsecPolicyObject = NULL; } if (pIpsecPolicyState->pIpsecPolicyData) { FreeIpsecPolicyData( pIpsecPolicyState->pIpsecPolicyData ); pIpsecPolicyState->pIpsecPolicyData = NULL; } if (pIpsecPolicyState->pszDirectoryPolicyDN) { FreeSPDStr(pIpsecPolicyState->pszDirectoryPolicyDN); pIpsecPolicyState->pszDirectoryPolicyDN = NULL; } pIpsecPolicyState->CurrentPollingInterval = gDefaultPollingInterval; pIpsecPolicyState->DefaultPollingInterval = gDefaultPollingInterval; pIpsecPolicyState->DSIncarnationNumber = 0; pIpsecPolicyState->RegIncarnationNumber = 0; pIpsecPolicyState->CurrentState = SPD_STATE_INITIAL; } DWORD OnPolicyPoll( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; switch (pIpsecPolicyState->CurrentState) { case SPD_STATE_DS_APPLY_SUCCESS: // Tell group policy to refresh machine policy. // Our GP extension will ping us with NEW_DS_POLICY_EVENT // or GPUPDATE_REFRESH_EVENT when it's finished. TRACE(TRC_INFORMATION, (L"Requesting group policy to notify policy agent to check for policy changes.")); RefreshPolicy(TRUE); break; case SPD_STATE_CACHE_APPLY_SUCCESS: dwError = ProcessCachePolicyPollState(pIpsecPolicyState); break; case SPD_STATE_LOCAL_APPLY_SUCCESS: dwError = ProcessLocalPolicyPollState(pIpsecPolicyState); break; case SPD_STATE_INITIAL: case SPD_STATE_PERSISTENT_APPLY_SUCCESS: // For these following states need to try to reload polcies from the start. // dwError = OnPolicyChanged(pIpsecPolicyState); break; case SPD_STATE_DS_APPLY_FAIL: // If DS apply failed, then still have loaded DS data so to reapply loaded data. // dwError = ApplyLoadedDirectoryPolicy(pIpsecPolicyState); // If error rollback. Ignoring rollback errors, because nothing can be done. // if (dwError) { TRACE(TRC_INFORMATION, ("Pastore rolling back policy application due to previous errors")); (VOID) DeletePolicyInformation( pIpsecPolicyState->pIpsecPolicyData ); } break; case SPD_STATE_LOCAL_APPLY_FAIL: // If apply failed, then still have loaded policy data so to reapply loaded data. // dwError = ApplyLoadedLocalPolicy(pIpsecPolicyState); // If error rollback. Ignoring rollback errors, because nothing can be done. // if (dwError) { TRACE(TRC_INFORMATION, ("Pastore rolling back policy application due to previous errors")); (VOID) DeletePolicyInformation( pIpsecPolicyState->pIpsecPolicyData ); } break; case SPD_STATE_LOCAL_LOAD_FAIL: dwError = PlumbLocalPolicy(pIpsecPolicyState); break; case SPD_STATE_DS_LOAD_FAIL: case SPD_STATE_CACHE_LOAD_FAIL: case SPD_STATE_CACHE_APPLY_FAIL: case SPD_STATE_CACHE_LOAD_SUCCESS: // if DS policy load failed so try to load *and* apply again. // In case of CACHE policy load/apply failue, little point in retrying again, // so directly try DS policy again. // dwError = PlumbDirectoryPolicy(pIpsecPolicyState); break; default: // Any other state is unexpected during polling // We should be in *APPLY_SUCCESS or *APPLY_FAIL or *LOAD_FAIL // SPD_STATE_DS_LOAD_SUCCESS, // SPD_STATE_LOCAL_LOAD_SUCCESS, // SPD_STATE_PERSISTENT_LOAD_SUCCESS // For the following errors we should have shutdown and not // be here. // SPD_STATE_PERSISTENT_LOAD_FAIL // SPD_STATE_PERSISTENT_APPLY_FAIL ASSERT(FALSE); break; } // // Set the new polling interval. // gCurrentPollingInterval = pIpsecPolicyState->CurrentPollingInterval; TRACE( TRC_INFORMATION, ("Set global polling interval to %d", gCurrentPollingInterval) ); if (InAcceptableState(pIpsecPolicyState->CurrentState)) { gdwRetryCount = 0; } else { gdwRetryCount++; } return (dwError); } DWORD ProcessDirectoryPolicyPollState( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; DWORD dwIncarnationNumber = 0; PIPSEC_POLICY_OBJECT pIpsecPolicyObject = NULL; PIPSEC_POLICY_DATA pIpsecPolicyData = NULL; DWORD dwStoreType = IPSEC_DIRECTORY_PROVIDER; DWORD dwSlientErrorCode = 0; if (pIpsecPolicyState->CurrentState != SPD_STATE_DS_APPLY_SUCCESS) { TRACE(TRC_INFORMATION, (L"Pastore not checking whether directory policy has been modified because not in DS apply success.")); return ERROR_SUCCESS; } // // The directory policy DN has to be the same, otherwise the // IPSec extension in Winlogon would have already notified // PA Store of the DS policy change. // TRACE(TRC_INFORMATION, (L"Pastore checking whether directory policy has been modified.")); dwError = GetDirectoryIncarnationNumber( pIpsecPolicyState->pszDirectoryPolicyDN, &dwIncarnationNumber ); if (dwError) { dwError = MigrateFromDSToCache(pIpsecPolicyState); BAIL_ON_WIN32_ERROR(dwError); return (ERROR_SUCCESS); } if (dwIncarnationNumber == pIpsecPolicyState->DSIncarnationNumber) { // // The policy has not changed at all. // AuditEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_POLLING_NO_CHANGES, NULL, TRUE, TRUE ); TRACE(TRC_INFORMATION, (L"Pastore did not detect any policy change.")); return (ERROR_SUCCESS); } // // The incarnation number is different, so there's a need to // update the policy. // TRACE(TRC_INFORMATION, (L"Pastore detected that policy has been modified. Performing policy update.")); dwError = LoadDirectoryPolicy( pIpsecPolicyState->pszDirectoryPolicyDN, &pIpsecPolicyObject ); if (dwError) { dwError = MigrateFromDSToCache(pIpsecPolicyState); BAIL_ON_WIN32_ERROR(dwError); return (ERROR_SUCCESS); } dwError = ProcessNFAs( pIpsecPolicyObject, dwStoreType, &dwSlientErrorCode, &pIpsecPolicyData ); if (dwError) { TRACE( TRC_ERROR, (L"Pastore failure when processing NFAs. Will migrate from directory to cache: %!winerr!", dwError) ); dwError = MigrateFromDSToCache(pIpsecPolicyState); BAIL_ON_WIN32_ERROR(dwError); if (pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyObject); } return (ERROR_SUCCESS); } dwError = UpdatePolicyInformation( pIpsecPolicyState->pIpsecPolicyData, pIpsecPolicyData, IPSEC_SOURCE_DOMAIN ); if (pIpsecPolicyState->pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyState->pIpsecPolicyObject); } if (pIpsecPolicyState->pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyState->pIpsecPolicyData); } // // Now delete the old cache and write the new one in. // DeleteRegistryCache(); CacheDirectorytoRegistry(pIpsecPolicyObject); pIpsecPolicyState->pIpsecPolicyObject = pIpsecPolicyObject; pIpsecPolicyState->pIpsecPolicyData = pIpsecPolicyData; pIpsecPolicyState->CurrentPollingInterval = pIpsecPolicyData->dwPollingInterval; pIpsecPolicyState->DSIncarnationNumber = dwIncarnationNumber; NotifyIpsecPolicyChange(); dwError = ERROR_SUCCESS; if (dwSlientErrorCode) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_SOME_NFA_APPLICATION, pIpsecPolicyData->pszIpsecName, dwSlientErrorCode, FALSE, TRUE ); TRACE( TRC_WARNING, ("Pastore failed to process one or more NFAs. Please compare active policy in SPD with policy in storage: %!winerr!", dwSlientErrorCode) ); } AuditEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_POLLING_APPLIED_CHANGES, NULL, TRUE, TRUE ); return (dwError); error: TRACE( TRC_ERROR, (L"Pastore failed when checking for policy change on poll: %!winerr!", dwError) ); if (pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyObject); } if (pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyData); } return (dwError); } DWORD GetDirectoryIncarnationNumber( LPWSTR pszIpsecPolicyDN, DWORD * pdwIncarnationNumber ) { DWORD dwError = 0; LPWSTR pszDefaultDirectory = NULL; HLDAP hLdapBindHandle = NULL; LPWSTR Attributes[] = {L"whenChanged", NULL}; LDAPMessage *res = NULL; LDAPMessage *e = NULL; WCHAR **strvalues = NULL; DWORD dwCount = 0; time_t t_WhenChanged = 0; *pdwIncarnationNumber = 0; // // Open the directory store. // dwError = ComputeDefaultDirectory( &pszDefaultDirectory ); BAIL_ON_WIN32_ERROR(dwError); dwError = OpenDirectoryServerHandle( pszDefaultDirectory, 389, &hLdapBindHandle ); BAIL_ON_WIN32_ERROR(dwError); dwError = LdapSearchST( hLdapBindHandle, pszIpsecPolicyDN, LDAP_SCOPE_BASE, L"(objectClass=*)", Attributes, 0, NULL, &res ); BAIL_ON_WIN32_ERROR(dwError); dwError = LdapFirstEntry( hLdapBindHandle, res, &e ); BAIL_ON_WIN32_ERROR(dwError); dwError = LdapGetValues( hLdapBindHandle, e, L"whenChanged", (WCHAR ***)&strvalues, (int *)&dwCount ); BAIL_ON_WIN32_ERROR(dwError); dwError = GeneralizedTimeToTime( LDAPOBJECT_STRING((PLDAPOBJECT)strvalues), &t_WhenChanged ); BAIL_ON_WIN32_ERROR(dwError); *pdwIncarnationNumber = TIME_T_TO_DWORD(t_WhenChanged); error: #ifdef TRACE_ON if (dwError) { TRACE(TRC_ERROR, ("Pastore failed to get directory policy change date/time: %!winerr!", dwError)); } #endif if (pszDefaultDirectory) { FreeSPDStr(pszDefaultDirectory); } if (hLdapBindHandle) { CloseDirectoryServerHandle(hLdapBindHandle); } if (res) { LdapMsgFree(res); } if (strvalues) { LdapValueFree(strvalues); } return (dwError); } DWORD MigrateFromDSToCache( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; LPWSTR pszCachePolicyDN = NULL; TRACE(TRC_INFORMATION, ("Migrating from directory to cache policy.")); dwError = GetCachePolicyDN( &pszCachePolicyDN ); BAIL_ON_WIN32_ERROR(dwError); if (pIpsecPolicyState->pszDirectoryPolicyDN) { FreeSPDStr(pIpsecPolicyState->pszDirectoryPolicyDN); pIpsecPolicyState->pszDirectoryPolicyDN = NULL; } pIpsecPolicyState->pszCachePolicyDN = pszCachePolicyDN; // // Keep pIpsecPolicyState->pIpsecPolicyData. // Keep pIpsecPolicyState->pIpsecPolicyObject. // Change the incarnation numbers. // pIpsecPolicyState->RegIncarnationNumber = pIpsecPolicyState->DSIncarnationNumber; pIpsecPolicyState->DSIncarnationNumber = 0; SetSpdStateOnError( IPSEC_SOURCE_CACHE, SPD_POLICY_APPLY, ERROR_SUCCESS, &pIpsecPolicyState->CurrentState ); // // Keep pIpsecPolicyState->CurrentPollingInterval. // Keep pIpsecPolicyState->DefaultPollingInterval. // gCurrentPollingInterval = pIpsecPolicyState->CurrentPollingInterval; TRACE( TRC_INFORMATION, ("Set global polling interval to %d", gCurrentPollingInterval) ); AuditEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_MIGRATE_DS_TO_CACHE, NULL, TRUE, TRUE ); TRACE(TRC_INFORMATION, (L"Pastore migrated from cache to directory policy.")); error: return (dwError); } DWORD ProcessCachePolicyPollState( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; LPWSTR pszDirectoryPolicyDN = NULL; DWORD dwIncarnationNumber = 0; LPWSTR pszCachePolicyDN = NULL; TRACE(TRC_INFORMATION, (L"Detecting if cache change time is different from directory change time.")); dwError = GetDirectoryPolicyDN( &pszDirectoryPolicyDN ); if (!dwError) { dwError = GetDirectoryIncarnationNumber( pszDirectoryPolicyDN, &dwIncarnationNumber ); if (!dwError) { dwError = CopyPolicyDSToFQRegString( pszDirectoryPolicyDN, &pszCachePolicyDN ); if (!dwError) { if (!_wcsicmp(pIpsecPolicyState->pszCachePolicyDN, pszCachePolicyDN)) { if (pIpsecPolicyState->RegIncarnationNumber == dwIncarnationNumber) { dwError = MigrateFromCacheToDS(pIpsecPolicyState); } else { dwError = UpdateFromCacheToDS(pIpsecPolicyState); } if (dwError) { dwError = OnPolicyChanged(pIpsecPolicyState); } } else { dwError = OnPolicyChanged(pIpsecPolicyState); } } } } if (pszDirectoryPolicyDN) { FreeSPDStr(pszDirectoryPolicyDN); } if (pszCachePolicyDN) { FreeSPDStr(pszCachePolicyDN); } return (ERROR_SUCCESS); } DWORD MigrateFromCacheToDS( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; LPWSTR pszDirectoryPolicyDN = NULL; dwError = GetDirectoryPolicyDN( &pszDirectoryPolicyDN ); BAIL_ON_WIN32_ERROR(dwError); if (pIpsecPolicyState->pszCachePolicyDN) { FreeSPDStr(pIpsecPolicyState->pszCachePolicyDN); pIpsecPolicyState->pszCachePolicyDN = NULL; } pIpsecPolicyState->pszDirectoryPolicyDN = pszDirectoryPolicyDN; // // Keep pIpsecPolicyState->pIpsecPolicyData. // Keep pIpsecPolicyState->pIpsecPolicyObject. // Change the incarnation numbers. // pIpsecPolicyState->DSIncarnationNumber = pIpsecPolicyState->RegIncarnationNumber; pIpsecPolicyState->RegIncarnationNumber = 0; SetSpdStateOnError( IPSEC_SOURCE_DOMAIN, SPD_POLICY_APPLY, ERROR_SUCCESS, &pIpsecPolicyState->CurrentState ); // // Keep pIpsecPolicyState->CurrentPollingInterval. // Keep pIpsecPolicyState->DefaultPollingInterval. // gCurrentPollingInterval = pIpsecPolicyState->CurrentPollingInterval; AuditEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_MIGRATE_CACHE_TO_DS, NULL, TRUE, TRUE ); error: return (dwError); } DWORD UpdateFromCacheToDS( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwError = 0; LPWSTR pszDirectoryPolicyDN = NULL; PIPSEC_POLICY_OBJECT pIpsecPolicyObject = NULL; PIPSEC_POLICY_DATA pIpsecPolicyData = NULL; DWORD dwStoreType = IPSEC_DIRECTORY_PROVIDER; DWORD dwSlientErrorCode = 0; TRACE(TRC_INFORMATION, (L"Detect difference between plumbed cache, and directory policy. Updating plumbed policy.")); dwError = GetDirectoryPolicyDN( &pszDirectoryPolicyDN ); BAIL_ON_WIN32_ERROR(dwError); dwError = LoadDirectoryPolicy( pszDirectoryPolicyDN, &pIpsecPolicyObject ); BAIL_ON_WIN32_ERROR(dwError); dwError = ProcessNFAs( pIpsecPolicyObject, dwStoreType, &dwSlientErrorCode, &pIpsecPolicyData ); BAIL_ON_WIN32_ERROR(dwError); dwError = UpdatePolicyInformation( pIpsecPolicyState->pIpsecPolicyData, pIpsecPolicyData, IPSEC_SOURCE_DOMAIN ); if (pIpsecPolicyState->pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyState->pIpsecPolicyObject); } if (pIpsecPolicyState->pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyState->pIpsecPolicyData); } if (pIpsecPolicyState->pszCachePolicyDN) { FreeSPDStr(pIpsecPolicyState->pszCachePolicyDN); } // // Now delete the old cache and write the new one in. // DeleteRegistryCache(); CacheDirectorytoRegistry(pIpsecPolicyObject); pIpsecPolicyState->pIpsecPolicyObject = pIpsecPolicyObject; pIpsecPolicyState->pIpsecPolicyData = pIpsecPolicyData; pIpsecPolicyState->pszDirectoryPolicyDN = pszDirectoryPolicyDN; // // Set the state to DS-DOWNLOADED. // SetSpdStateOnError( IPSEC_SOURCE_DOMAIN, SPD_POLICY_APPLY, ERROR_SUCCESS, &pIpsecPolicyState->CurrentState ); // // Compute the new polling interval. // pIpsecPolicyState->CurrentPollingInterval = pIpsecPolicyData->dwPollingInterval; pIpsecPolicyState->DSIncarnationNumber = pIpsecPolicyData->dwWhenChanged; pIpsecPolicyState->RegIncarnationNumber = 0; gCurrentPollingInterval = pIpsecPolicyState->CurrentPollingInterval; NotifyIpsecPolicyChange(); dwError = ERROR_SUCCESS; if (dwSlientErrorCode) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_SOME_NFA_APPLICATION, pIpsecPolicyData->pszIpsecName, dwSlientErrorCode, FALSE, TRUE ); TRACE( TRC_WARNING, ("Pastore failed to process one or more NFAs. Please compare active policy in SPD with policy in storage: %!winerr!", dwSlientErrorCode) ); } AuditEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_UPDATE_CACHE_TO_DS, NULL, TRUE, TRUE ); return (dwError); error: if (pszDirectoryPolicyDN) { FreeSPDStr(pszDirectoryPolicyDN); } if (pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyObject); } if (pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyData); } return (dwError); } DWORD ProcessLocalPolicyPollState( PIPSEC_POLICY_STATE pIpsecPolicyState ) { DWORD dwStatus = 0; LPWSTR pszDirectoryPolicyDN = NULL; DWORD dwDSIncarnationNumber = 0; DWORD dwError = 0; BOOL bChanged = FALSE; DWORD dwIncarnationNumber = 0; PIPSEC_POLICY_OBJECT pIpsecPolicyObject = NULL; PIPSEC_POLICY_DATA pIpsecPolicyData = NULL; DWORD dwStoreType = IPSEC_REGISTRY_PROVIDER; DWORD dwSlientErrorCode = 0; TRACE(TRC_INFORMATION, (L"Pastore checking whether local policy assignment has changed.")); dwStatus = GetDirectoryPolicyDN( &pszDirectoryPolicyDN ); if (!dwStatus) { dwStatus = GetDirectoryIncarnationNumber( pszDirectoryPolicyDN, &dwDSIncarnationNumber ); if (pszDirectoryPolicyDN) { FreeSPDStr(pszDirectoryPolicyDN); } if (!dwStatus) { dwStatus = OnPolicyChanged(pIpsecPolicyState); return (dwStatus); } } dwError = HasRegistryPolicyChanged( pIpsecPolicyState->pszRegistryPolicyDN, &bChanged ); BAIL_ON_WIN32_ERROR(dwError); if (bChanged) { dwError = OnPolicyChanged(pIpsecPolicyState); return (dwError); } if (pIpsecPolicyState->CurrentState == SPD_STATE_INITIAL) { return (ERROR_SUCCESS); } dwError = GetRegistryIncarnationNumber( pIpsecPolicyState->pszRegistryPolicyDN, &dwIncarnationNumber ); BAIL_ON_WIN32_ERROR(dwError); if (dwIncarnationNumber == pIpsecPolicyState->RegIncarnationNumber) { // // The policy has not changed at all. // AuditEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_POLLING_NO_CHANGES, NULL, TRUE, TRUE ); TRACE(TRC_INFORMATION, (L"Pastore did not detect any policy change.")); return (ERROR_SUCCESS); } TRACE(TRC_INFORMATION, (L"Pastore detected that policy has been modified. Performing policy update.")); dwError = LoadRegistryPolicy( pIpsecPolicyState->pszRegistryPolicyDN, &pIpsecPolicyObject, IPSEC_STORE_LOCAL ); BAIL_ON_WIN32_ERROR(dwError); dwError = ProcessNFAs( pIpsecPolicyObject, dwStoreType, &dwSlientErrorCode, &pIpsecPolicyData ); BAIL_ON_WIN32_ERROR(dwError); dwError = UpdatePolicyInformation( pIpsecPolicyState->pIpsecPolicyData, pIpsecPolicyData, IPSEC_SOURCE_LOCAL ); if (pIpsecPolicyState->pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyState->pIpsecPolicyObject); } if (pIpsecPolicyState->pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyState->pIpsecPolicyData); } pIpsecPolicyState->pIpsecPolicyObject = pIpsecPolicyObject; pIpsecPolicyState->pIpsecPolicyData = pIpsecPolicyData; pIpsecPolicyState->CurrentPollingInterval = pIpsecPolicyData->dwPollingInterval; pIpsecPolicyState->RegIncarnationNumber = dwIncarnationNumber; NotifyIpsecPolicyChange(); dwError = ERROR_SUCCESS; if (dwSlientErrorCode) { AuditIPSecPolicyErrorEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_FAILED_SOME_NFA_APPLICATION, pIpsecPolicyData->pszIpsecName, dwSlientErrorCode, FALSE, TRUE ); TRACE( TRC_WARNING, ("Pastore failed to process one or more NFAs. Please compare active policy in SPD with policy in storage: %!winerr!", dwSlientErrorCode ) ); } AuditEvent( SE_CATEGID_POLICY_CHANGE, SE_AUDITID_IPSEC_POLICY_CHANGED, PASTORE_POLLING_APPLIED_CHANGES, NULL, TRUE, TRUE ); return (dwError); error: TRACE( TRC_ERROR, (L"Pastore failed when checking for policy change on poll: %!winerr!", dwError) ); if (pIpsecPolicyObject) { FreeIpsecPolicyObject(pIpsecPolicyObject); } if (pIpsecPolicyData) { FreeIpsecPolicyData(pIpsecPolicyData); } return (dwError); } DWORD HasRegistryPolicyChanged( LPWSTR pszCurrentPolicyDN, PBOOL pbChanged ) { DWORD dwError = 0; HKEY hRegKey = NULL; LPWSTR pszIpsecPolicyName = NULL; DWORD dwSize = 0; BOOL bChanged = FALSE; dwError = RegOpenKeyExW( HKEY_LOCAL_MACHINE, gpszIpsecLocalPolicyKey, 0, KEY_ALL_ACCESS, &hRegKey ); BAIL_ON_WIN32_ERROR(dwError); dwError = RegstoreQueryValue( hRegKey, L"ActivePolicy", REG_SZ, (LPBYTE *)&pszIpsecPolicyName, &dwSize ); // // Must not bail from here, as there can be no // active local policy. // if (pszIpsecPolicyName && *pszIpsecPolicyName) { if (!pszCurrentPolicyDN || !*pszCurrentPolicyDN) { bChanged = TRUE; } else { if (!_wcsicmp(pszIpsecPolicyName, pszCurrentPolicyDN)) { bChanged = FALSE; } else { bChanged = TRUE; } } } else { if (!pszCurrentPolicyDN || !*pszCurrentPolicyDN) { bChanged = FALSE; } else { bChanged = TRUE; } } *pbChanged = bChanged; dwError = ERROR_SUCCESS; cleanup: if (hRegKey) { CloseHandle(hRegKey); } if (pszIpsecPolicyName) { FreeSPDStr(pszIpsecPolicyName); } return (dwError); error: TRACE(TRC_ERROR, ("Pastore failed when trying to detect if local policy assigment has changed: %!winerr!", dwError)); *pbChanged = FALSE; goto cleanup; } DWORD GetRegistryIncarnationNumber( LPWSTR pszIpsecPolicyDN, DWORD * pdwIncarnationNumber ) { DWORD dwError = 0; HKEY hRegKey = NULL; DWORD dwType = REG_DWORD; DWORD dwWhenChanged = 0; DWORD dwSize = sizeof(DWORD); *pdwIncarnationNumber = 0; dwError = RegOpenKeyExW( HKEY_LOCAL_MACHINE, pszIpsecPolicyDN, 0, KEY_ALL_ACCESS, &hRegKey ); BAIL_ON_WIN32_ERROR(dwError); dwError = RegQueryValueExW( hRegKey, L"whenChanged", NULL, &dwType, (LPBYTE)&dwWhenChanged, &dwSize ); BAIL_ON_WIN32_ERROR(dwError); *pdwIncarnationNumber = dwWhenChanged; error: #ifdef TRACE_ON if (dwError) { TRACE(TRC_ERROR, ("Pastore failed to get registry change date/time: %!winerr!", dwError)); } #endif if (hRegKey) { CloseHandle(hRegKey); } return(dwError); } DWORD UpdatePolicyInformation( PIPSEC_POLICY_DATA pOldIpsecPolicyData, PIPSEC_POLICY_DATA pNewIpsecPolicyData, IN DWORD dwSource ) { DWORD dwError = 0; PIPSEC_ISAKMP_DATA pOldIpsecISAKMPData = NULL; PIPSEC_NFA_DATA * ppOldIpsecNFAData = NULL; DWORD dwNumOldNFACount = 0; PIPSEC_ISAKMP_DATA pNewIpsecISAKMPData = NULL; PIPSEC_NFA_DATA * ppNewIpsecNFAData = NULL; DWORD dwNumNewNFACount = 0; pOldIpsecISAKMPData = pOldIpsecPolicyData->pIpsecISAKMPData; ppOldIpsecNFAData = pOldIpsecPolicyData->ppIpsecNFAData; dwNumOldNFACount = pOldIpsecPolicyData->dwNumNFACount; pNewIpsecISAKMPData = pNewIpsecPolicyData->pIpsecISAKMPData; ppNewIpsecNFAData = pNewIpsecPolicyData->ppIpsecNFAData; dwNumNewNFACount = pNewIpsecPolicyData->dwNumNFACount; TRACE( TRC_INFORMATION, (L"Pastore performing policy update") ); dwError = PADeleteObseleteISAKMPData( &pOldIpsecISAKMPData, 1, ppOldIpsecNFAData, dwNumOldNFACount, &pNewIpsecISAKMPData, 1 ); dwError = PAUpdateISAKMPData( &pNewIpsecISAKMPData, 1, ppOldIpsecNFAData, dwNumOldNFACount, &pOldIpsecISAKMPData, 1, dwSource ); dwError = PADeleteObseleteNFAData( pNewIpsecISAKMPData, ppOldIpsecNFAData, dwNumOldNFACount, ppNewIpsecNFAData, dwNumNewNFACount ); dwError = PAUpdateNFAData( pNewIpsecISAKMPData, ppNewIpsecNFAData, dwNumNewNFACount, ppOldIpsecNFAData, dwNumOldNFACount, dwSource ); return (dwError); } DWORD LoadDefaultISAKMPInformation( LPWSTR pszDefaultISAKMPDN ) { DWORD dwError = 0; gbLoadedISAKMPDefaults = TRUE; return (dwError); } VOID UnLoadDefaultISAKMPInformation( LPWSTR pszDefaultISAKMPDN ) { return; } BOOL IsDirectoryPolicySpecified( ) { DWORD dwError = ERROR_SUCCESS; LPWSTR pszDirectoryPolicyDN = NULL; dwError = GetDirectoryPolicyDN( &pszDirectoryPolicyDN ); if (pszDirectoryPolicyDN) { FreeSPDStr(pszDirectoryPolicyDN); } if (dwError) { return FALSE; } else { return TRUE; } } BOOL IsLocalPolicySpecified( ) { DWORD dwError = ERROR_SUCCESS; LPWSTR pszRegistryPolicyDN = NULL; dwError = GetRegistryPolicyDN( &pszRegistryPolicyDN, IPSEC_STORE_LOCAL ); if (pszRegistryPolicyDN) { FreeSPDStr(pszRegistryPolicyDN); } if (dwError) { return FALSE; } else { return TRUE; } } BOOL IsPersistentPolicySpecified( ) { DWORD dwError = ERROR_SUCCESS; LPWSTR pszRegistryPolicyDN = NULL; dwError = GetRegistryPolicyDN( &pszRegistryPolicyDN, IPSEC_STORE_PERSISTENT ); if (pszRegistryPolicyDN) { FreeSPDStr(pszRegistryPolicyDN); } if (dwError) { return FALSE; } else { return TRUE; } }