////////////////////////////////////////////////////////////////////// // Policy.h : Declaration of base class for main mode and quick mode // policies classes // security WMI provider for SCE // Copyright (c)1997-2001 Microsoft Corporation // // Original Create Date: 4/11/2001 // Original Author: shawnwu ////////////////////////////////////////////////////////////////////// #pragma once #include "globals.h" #include "IPSecBase.h" extern CComVariant g_varRollbackGuid; const DWORD DefaultMMPolicyFlag = 0; const DWORD DefaultQMPolicyFlag = 0; const DWORD DefaultMMPolicyOfferFlag = 0; const DWORD DefaultQMPolicyOfferFlag = 0; const DWORD DefaultaultSoftSAExpirationTime = DEFAULT_MM_KEY_EXPIRATION_TIME; // // any value is valid. 0 means unlimited // const DWORD DefaultQMModeLimit = 32; // // either DH_GROUP_1 or DH_GROUP_2 (stronger and more costly) // const DWORD DefaultDHGroup = DH_GROUP_1; // //IPSEC_DOI_ESP_3_DES is more cost // const DWORD DefaultEncryptAlgoID = IPSEC_DOI_ESP_DES; const DWORD DefaultHashAlgoID = 0; // // either is valid, TRUE more cost // const BOOL DefaultPFSRequired = FALSE; const DWORD DefaultPFSGroup = PFS_GROUP_NONE; const DWORD DefaultNumAlgos = 1; // // If ENCRYPTION, then uAlgoIdentifier is the IPSEC_DOI_ESP_DES or IPSEC_DOI_ESP_3_DES // and uSecAlgoIdentifier can't be HMAC_AH_NONE // else if AUTHENTICATION then uAlgoIdentifier is IPSEC_DOI_AH_MD5 or IPSEC_DOI_AH_SHA1, // and uSecAlgoIdentifier should be HMAC_AH_NONE // else if COMPRESSION, ?? // else if SA_DELETE, ?? // const IPSEC_OPERATION DefaultQMAlgoOperation = ENCRYPTION; const ULONG DefaultAlgoID = IPSEC_DOI_ESP_DES; const HMAC_AH_ALGO DefaultAlgoSecID = HMAC_AH_MD5; // // We have two different types of policies in SPD // enum EnumPolicyType { MainMode_Policy = 1, QuickMode_Policy = 2, }; /* Class description Naming: CIPSecPolicy stands for IPSec Policy. Base class: CIPSecBase Purpose of class: (1) Being a base for both main mode policy and quick mode policy implementations. Design: (1) Provide property access (both Put and Get) that are common to both main mode and quick mode. See GetPolicyFromWbemObj/CreateWbemObjFromPolicy. (2) Provide rollback support. Both main mode and quick mode have the same logic. (3) Provide some allocation/deallocation that can be parameterized using template functions. Use: (1) Class is designed for inheritance use. (2) Rollback, GetPolicyFromWbemObj, and CreateWbemObjFromPolicy are the ones you will use directly, even though all other static ones are also available for the other classes, they are not intended for such use. Notes: (1) It contains several template functions. This reduces the duplicate code. */ class CIPSecPolicy : public CIPSecBase { protected: CIPSecPolicy(){} virtual ~CIPSecPolicy(){} public: static HRESULT Rollback ( IN IWbemServices * pNamespace, IN LPCWSTR pszRollbackToken, IN bool bClearAll ); // // some template functions // /* Routine Description: Name: CIPSecPolicy::GetPolicyFromWbemObj Functionality: Given a wbem object representing a policy (either main mode or quick mode), this function either finds the policy from SPD or creates a new one and fill in the wbem object's properties into the policy struct. Virtual: No. Arguments: pInst - The wbem object. ppPolicy - Receives the policy. This can be PIPSEC_MM_POLICY or PIPSEC_QM_POLICY. Caller needs to free this by calling FreePolicy; pbPreExist - Whether SPD allocates the buffer (true) or not (false). Return Value: Success: WBEM_NO_ERROR Failure: (1) WBEM_E_INVALID_PARAMETER if ppPolicy == NULL or pdwResumeHandle == NULL. (2) WBEM_E_NOT_FOUND if the policy is not found. Notes: (1) Make sure that you call FreePolicy to free the buffer! */ template static HRESULT GetPolicyFromWbemObj ( IN IWbemClassObject * pInst, OUT Policy ** ppPolicy, OUT bool * pbPreExist ) { if (pInst == NULL || ppPolicy == NULL || pbPreExist == NULL) { return WBEM_E_INVALID_PARAMETER; } *ppPolicy = NULL; *pbPreExist = false; DWORD dwResumeHandle = 0; // this var will be re-used again and again. Each should be Clear'ed before reuse. CComVariant var; // try to find out if the filter already exists HRESULT hr = pInst->Get(g_pszPolicyName, 0, &var, NULL, NULL); if (SUCCEEDED(hr) && var.vt == VT_BSTR) { // see if this is a filter we already have hr = FindPolicyByName(var.bstrVal, ppPolicy, &dwResumeHandle); if (SUCCEEDED(hr)) *pbPreExist = true; else { // can't find it, fine. I will create a new one hr = AllocPolicy(ppPolicy); if (SUCCEEDED(hr)) { (*ppPolicy)->pszPolicyName = NULL; hr = ::CoCreateGuid(&((*ppPolicy)->gPolicyID)); if (SUCCEEDED(hr)) { // give it the name DWORD dwSize = wcslen(var.bstrVal) + 1; (*ppPolicy)->pszPolicyName = new WCHAR[dwSize]; if (NULL == (*ppPolicy)->pszPolicyName) hr = WBEM_E_OUT_OF_MEMORY; else { ::memcpy((*ppPolicy)->pszPolicyName, var.bstrVal, dwSize * sizeof(WCHAR)); } } } // dwFlags and pOffers if (SUCCEEDED(hr)) { var.Clear(); // dwFlags. We allow this to be missing if (SUCCEEDED(pInst->Get(g_pszPolicyFlag, 0, &var, NULL, NULL)) && var.vt == VT_I4) (*ppPolicy)->dwFlags = var.lVal; else (*ppPolicy)->dwFlags = 0; hr = pInst->Get(g_pszOfferCount, 0, &var, NULL, NULL); if (SUCCEEDED(hr) && var.vt == VT_I4) { hr = AllocOffer( &((*ppPolicy)->pOffers), var.lVal); if (SUCCEEDED(hr)) (*ppPolicy)->dwOfferCount = var.lVal; } else hr = WBEM_E_INVALID_OBJECT; } // set up the LifeTime if (SUCCEEDED(hr)) { DWORD* pdwTimeKBytes = new DWORD[(*ppPolicy)->dwOfferCount]; if (pdwTimeKBytes == NULL) hr = WBEM_E_OUT_OF_MEMORY; else { var.Clear(); // we will allow the life-time's expiration time to be missing since we have defaults // if we successfully get the key life exp time, then set them if ( SUCCEEDED(pInst->Get(g_pszKeyLifeTime, 0, &var, NULL, NULL)) && (var.vt & VT_ARRAY) == VT_ARRAY ) { hr = ::GetDWORDSafeArrayElements(&var, (*ppPolicy)->dwOfferCount, pdwTimeKBytes); // if get the exp times if (SUCCEEDED(hr)) { for (long l = 0; l < (*ppPolicy)->dwOfferCount; l++) { (*ppPolicy)->pOffers[l].Lifetime.uKeyExpirationTime = pdwTimeKBytes[l]; } } } var.Clear(); // set the expiration kbytes, again, we allow the info to be missing since we already has default if ( SUCCEEDED(pInst->Get(g_pszKeyLifeTimeKBytes, 0, &var, NULL, NULL)) && (var.vt & VT_ARRAY) == VT_ARRAY ) { hr = ::GetDWORDSafeArrayElements(&var, (*ppPolicy)->dwOfferCount, pdwTimeKBytes); // if get the exp kbytes if (SUCCEEDED(hr)) { for (long l = 0; l < (*ppPolicy)->dwOfferCount; l++) { (*ppPolicy)->pOffers[l].Lifetime.uKeyExpirationKBytes = pdwTimeKBytes[l]; } } } delete [] pdwTimeKBytes; } } } } if (FAILED(hr)) { FreePolicy(ppPolicy, *pbPreExist); } return hr; }; template HRESULT CreateWbemObjFromPolicy(Policy* pPolicy, IWbemClassObject* pInst) { if (pInst == NULL || pPolicy == NULL) return WBEM_E_INVALID_PARAMETER; CComVariant var = pPolicy->pszPolicyName; HRESULT hr = pInst->Put(g_pszPolicyName, 0, &var, CIM_EMPTY); // put offer count if (SUCCEEDED(hr)) { var.Clear(); var.vt = VT_I4; // don't really care much about dwFlags var.lVal = pPolicy->dwFlags; pInst->Put(g_pszPolicyFlag, 0, &var, CIM_EMPTY); var.lVal = pPolicy->dwOfferCount; hr = pInst->Put(g_pszOfferCount, 0, &var, CIM_EMPTY); } // put LifeTime if (SUCCEEDED(hr)) { // create the a safearray var.vt = VT_ARRAY | VT_I4; SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0; rgsabound[0].cElements = pPolicy->dwOfferCount; var.parray = ::SafeArrayCreate(VT_I4, 1, rgsabound); if (var.parray == NULL) hr = WBEM_E_OUT_OF_MEMORY; else { long lIndecies[1]; // deal with uKeyExpirationTime for (DWORD dwIndex = 0; SUCCEEDED(hr) && dwIndex < pPolicy->dwOfferCount; dwIndex++) { lIndecies[0] = dwIndex; hr = ::SafeArrayPutElement(var.parray, lIndecies, &(pPolicy->pOffers[dwIndex].Lifetime.uKeyExpirationTime) ); } if (SUCCEEDED(hr)) hr = pInst->Put(g_pszKeyLifeTime, 0, &var, CIM_EMPTY); // deal with uKeyExpirationKBytes for (DWORD dwIndex = 0; SUCCEEDED(hr) && dwIndex < pPolicy->dwOfferCount; dwIndex++) { lIndecies[0] = dwIndex; hr = ::SafeArrayPutElement(var.parray, lIndecies, &(pPolicy->pOffers[dwIndex].Lifetime.uKeyExpirationKBytes) ); } if (SUCCEEDED(hr)) hr = pInst->Put(g_pszKeyLifeTimeKBytes, 0, &var, CIM_EMPTY); } } return hr; } protected: template static HRESULT AllocPolicy(Policy** ppPolicy) { if (ppPolicy == NULL) return WBEM_E_INVALID_PARAMETER; HRESULT hr = WBEM_NO_ERROR; *ppPolicy = new Policy; if (*ppPolicy) { (*ppPolicy)->pszPolicyName = NULL; (*ppPolicy)->dwOfferCount = 0; (*ppPolicy)->pOffers = NULL; } else hr = WBEM_E_OUT_OF_MEMORY; return hr; } static void GetDefaultOfferLifeTime(PIPSEC_MM_OFFER pOffer, DWORD* pdwDefFlag, ULONG* pulTime, ULONG* pulKBytes) { *pdwDefFlag = DefaultMMPolicyOfferFlag; *pulTime = DEFAULT_MM_KEY_EXPIRATION_TIME; *pulKBytes = DEFAULT_QM_KEY_EXPIRATION_KBYTES; } static void GetDefaultOfferLifeTime(PIPSEC_QM_OFFER pOffer, DWORD* pdwDefFlag, ULONG* pulTime, ULONG* pulKBytes) { *pdwDefFlag = DefaultQMPolicyOfferFlag; *pulTime = DEFAULT_QM_KEY_EXPIRATION_TIME; *pulKBytes = DEFAULT_QM_KEY_EXPIRATION_KBYTES; } template static HRESULT AllocOffer(Offer** ppOffer, long lCount) { if (ppOffer == NULL) return WBEM_E_INVALID_PARAMETER; *ppOffer = new Offer[lCount]; if (*ppOffer != NULL) { ULONG ulTime, ulKBytes; DWORD dwDefFlag; GetDefaultOfferLifeTime(*ppOffer, &dwDefFlag, &ulTime, &ulKBytes); for (long l = 0; l < lCount; l++) { (*ppOffer)[l].dwFlags = dwDefFlag; (*ppOffer)[l].Lifetime.uKeyExpirationTime = ulTime; (*ppOffer)[l].Lifetime.uKeyExpirationKBytes = ulKBytes; } return WBEM_NO_ERROR; } else return WBEM_E_OUT_OF_MEMORY; } template static void FreePolicy(Policy** ppPolicy, bool bPreExist) { if (ppPolicy == NULL || *ppPolicy == NULL) return; if (bPreExist) ::SPDApiBufferFree(*ppPolicy); else { delete [] (*ppPolicy)->pszPolicyName; delete [] (*ppPolicy)->pOffers; delete *ppPolicy; } *ppPolicy = NULL; }; static HRESULT ClearAllPolicies(IWbemServices* pNamespace); HRESULT OnAfterAddPolicy(LPCWSTR pszPolicyName, EnumPolicyType eType); };