Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1691 lines
37 KiB

/*++
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);
}