/*++ Copyright (c) 1999 Microsoft Corporation Module Name: qm-policy.c Abstract: Author: Environment: User Mode Revision History: --*/ #include "precomp.h" #ifdef TRACE_ON #include "qm-policy.tmh" #endif DWORD AddQMPolicyInternal( LPWSTR pServerName, DWORD dwVersion, DWORD dwFlags, DWORD dwSource, PIPSEC_QM_POLICY pQMPolicy, LPVOID pvReserved ) /*++ Routine Description: This function adds a quick mode policy to the SPD. Arguments: pServerName - Server on which the quick mode policy is to be added. pQMPolicy - Quick mode policy to be added. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; PINIQMPOLICY pIniQMPolicy = NULL; // // Validate the quick mode policy. // dwError = ValidateQMPolicy( pQMPolicy ); BAIL_ON_WIN32_ERROR(dwError); ENTER_SPD_SECTION(); dwError = ValidateSecurity( SPD_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL ); BAIL_ON_LOCK_ERROR(dwError); pIniQMPolicy = FindQMPolicy( gpIniQMPolicy, pQMPolicy->pszPolicyName ); if (pIniQMPolicy) { dwError = ERROR_IPSEC_QM_POLICY_EXISTS; BAIL_ON_LOCK_ERROR(dwError); } pIniQMPolicy = FindQMPolicyByGuid( gpIniQMPolicy, pQMPolicy->gPolicyID ); if (pIniQMPolicy) { dwError = ERROR_IPSEC_QM_POLICY_EXISTS; BAIL_ON_LOCK_ERROR(dwError); } dwError = CreateIniQMPolicy( pQMPolicy, &pIniQMPolicy ); if (dwError != WARNING_IPSEC_QM_POLICY_PRUNED) { BAIL_ON_LOCK_ERROR(dwError); } pIniQMPolicy->dwSource = dwSource; pIniQMPolicy->pNext = gpIniQMPolicy; gpIniQMPolicy = pIniQMPolicy; if ((pIniQMPolicy->dwFlags) & IPSEC_QM_POLICY_DEFAULT_POLICY) { gpIniDefaultQMPolicy = pIniQMPolicy; TRACE( TRC_INFORMATION, (L"Set default QM policy to \"%ls\" (%!guid!)", pQMPolicy->pszPolicyName, &pQMPolicy->gPolicyID) ); } LEAVE_SPD_SECTION(); TRACE( TRC_INFORMATION, (L"Added QM policy \"%ls\"(%!guid!)", pQMPolicy->pszPolicyName, &pQMPolicy->gPolicyID) ); return (dwError); lock: LEAVE_SPD_SECTION(); error: #ifdef TRACE_ON if (pQMPolicy) { TRACE( TRC_ERROR, (L"Failed to add QM policy \"%ls\"(%!guid!): %!winerr!", pQMPolicy->pszPolicyName, &pQMPolicy->gPolicyID, dwError) ); } else { TRACE( TRC_ERROR, (L"Failed to add MM policy. Policy details unavailable since pQMPolicy is null: %!winerr!", dwError) ); } #endif return (dwError); } DWORD AddQMPolicy( LPWSTR pServerName, DWORD dwVersion, DWORD dwFlags, PIPSEC_QM_POLICY pQMPolicy, LPVOID pvReserved ) { return AddQMPolicyInternal( pServerName, dwVersion, dwFlags, IPSEC_SOURCE_WINIPSEC, pQMPolicy, pvReserved); } DWORD ValidateQMPolicy( PIPSEC_QM_POLICY pQMPolicy ) { DWORD dwError = 0; if (!pQMPolicy) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } if (!(pQMPolicy->pszPolicyName) || !(*(pQMPolicy->pszPolicyName))) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } dwError = ValidateQMOffers( pQMPolicy->dwOfferCount, pQMPolicy->pOffers ); BAIL_ON_WIN32_ERROR(dwError); error: #ifdef TRACE_ON if (dwError) { TRACE(TRC_ERROR, ("Failed QM policy validation: %!winerr!", dwError)); } #endif return (dwError); } DWORD ValidateQMOffers( DWORD dwOfferCount, PIPSEC_QM_OFFER pOffers ) { DWORD dwError = 0; if (!dwOfferCount || !pOffers || (dwOfferCount > IPSEC_MAX_QM_OFFERS)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } error: #ifdef TRACE_ON if (dwError) { TRACE(TRC_ERROR, ("Failed QM offers validation: %!winerr!", dwError)); } #endif return (dwError); } DWORD ValidateQMOffer( PIPSEC_QM_OFFER pOffer, BOOL *pbInitGroup, LPDWORD pdwPFSGroup ) { DWORD dwError = 0; DWORD j = 0; BOOL bAH = FALSE; BOOL bESP = FALSE; DWORD dwPFSGroup = *pdwPFSGroup; BOOL bInitGroup = *pbInitGroup; if (!bInitGroup) { if (pOffer->bPFSRequired) { if ((pOffer->dwPFSGroup != PFS_GROUP_1) && (pOffer->dwPFSGroup != PFS_GROUP_2) && (pOffer->dwPFSGroup != PFS_GROUP_2048) && (pOffer->dwPFSGroup != PFS_GROUP_MM)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } dwPFSGroup=pOffer->dwPFSGroup; } else { if (pOffer->dwPFSGroup != PFS_GROUP_NONE) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } dwPFSGroup=PFS_GROUP_NONE; } bInitGroup = TRUE; } if (dwPFSGroup) { if ((!pOffer->bPFSRequired) || (pOffer->dwPFSGroup != dwPFSGroup)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } } else { if ((pOffer->bPFSRequired) || (pOffer->dwPFSGroup != PFS_GROUP_NONE)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } } if (!(pOffer->dwNumAlgos) || (pOffer->dwNumAlgos > QM_MAX_ALGOS)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } bAH = FALSE; bESP = FALSE; for (j = 0; j < (pOffer->dwNumAlgos); j++) { switch (pOffer->Algos[j].Operation) { case AUTHENTICATION: if (bAH) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } if ((pOffer->Algos[j].uAlgoIdentifier == AUTH_ALGO_NONE) || (pOffer->Algos[j].uAlgoIdentifier >= AUTH_ALGO_MAX)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } if (pOffer->Algos[j].uSecAlgoIdentifier != HMAC_AUTH_ALGO_NONE) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } bAH = TRUE; break; case ENCRYPTION: if (bESP) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } if (pOffer->Algos[j].uAlgoIdentifier >= CONF_ALGO_MAX) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } if (pOffer->Algos[j].uSecAlgoIdentifier >= HMAC_AUTH_ALGO_MAX) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } if (pOffer->Algos[j].uAlgoIdentifier == CONF_ALGO_NONE) { if (pOffer->Algos[j].uSecAlgoIdentifier == HMAC_AUTH_ALGO_NONE) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } } bESP = TRUE; break; case NONE: case COMPRESSION: default: dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); break; } } *pdwPFSGroup = dwPFSGroup; *pbInitGroup = bInitGroup; error: #ifdef TRACE_ON if (dwError) { TRACE(TRC_ERROR, ("Failed a QM offer validation: %!winerr!", dwError)); } #endif return (dwError); } DWORD CreateIniQMPolicy( PIPSEC_QM_POLICY pQMPolicy, PINIQMPOLICY * ppIniQMPolicy ) { DWORD dwError = 0; PINIQMPOLICY pIniQMPolicy = NULL; dwError = AllocateSPDMemory( sizeof(INIQMPOLICY), &pIniQMPolicy ); BAIL_ON_WIN32_ERROR(dwError); memcpy( &(pIniQMPolicy->gPolicyID), &(pQMPolicy->gPolicyID), sizeof(GUID) ); dwError = AllocateSPDString( pQMPolicy->pszPolicyName, &(pIniQMPolicy->pszPolicyName) ); BAIL_ON_WIN32_ERROR(dwError); pIniQMPolicy->cRef = 0; pIniQMPolicy->dwSource = 0; pIniQMPolicy->dwFlags = pQMPolicy->dwFlags; pIniQMPolicy->dwReserved = pQMPolicy->dwReserved; pIniQMPolicy->pNext = NULL; dwError = CreateIniQMOffers( pQMPolicy->dwOfferCount, pQMPolicy->pOffers, &(pIniQMPolicy->dwOfferCount), &(pIniQMPolicy->pOffers) ); if (dwError != WARNING_IPSEC_QM_POLICY_PRUNED) { BAIL_ON_WIN32_ERROR(dwError); } *ppIniQMPolicy = pIniQMPolicy; return (dwError); error: TRACE(TRC_ERROR, ("Failed to create QM Policy link node: %!winerr!", dwError)); if (pIniQMPolicy) { FreeIniQMPolicy( pIniQMPolicy ); } *ppIniQMPolicy = NULL; return (dwError); } DWORD CreateIniQMOffers( DWORD dwInOfferCount, PIPSEC_QM_OFFER pInOffers, PDWORD pdwOfferCount, PIPSEC_QM_OFFER * ppOffers ) { DWORD dwError = 0; PIPSEC_QM_OFFER pOffers = NULL; PIPSEC_QM_OFFER pTemp = NULL; PIPSEC_QM_OFFER pInTempOffer = NULL; DWORD i = 0; DWORD j = 0; BOOL bGroupInit = FALSE; DWORD dwPFSGroup = PFS_GROUP_NONE; DWORD dwOfferCount = 0; DWORD dwCurIndex = 0; for (i = 0; i < dwInOfferCount; i++) { dwError = ValidateQMOffer(&pInOffers[i], &bGroupInit, &dwPFSGroup); if (dwError == ERROR_SUCCESS) { dwOfferCount++; } } if (dwOfferCount == 0) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } // // Offer count and the offers themselves have already been validated. // dwError = AllocateSPDMemory( sizeof(IPSEC_QM_OFFER) * dwOfferCount, &(pOffers) ); BAIL_ON_WIN32_ERROR(dwError); for (i = 0; i < dwInOfferCount; i++) { pTemp = &pOffers[dwCurIndex]; pInTempOffer = &pInOffers[i]; dwError = ValidateQMOffer(pInTempOffer, &bGroupInit, &dwPFSGroup); if (dwError) { continue; } memcpy( &(pTemp->Lifetime), &(pInTempOffer->Lifetime), sizeof(KEY_LIFETIME) ); pTemp->dwFlags = pInTempOffer->dwFlags; pTemp->bPFSRequired = pInTempOffer->bPFSRequired; pTemp->dwPFSGroup = pInTempOffer->dwPFSGroup; pTemp->dwNumAlgos = pInTempOffer->dwNumAlgos; for (j = 0; j < (pInTempOffer->dwNumAlgos); j++) { memcpy( &(pTemp->Algos[j]), &(pInTempOffer->Algos[j]), sizeof(IPSEC_QM_ALGO) ); } pTemp->dwReserved = pInTempOffer->dwReserved; dwCurIndex++; } *pdwOfferCount = dwOfferCount; *ppOffers = pOffers; if (dwOfferCount != dwInOfferCount) { return WARNING_IPSEC_QM_POLICY_PRUNED; } return (ERROR_SUCCESS); error: TRACE(TRC_ERROR, ("Failed to create QM offers node: %!winerr!", dwError)); if (pOffers) { FreeIniQMOffers( i, pOffers ); } *pdwOfferCount = 0; *ppOffers = NULL; return (dwError); } VOID FreeIniQMPolicy( PINIQMPOLICY pIniQMPolicy ) { if (pIniQMPolicy) { if (pIniQMPolicy->pszPolicyName) { FreeSPDString(pIniQMPolicy->pszPolicyName); } FreeIniQMOffers( pIniQMPolicy->dwOfferCount, pIniQMPolicy->pOffers ); FreeSPDMemory(pIniQMPolicy); } } VOID FreeIniQMOffers( DWORD dwOfferCount, PIPSEC_QM_OFFER pOffers ) { if (pOffers) { FreeSPDMemory(pOffers); } } PINIQMPOLICY FindQMPolicy( PINIQMPOLICY pIniQMPolicyList, LPWSTR pszPolicyName ) { DWORD dwError = 0; PINIQMPOLICY pTemp = NULL; pTemp = pIniQMPolicyList; while (pTemp) { if (!_wcsicmp(pTemp->pszPolicyName, pszPolicyName)) { return (pTemp); } pTemp = pTemp->pNext; } return (NULL); } DWORD DeleteQMPolicy( LPWSTR pServerName, DWORD dwVersion, LPWSTR pszPolicyName, LPVOID pvReserved ) /*++ Routine Description: This function deletes a quick mode policy from the SPD. Arguments: pServerName - Server on which the quick mode policy is to be deleted. pszPolicyName - Quick mode policy to be deleted. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; PINIQMPOLICY pIniQMPolicy = NULL; GUID gPolicyID; if (!pszPolicyName || !*pszPolicyName) { return (ERROR_INVALID_PARAMETER); } ENTER_SPD_SECTION(); dwError = ValidateSecurity( SPD_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL ); BAIL_ON_LOCK_ERROR(dwError); pIniQMPolicy = FindQMPolicy( gpIniQMPolicy, pszPolicyName ); if (!pIniQMPolicy) { dwError = ERROR_IPSEC_QM_POLICY_NOT_FOUND; BAIL_ON_LOCK_ERROR(dwError); } if (pIniQMPolicy->cRef) { dwError = ERROR_IPSEC_QM_POLICY_IN_USE; memcpy(&gPolicyID, &pIniQMPolicy->gPolicyID, sizeof(GUID)); BAIL_ON_LOCK_ERROR(dwError); } memcpy(&gPolicyID, &pIniQMPolicy->gPolicyID, sizeof(GUID)); dwError = DeleteIniQMPolicy( pIniQMPolicy ); BAIL_ON_LOCK_ERROR(dwError); LEAVE_SPD_SECTION(); if (gbIKENotify) { (VOID) IKENotifyPolicyChange( &(gPolicyID), POLICY_GUID_QM ); } TRACE( TRC_INFORMATION, ("Deleted QM Policy \"%ls\"(%!guid!)", pszPolicyName, &gPolicyID) ); return (dwError); lock: #ifdef TRACE_ON if (pIniQMPolicy) { TRACE( TRC_ERROR, (L"Failed to delete QM policy \"%ls\"(%!guid!): %!winerr!", pIniQMPolicy->pszPolicyName, &pIniQMPolicy->gPolicyID, dwError) ); } else { TRACE( TRC_ERROR, (L"Failed to delete QM policy \"%ls\": %!winerr!", pszPolicyName, dwError) ); } #endif LEAVE_SPD_SECTION(); if ((dwError == ERROR_IPSEC_QM_POLICY_IN_USE) && gbIKENotify) { (VOID) IKENotifyPolicyChange( &(gPolicyID), POLICY_GUID_QM ); } return (dwError); } DWORD EnumQMPolicies( LPWSTR pServerName, DWORD dwVersion, PIPSEC_QM_POLICY pQMTemplatePolicy, DWORD dwFlags, DWORD dwPreferredNumEntries, PIPSEC_QM_POLICY * ppQMPolicies, LPDWORD pdwNumPolicies, LPDWORD pdwResumeHandle, LPVOID pvReserved ) /*++ Routine Description: This function enumerates quick mode policies from the SPD. Arguments: pServerName - Server on which the quick mode policies are to be enumerated. ppQMPolicies - Enumerated quick mode policies returned to the caller. dwPreferredNumEntries - Preferred number of enumeration entries. pdwNumPolicies - Number of quick mode policies actually enumerated. pdwResumeHandle - Handle to the location in the quick mode policy list from which to resume enumeration. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; DWORD dwResumeHandle = 0; DWORD dwNumToEnum = 0; PINIQMPOLICY pIniQMPolicy = NULL; DWORD i = 0; PINIQMPOLICY pTemp = NULL; DWORD dwNumPolicies = 0; PIPSEC_QM_POLICY pQMPolicies = NULL; PIPSEC_QM_POLICY pQMPolicy = NULL; dwResumeHandle = *pdwResumeHandle; if (!dwPreferredNumEntries || (dwPreferredNumEntries > MAX_QMPOLICY_ENUM_COUNT)) { dwNumToEnum = MAX_QMPOLICY_ENUM_COUNT; } else { dwNumToEnum = dwPreferredNumEntries; } ENTER_SPD_SECTION(); dwError = ValidateSecurity( SPD_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL ); BAIL_ON_LOCK_ERROR(dwError); pIniQMPolicy = gpIniQMPolicy; for (i = 0; (i < dwResumeHandle) && (pIniQMPolicy != NULL); i++) { pIniQMPolicy = pIniQMPolicy->pNext; } if (!pIniQMPolicy) { dwError = ERROR_NO_DATA; BAIL_ON_LOCK_ERROR(dwError); } pTemp = pIniQMPolicy; while (pTemp && (dwNumPolicies < dwNumToEnum)) { dwNumPolicies++; pTemp = pTemp->pNext; } dwError = SPDApiBufferAllocate( sizeof(IPSEC_QM_POLICY)*dwNumPolicies, &pQMPolicies ); BAIL_ON_LOCK_ERROR(dwError); pTemp = pIniQMPolicy; pQMPolicy = pQMPolicies; for (i = 0; i < dwNumPolicies; i++) { dwError = CopyQMPolicy( dwFlags, pTemp, pQMPolicy ); BAIL_ON_LOCK_ERROR(dwError); pTemp = pTemp->pNext; pQMPolicy++; } *ppQMPolicies = pQMPolicies; *pdwResumeHandle = dwResumeHandle + dwNumPolicies; *pdwNumPolicies = dwNumPolicies; LEAVE_SPD_SECTION(); return (dwError); lock: LEAVE_SPD_SECTION(); if (pQMPolicies) { FreeQMPolicies( i, pQMPolicies ); } *ppQMPolicies = NULL; *pdwResumeHandle = dwResumeHandle; *pdwNumPolicies = 0; return (dwError); } DWORD SetQMPolicy( LPWSTR pServerName, DWORD dwVersion, LPWSTR pszPolicyName, PIPSEC_QM_POLICY pQMPolicy, LPVOID pvReserved ) /*++ Routine Description: This function updates a quick mode policy in the SPD. Arguments: pServerName - Server on which the quick mode policy is to be updated. pszPolicyName - Name of the quick mode policy to be updated. pQMPolicy - New quick mode policy which will replace the existing policy. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; PINIQMPOLICY pIniQMPolicy = NULL; DWORD dwStatus = 0; if (!pszPolicyName || !*pszPolicyName) { return (ERROR_INVALID_PARAMETER); } // // Validate quick mode policy. // dwError = ValidateQMPolicy( pQMPolicy ); BAIL_ON_WIN32_ERROR(dwError); ENTER_SPD_SECTION(); dwError = ValidateSecurity( SPD_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL ); BAIL_ON_LOCK_ERROR(dwError); pIniQMPolicy = FindQMPolicy( gpIniQMPolicy, pszPolicyName ); if (!pIniQMPolicy) { dwError = ERROR_IPSEC_QM_POLICY_NOT_FOUND; BAIL_ON_LOCK_ERROR(dwError); } if (memcmp( &(pIniQMPolicy->gPolicyID), &(pQMPolicy->gPolicyID), sizeof(GUID))) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_LOCK_ERROR(dwError); } dwError = SetIniQMPolicy( pIniQMPolicy, pQMPolicy ); if (dwError != WARNING_IPSEC_QM_POLICY_PRUNED) { BAIL_ON_LOCK_ERROR(dwError); } else { dwStatus = dwError; } LEAVE_SPD_SECTION(); (VOID) IKENotifyPolicyChange( &(pQMPolicy->gPolicyID), POLICY_GUID_QM ); TRACE( TRC_INFORMATION, (L"Changed QM Policy \"%ls\" (%!guid!)", pQMPolicy->pszPolicyName, &pQMPolicy->gPolicyID) ); return (dwStatus); lock: LEAVE_SPD_SECTION(); error: #ifdef TRACE_ON if (pIniQMPolicy) { TRACE( TRC_ERROR, (L"Failed to change QM policy \"%ls\"(%!guid!): %!winerr!", pIniQMPolicy->pszPolicyName, &pIniQMPolicy->gPolicyID, dwError) ); } else { TRACE( TRC_ERROR, (L"Failed to change QM policy \"%ls\": %!winerr!", pszPolicyName, dwError) ); } #endif return (dwError); } DWORD GetQMPolicy( LPWSTR pServerName, DWORD dwVersion, LPWSTR pszPolicyName, DWORD dwFlags, PIPSEC_QM_POLICY * ppQMPolicy, LPVOID pvReserved ) /*++ Routine Description: This function gets a quick mode policy from the SPD. Arguments: pServerName - Server from which to get the quick mode policy. pszPolicyName - Name of the quick mode policy to get. ppQMPolicy - Quick mode policy found returned to the caller. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; PINIQMPOLICY pIniQMPolicy = NULL; PIPSEC_QM_POLICY pQMPolicy = NULL; if (!pszPolicyName || !*pszPolicyName) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_WIN32_ERROR(dwError); } ENTER_SPD_SECTION(); dwError = ValidateSecurity( SPD_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL ); BAIL_ON_LOCK_ERROR(dwError); pIniQMPolicy = FindQMPolicy( gpIniQMPolicy, pszPolicyName ); if (!pIniQMPolicy) { dwError = ERROR_IPSEC_QM_POLICY_NOT_FOUND; BAIL_ON_LOCK_ERROR(dwError); } dwError = GetIniQMPolicy( dwFlags, pIniQMPolicy, &pQMPolicy ); BAIL_ON_LOCK_ERROR(dwError); *ppQMPolicy = pQMPolicy; LEAVE_SPD_SECTION(); return (dwError); lock: LEAVE_SPD_SECTION(); error: *ppQMPolicy = NULL; return (dwError); } DWORD SetIniQMPolicy( PINIQMPOLICY pIniQMPolicy, PIPSEC_QM_POLICY pQMPolicy ) { DWORD dwError = 0; DWORD dwOfferCount = 0; PIPSEC_QM_OFFER pOffers = NULL; dwError = CreateIniQMOffers( pQMPolicy->dwOfferCount, pQMPolicy->pOffers, &dwOfferCount, &pOffers ); if (dwError != WARNING_IPSEC_QM_POLICY_PRUNED) { BAIL_ON_WIN32_ERROR(dwError); } FreeIniQMOffers( pIniQMPolicy->dwOfferCount, pIniQMPolicy->pOffers ); if ((pIniQMPolicy->dwFlags) & IPSEC_QM_POLICY_DEFAULT_POLICY) { gpIniDefaultQMPolicy = NULL; TRACE( TRC_INFORMATION, (L"Cleared default QM policy \"%ls\" (%!guid!)", pIniQMPolicy->pszPolicyName, &pIniQMPolicy->gPolicyID) ); } pIniQMPolicy->dwFlags = pQMPolicy->dwFlags; pIniQMPolicy->dwReserved = pQMPolicy->dwReserved; pIniQMPolicy->dwOfferCount = dwOfferCount; pIniQMPolicy->pOffers = pOffers; if ((pIniQMPolicy->dwFlags) & IPSEC_QM_POLICY_DEFAULT_POLICY) { gpIniDefaultQMPolicy = pIniQMPolicy; TRACE( TRC_INFORMATION, (L"Set default QM policy to \"%ls\" (%!guid!)", pIniQMPolicy->pszPolicyName, &pIniQMPolicy->gPolicyID) ); } error: return (dwError); } DWORD GetIniQMPolicy( DWORD dwFlags, PINIQMPOLICY pIniQMPolicy, PIPSEC_QM_POLICY * ppQMPolicy ) { DWORD dwError = 0; PIPSEC_QM_POLICY pQMPolicy = NULL; dwError = SPDApiBufferAllocate( sizeof(IPSEC_QM_POLICY), &pQMPolicy ); BAIL_ON_WIN32_ERROR(dwError); dwError = CopyQMPolicy( dwFlags, pIniQMPolicy, pQMPolicy ); BAIL_ON_WIN32_ERROR(dwError); *ppQMPolicy = pQMPolicy; return (dwError); error: if (pQMPolicy) { SPDApiBufferFree(pQMPolicy); } *ppQMPolicy = NULL; return (dwError); } DWORD CopyQMPolicy( DWORD dwFlags, PINIQMPOLICY pIniQMPolicy, PIPSEC_QM_POLICY pQMPolicy ) { DWORD dwError = 0; memcpy( &(pQMPolicy->gPolicyID), &(pIniQMPolicy->gPolicyID), sizeof(GUID) ); dwError = SPDApiBufferAllocate( wcslen(pIniQMPolicy->pszPolicyName)*sizeof(WCHAR) + sizeof(WCHAR), &(pQMPolicy->pszPolicyName) ); BAIL_ON_WIN32_ERROR(dwError); wcscpy(pQMPolicy->pszPolicyName, pIniQMPolicy->pszPolicyName); pQMPolicy->dwFlags = pIniQMPolicy->dwFlags; pQMPolicy->dwReserved = pIniQMPolicy->dwReserved; if (dwFlags & RETURN_NON_AH_OFFERS) { dwError = CreateNonAHQMOffers( pIniQMPolicy->dwOfferCount, pIniQMPolicy->pOffers, &(pQMPolicy->dwOfferCount), &(pQMPolicy->pOffers) ); } else { dwError = CreateQMOffers( pIniQMPolicy->dwOfferCount, pIniQMPolicy->pOffers, &(pQMPolicy->dwOfferCount), &(pQMPolicy->pOffers) ); } BAIL_ON_WIN32_ERROR(dwError); return (dwError); error: if (pQMPolicy->pszPolicyName) { SPDApiBufferFree(pQMPolicy->pszPolicyName); } return (dwError); } DWORD CreateQMOffers( DWORD dwInOfferCount, PIPSEC_QM_OFFER pInOffers, PDWORD pdwOfferCount, PIPSEC_QM_OFFER * ppOffers ) { DWORD dwError = 0; PIPSEC_QM_OFFER pOffers = NULL; PIPSEC_QM_OFFER pTemp = NULL; PIPSEC_QM_OFFER pInTempOffer = NULL; DWORD i = 0; DWORD j = 0; DWORD k = 0; // // Offer count and the offers themselves have already been validated. // dwError = SPDApiBufferAllocate( sizeof(IPSEC_QM_OFFER) * dwInOfferCount, &(pOffers) ); BAIL_ON_WIN32_ERROR(dwError); pTemp = pOffers; pInTempOffer = pInOffers; for (i = 0; i < dwInOfferCount; i++) { memcpy( &(pTemp->Lifetime), &(pInTempOffer->Lifetime), sizeof(KEY_LIFETIME) ); pTemp->dwFlags = pInTempOffer->dwFlags; pTemp->bPFSRequired = pInTempOffer->bPFSRequired; pTemp->dwPFSGroup = pInTempOffer->dwPFSGroup; pTemp->dwNumAlgos = pInTempOffer->dwNumAlgos; for (j = 0; j < (pInTempOffer->dwNumAlgos); j++) { memcpy( &(pTemp->Algos[j]), &(pInTempOffer->Algos[j]), sizeof(IPSEC_QM_ALGO) ); } for (k = j; k < QM_MAX_ALGOS; k++) { memset(&(pTemp->Algos[k]), 0, sizeof(IPSEC_QM_ALGO)); } pTemp->dwReserved = pInTempOffer->dwReserved; pInTempOffer++; pTemp++; } *pdwOfferCount = dwInOfferCount; *ppOffers = pOffers; return (dwError); error: TRACE(TRC_ERROR, ("Failed to create QM offers")); if (pOffers) { FreeQMOffers( i, pOffers ); } *pdwOfferCount = 0; *ppOffers = NULL; return (dwError); } DWORD DeleteIniQMPolicy( PINIQMPOLICY pIniQMPolicy ) { DWORD dwError = 0; PINIQMPOLICY * ppTemp = NULL; ppTemp = &gpIniQMPolicy; while (*ppTemp) { if (*ppTemp == pIniQMPolicy) { break; } ppTemp = &((*ppTemp)->pNext); } if (*ppTemp) { *ppTemp = pIniQMPolicy->pNext; } if ((pIniQMPolicy->dwFlags) & IPSEC_QM_POLICY_DEFAULT_POLICY) { gpIniDefaultQMPolicy = NULL; TRACE( TRC_INFORMATION, (L"Cleared default QM policy \"%ls\" (%!guid!)", pIniQMPolicy->pszPolicyName, &pIniQMPolicy->gPolicyID) ); } FreeIniQMPolicy(pIniQMPolicy); return (dwError); } VOID FreeQMOffers( DWORD dwOfferCount, PIPSEC_QM_OFFER pOffers ) { if (pOffers) { SPDApiBufferFree(pOffers); } } VOID FreeIniQMPolicyList( PINIQMPOLICY pIniQMPolicyList ) { PINIQMPOLICY pTemp = NULL; PINIQMPOLICY pIniQMPolicy = NULL; pTemp = pIniQMPolicyList; while (pTemp) { pIniQMPolicy = pTemp; pTemp = pTemp->pNext; FreeIniQMPolicy(pIniQMPolicy); } } PINIQMPOLICY FindQMPolicyByGuid( PINIQMPOLICY pIniQMPolicyList, GUID gPolicyID ) { DWORD dwError = 0; PINIQMPOLICY pTemp = NULL; pTemp = pIniQMPolicyList; while (pTemp) { if (!memcmp(&(pTemp->gPolicyID), &gPolicyID, sizeof(GUID))) { return (pTemp); } pTemp = pTemp->pNext; } return (NULL); } VOID FreeQMPolicies( DWORD dwNumQMPolicies, PIPSEC_QM_POLICY pQMPolicies ) { DWORD i = 0; if (pQMPolicies) { for (i = 0; i < dwNumQMPolicies; i++) { if (pQMPolicies[i].pszPolicyName) { SPDApiBufferFree(pQMPolicies[i].pszPolicyName); } FreeQMOffers( pQMPolicies[i].dwOfferCount, pQMPolicies[i].pOffers ); } SPDApiBufferFree(pQMPolicies); } } DWORD GetQMPolicyByID( LPWSTR pServerName, DWORD dwVersion, GUID gQMPolicyID, DWORD dwFlags, PIPSEC_QM_POLICY * ppQMPolicy, LPVOID pvReserved ) /*++ Routine Description: This function gets a quick mode policy from the SPD. Arguments: pServerName - Server from which to get the quick mode policy. gQMFilter - Guid of the quick mode policy to get. ppQMPolicy - Quick mode policy found returned to the caller. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; PINIQMPOLICY pIniQMPolicy = NULL; PIPSEC_QM_POLICY pQMPolicy = NULL; ENTER_SPD_SECTION(); dwError = ValidateSecurity( SPD_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL ); BAIL_ON_LOCK_ERROR(dwError); pIniQMPolicy = FindQMPolicyByGuid( gpIniQMPolicy, gQMPolicyID ); if (!pIniQMPolicy) { dwError = ERROR_IPSEC_QM_POLICY_NOT_FOUND; BAIL_ON_LOCK_ERROR(dwError); } dwError = GetIniQMPolicy( dwFlags, pIniQMPolicy, &pQMPolicy ); BAIL_ON_LOCK_ERROR(dwError); *ppQMPolicy = pQMPolicy; LEAVE_SPD_SECTION(); return (dwError); lock: LEAVE_SPD_SECTION(); *ppQMPolicy = NULL; return (dwError); } DWORD LocateQMPolicy( DWORD dwFlags, GUID gPolicyID, PINIQMPOLICY * ppIniQMPolicy ) { DWORD dwError = 0; PINIQMPOLICY pIniQMPolicy = NULL; if (dwFlags & IPSEC_QM_POLICY_DEFAULT_POLICY) { if (!gpIniDefaultQMPolicy) { dwError = ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND; BAIL_ON_WIN32_ERROR(dwError); } pIniQMPolicy = gpIniDefaultQMPolicy; } else { pIniQMPolicy = FindQMPolicyByGuid( gpIniQMPolicy, gPolicyID ); if (!pIniQMPolicy) { dwError = ERROR_IPSEC_QM_POLICY_NOT_FOUND; BAIL_ON_WIN32_ERROR(dwError); } } *ppIniQMPolicy = pIniQMPolicy; return (dwError); error: *ppIniQMPolicy = NULL; return (dwError); } DWORD CreateNonAHQMOffers( DWORD dwInOfferCount, PIPSEC_QM_OFFER pInOffers, PDWORD pdwOfferCount, PIPSEC_QM_OFFER * ppOffers ) { DWORD dwError = 0; PIPSEC_QM_OFFER pInTempOffer = NULL; DWORD i = 0; BOOL bAH = FALSE; DWORD dwNonAHOfferCount = 0; PIPSEC_QM_OFFER pOffers = NULL; PIPSEC_QM_OFFER pTemp = NULL; DWORD j = 0; DWORD k = 0; pInTempOffer = pInOffers; for (i = 0; i < dwInOfferCount; i++) { bAH = IsAHQMOffer(pInTempOffer); if (!bAH) { dwNonAHOfferCount++; } pInTempOffer++; } if (!dwNonAHOfferCount) { *pdwOfferCount = 0; *ppOffers = NULL; return (dwError); } dwError = SPDApiBufferAllocate( sizeof(IPSEC_QM_OFFER) * dwNonAHOfferCount, &(pOffers) ); BAIL_ON_WIN32_ERROR(dwError); pTemp = pOffers; pInTempOffer = pInOffers; for (i = 0; i < dwInOfferCount; i++) { bAH = IsAHQMOffer(pInTempOffer); if (bAH) { pInTempOffer++; continue; } memcpy( &(pTemp->Lifetime), &(pInTempOffer->Lifetime), sizeof(KEY_LIFETIME) ); pTemp->dwFlags = pInTempOffer->dwFlags; pTemp->bPFSRequired = pInTempOffer->bPFSRequired; pTemp->dwPFSGroup = pInTempOffer->dwPFSGroup; pTemp->dwNumAlgos = pInTempOffer->dwNumAlgos; for (j = 0; j < (pInTempOffer->dwNumAlgos); j++) { memcpy( &(pTemp->Algos[j]), &(pInTempOffer->Algos[j]), sizeof(IPSEC_QM_ALGO) ); } for (k = j; k < QM_MAX_ALGOS; k++) { memset(&(pTemp->Algos[k]), 0, sizeof(IPSEC_QM_ALGO)); } pTemp->dwReserved = pInTempOffer->dwReserved; pInTempOffer++; pTemp++; } *pdwOfferCount = dwNonAHOfferCount; *ppOffers = pOffers; return (dwError); error: if (pOffers) { FreeQMOffers( i, pOffers ); } *pdwOfferCount = 0; *ppOffers = NULL; return (dwError); } BOOL IsAHQMOffer( PIPSEC_QM_OFFER pIpsecQMOffer ) { BOOL bAH = FALSE; DWORD j = 0; for (j = 0; j < (pIpsecQMOffer->dwNumAlgos); j++) { switch (pIpsecQMOffer->Algos[j].Operation) { case AUTHENTICATION: bAH = TRUE; break; case ENCRYPTION: break; case NONE: case COMPRESSION: default: ASSERT(FALSE); break; } if (bAH) { break; } } return (bAH); }