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.
 
 
 
 
 
 

2066 lines
47 KiB

// AuthMM.cpp: implementation for the WMI class Nsp_MMAuthSettings
//
// Copyright (c)1997-2001 Microsoft Corporation
//
//////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include "IPSecBase.h"
#include "AuthMM.h"
#include "NetSecProv.h"
//extern CCriticalSection g_CS;
const DWORD DefMMAuthMethodFlag = 1;
const MM_AUTH_ENUM DefMMAuthMethod = IKE_SSPI;
/*
Routine Description:
Name:
CAuthMM::QueryInstance
Functionality:
Given the query, it returns to WMI (using pSink) all the instances that satisfy the query.
Actually, what we give back to WMI may contain extra instances. WMI will do the final filtering.
Virtual:
Yes (part of IIPSecObjectImpl)
Arguments:
None.
Return Value:
Success:
(1) WBEM_NO_ERROR if instances are returned;
(2) WBEM_S_NO_MORE_DATA if no instances are returned.
Failure:
Various errors may occur. We return various error code to indicate such errors.
Notes:
*/
STDMETHODIMP
CAuthMM::QueryInstance (
IN LPCWSTR pszQuery,
IN IWbemContext * pCtx,
IN IWbemObjectSink * pSink
)
{
//
// get the authentication method name from the query
// the given key chain doesn't know anything about where clause property
// should be authenticaion, so make another one ourselves.
//
m_srpKeyChain.Release();
HRESULT hr = CNetSecProv::GetKeyChainFromQuery(pszQuery, g_pszAuthMethodID, &m_srpKeyChain);
if (FAILED(hr))
{
return hr;
}
CComVariant var;
//
// if the name is missing, it will return WBEM_S_FALSE, which is fine with us
// because we are querying.
//
hr = m_srpKeyChain->GetKeyPropertyValue(g_pszAuthMethodID, &var);
LPCWSTR pszID = (var.vt == VT_BSTR) ? var.bstrVal : NULL;
var.Clear();
DWORD dwResumeHandle = 0;
PMM_AUTH_METHODS pMMAuth = NULL;
//
// let's enumerate all MM auth methods
//
hr = ::FindMMAuthMethodsByID(pszID, &pMMAuth, &dwResumeHandle);
while (SUCCEEDED(hr) && pMMAuth)
{
CComPtr<IWbemClassObject> srpObj;
hr = CreateWbemObjFromMMAuthMethods(pMMAuth, &srpObj);
//
// we created a method object, then give it to WMI
//
if (SUCCEEDED(hr))
{
pSink->Indicate(1, &srpObj);
}
::SPDApiBufferFree(pMMAuth);
pMMAuth = NULL;
hr = ::FindMMAuthMethodsByID(pszID, &pMMAuth, &dwResumeHandle);
}
//
// since we are querying, it's ok to return not found
//
if (WBEM_E_NOT_FOUND == hr)
{
hr = WBEM_S_NO_MORE_DATA;
}
else if (SUCCEEDED(hr))
{
hr = WBEM_NO_ERROR;
}
return hr;
}
/*
Routine Description:
Name:
CAuthMM::DeleteInstance
Functionality:
Will delete the wbem object (which causes to delete the IPSec main mode auth method).
Virtual:
Yes (part of IIPSecObjectImpl)
Arguments:
pCtx - COM interface pointer given by WMI and needed for various WMI APIs.
pSink - COM interface pointer to notify WMI of any created objects.
Return Value:
Success:
Success code. Use SUCCEEDED(hr) to test.
Failure:
(1) WBEM_E_NOT_FOUND if the auth method can't be found. Depending on
the context, this may not be an error
(2) Other various errors indicated by the returned error codes.
Notes:
*/
STDMETHODIMP
CAuthMM::DeleteInstance (
IN IWbemContext * pCtx,
IN IWbemObjectSink * pSink
)
{
CComVariant varID;
HRESULT hr = m_srpKeyChain->GetKeyPropertyValue(g_pszAuthMethodID, &varID);
if (FAILED(hr))
{
return hr;
}
else if (varID.vt != VT_BSTR || varID.bstrVal == NULL || varID.bstrVal[0] == L'\0')
{
return WBEM_E_NOT_FOUND;
}
DWORD dwResumeHandle = 0;
PMM_AUTH_METHODS pMMAuth = NULL;
hr = ::FindMMAuthMethodsByID(varID.bstrVal, &pMMAuth, &dwResumeHandle);
if (SUCCEEDED(hr))
{
//
// currently, we don't do rollback for delete
//
hr = DeleteAuthMethods(pMMAuth->gMMAuthID);
::SPDApiBufferFree(pMMAuth);
}
return hr;
}
/*
Routine Description:
Name:
CAuthMM::PutInstance
Functionality:
Put an authentication method into SPD whose properties are represented by the
wbem object.
Virtual:
Yes (part of IIPSecObjectImpl)
Arguments:
pInst - The wbem object.
pCtx - COM interface pointer given by WMI and needed for various WMI APIs.
pSink - COM interface pointer to notify WMI of results.
Return Value:
Success:
WBEM_NO_ERROR
Failure:
Various error codes specifying the error.
Notes:
*/
STDMETHODIMP
CAuthMM::PutInstance (
IN IWbemClassObject * pInst,
IN IWbemContext * pCtx,
IN IWbemObjectSink * pSink
)
{
if (pInst == NULL || pSink == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
bool bPreExist = false;
//
// for those policies that are created by ourselves (bPreExist == true)
// we have our own way of allocating the buffer, need to free it in our corresponding way
//
PMM_AUTH_METHODS pMMAuth = NULL;
HRESULT hr = GetMMAuthMethodsFromWbemObj(pInst, &pMMAuth, &bPreExist);
//
// if policy is successfully returned, then use it
//
if (SUCCEEDED(hr))
{
hr = AddAuthMethods(bPreExist, pMMAuth);
if (SUCCEEDED(hr))
{
//
// release the auth method structure
//
hr = OnAfterAddMMAuthMethods(pMMAuth->gMMAuthID);
}
}
if (pMMAuth != NULL)
{
//
// do something to allow this action to be rollback
//
FreeAuthMethods(&pMMAuth, bPreExist);
}
return hr;
}
/*
Routine Description:
Name:
CAuthMM::GetInstance
Functionality:
Create a wbem object by the given key properties (already captured by our key chain object)..
Virtual:
Yes (part of IIPSecObjectImpl)
Arguments:
pCtx - COM interface pointer given by WMI and needed for various WMI APIs.
pSink - COM interface pointer to notify WMI of any created objects.
Return Value:
Success:
WBEM_NO_ERROR.
Failure:
(1) WBEM_E_NOT_FOUND if the auth method can't be found. Depending on
the context, this may not be an error
(2) Other various errors indicated by the returned error codes.
Notes:
*/
STDMETHODIMP
CAuthMM::GetInstance (
IN IWbemContext * pCtx,
IN IWbemObjectSink * pSink
)
{
//
// main mode auth method is uniquely identified by its ID
//
CComVariant varID;
HRESULT hr = m_srpKeyChain->GetKeyPropertyValue(g_pszAuthMethodID, &varID);
if (FAILED(hr))
{
return hr;
}
else if (varID.vt != VT_BSTR || varID.bstrVal == NULL || varID.bstrVal[0] == L'\0')
{
return WBEM_E_NOT_FOUND;
}
//
// need to find the method by its ID. If found, then create a wbem object
// to represent the method.
//
PMM_AUTH_METHODS pMMAuth = NULL;
DWORD dwResumeHandle = 0;
hr = ::FindMMAuthMethodsByID(varID.bstrVal, &pMMAuth, &dwResumeHandle);
if (SUCCEEDED(hr))
{
CComPtr<IWbemClassObject> srpObj;
hr = CreateWbemObjFromMMAuthMethods(pMMAuth, &srpObj);
if (SUCCEEDED(hr))
{
hr = pSink->Indicate(1, &srpObj);
}
::SPDApiBufferFree(pMMAuth);
}
return SUCCEEDED(hr) ? WBEM_NO_ERROR : hr;
}
/*
Routine Description:
Name:
CAuthMM::OnAfterAddMMAuthMethods
Functionality:
Post-adding handler to be called after successfully added a main mode auth method to SPD.
Virtual:
No.
Arguments:
gMethodID - The newly added method's guid.
Return Value:
Success:
(1) WBEM_NO_ERROR: if rollback object is successfully created.
(2) WBEM_S_FALSE: if there is no rollback guid information.
Failure:
(1) various errors indicated by the returned error codes.
Notes:
(1) Currently, we don't require a rollback object to be created for each
object added to SPD. Only a host that support rollback will deposit
rollback guid information and only then can we create a rollback object.
*/
HRESULT
CAuthMM::OnAfterAddMMAuthMethods (
IN GUID gMethodID
)
{
//
// will create an Nsp_RollbackMMAuth
//
CComPtr<IWbemClassObject> srpObj;
HRESULT hr = SpawnRollbackInstance(pszNspRollbackMMAuth, &srpObj);
if (FAILED(hr))
{
return hr;
}
//
// convert the guid into a string version
//
CComBSTR bstrMethodGuid;
bstrMethodGuid.m_str = ::SysAllocStringLen(NULL, GUID_STRING_LENGTH);
if (bstrMethodGuid.m_str)
{
int iRet = ::StringFromGUID2(gMethodID, bstrMethodGuid.m_str, GUID_STRING_LENGTH);
if (iRet == 0)
{
hr = WBEM_E_INVALID_PARAMETER;
}
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
if (SUCCEEDED(hr))
{
//
// get the rollback guid
//
//::UpdateGlobals(m_srpNamespace, m_srpCtx);
//if (g_varRollbackGuid.vt != VT_NULL && g_varRollbackGuid.vt != VT_EMPTY)
//{
// hr = srpObj->Put(g_pszTokenGuid, 0, &g_varRollbackGuid, CIM_EMPTY);
//}
//else
//{
CComVariant varRollbackNull = pszEmptyRollbackToken;
hr = srpObj->Put(g_pszTokenGuid, 0, &varRollbackNull, CIM_EMPTY);
//}
//
// we can create a rollback object
//
if (SUCCEEDED(hr))
{
//
// $undone:shawnwu, Currently, we only support rolling back added objects, not removed objects
// Also, we don't cache the previous instance data yet.
//
VARIANT var;
var.vt = VT_I4;
var.lVal = Action_Add;
hr = srpObj->Put(g_pszAction, 0, &var, CIM_EMPTY);
if (SUCCEEDED(hr))
{
//
// ******Warning******
// don't clear this var. It's bstr will be released by bstrMethodGuid itself!
//
var.vt = VT_BSTR;
var.bstrVal = bstrMethodGuid.m_str;
hr = srpObj->Put(g_pszAuthMethodID, 0, &var, CIM_EMPTY);
//
// after this, I don't care what you do with the var any more.
//
var.vt = VT_EMPTY;
}
}
}
if (SUCCEEDED(hr))
{
hr = m_srpNamespace->PutInstance(srpObj, WBEM_FLAG_CREATE_OR_UPDATE, m_srpCtx, NULL);
if (SUCCEEDED(hr))
{
hr = WBEM_NO_ERROR;
}
}
else if (SUCCEEDED(hr))
{
//
// we don't have rollback guid
//
hr = WBEM_S_FALSE;
}
return hr;
}
/*
Routine Description:
Name:
CAuthMM::CreateWbemObjFromMMAuthMethods
Functionality:
Given a SPD's main mode auth method, we will create a wbem object representing it.
Virtual:
No.
Arguments:
pMMAuth - The SPD's main mode auth method object.
ppObj - Receives the wbem object.
Return Value:
Success:
WBEM_NO_ERROR
Failure:
(1) various errors indicated by the returned error codes.
Notes:
*/
HRESULT
CAuthMM::CreateWbemObjFromMMAuthMethods (
IN PMM_AUTH_METHODS pMMAuth,
OUT IWbemClassObject ** ppObj
)
{
if (pMMAuth == NULL || ppObj == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
*ppObj = NULL;
HRESULT hr = SpawnObjectInstance(ppObj);
if (SUCCEEDED(hr))
{
//
// translate the ID guid into a bstr for the wbem object
//
CComVariant var;
var.vt = VT_BSTR;
var.bstrVal = ::SysAllocStringLen(NULL, Guid_Buffer_Size);
if (var.bstrVal != NULL)
{
//
// it's a key property, so, we must have this property set
//
if (::StringFromGUID2(pMMAuth->gMMAuthID, var.bstrVal, Guid_Buffer_Size) > 0)
{
hr = (*ppObj)->Put(g_pszAuthMethodID, 0, &var, CIM_EMPTY);
}
else
{
hr = WBEM_E_BUFFER_TOO_SMALL;
}
//
// previous var is bstr, we have to clear it for re-use
//
var.Clear();
var.vt = VT_I4;
var.lVal = pMMAuth->dwNumAuthInfos;
hr = (*ppObj)->Put(g_pszNumAuthInfos, 0, &var, CIM_EMPTY);
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
//
// need to fill up the wbem object's properties (those safearray)
//
if (SUCCEEDED(hr))
{
//
// prepare to create the safearrays
//
CComVariant varMethod, varInfo;
varMethod.vt = VT_ARRAY | VT_I4;
varInfo.vt = VT_ARRAY | VT_BSTR;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = pMMAuth->dwNumAuthInfos;
varMethod.parray = ::SafeArrayCreate(VT_I4, 1, rgsabound);
varInfo.parray = ::SafeArrayCreate(VT_BSTR, 1, rgsabound);
//
// for readability
//
PIPSEC_MM_AUTH_INFO pMMAuthInfo = pMMAuth->pAuthenticationInfo;
long lIndecies[1];
DWORD dwIndex;
//
// if arrays are successfully created, then, we are ready to populate the arrays
//
if (varMethod.parray == NULL || varInfo.parray == NULL)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
else
{
//
// put all the method values into the array. If everything is fine, give the var to the wbem object
//
for (dwIndex = 0; SUCCEEDED(hr) && dwIndex < pMMAuth->dwNumAuthInfos; dwIndex++)
{
//
// the element of the safearray to put
//
lIndecies[0] = dwIndex;
hr = ::SafeArrayPutElement(varMethod.parray, lIndecies, &(pMMAuthInfo[dwIndex].AuthMethod) );
if (SUCCEEDED(hr))
{
//
// now, we need to transform the pAuthInfo into a bstr
//
BSTR bstrInfo = NULL;
DWORD dwLength = 0;
switch (pMMAuthInfo[dwIndex].AuthMethod)
{
case IKE_PRESHARED_KEY:
//
// pAuthInfo is wchar array
//
dwLength = pMMAuthInfo[dwIndex].dwAuthInfoSize/sizeof(WCHAR);
bstrInfo = ::SysAllocStringLen(NULL, dwLength + 1);
if (bstrInfo)
{
//
// convert it to a bstr from the wchar array (no 0 terminator!)
//
::wcsncpy(bstrInfo, (LPCWSTR)(pMMAuthInfo[dwIndex].pAuthInfo), dwLength);
bstrInfo[dwLength] = L'\0';
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
break;
case IKE_RSA_SIGNATURE:
//
// pAuthInfo is ansi char array
//
dwLength = pMMAuthInfo[dwIndex].dwAuthInfoSize;
bstrInfo = ::SysAllocStringLen(NULL, dwLength + 1);
if (bstrInfo)
{
//
// convert it to a bstr from the ansi char array.
// remember, pAuthInfo has no 0 terminator!
//
for (DWORD d = 0; d < dwLength; d++)
{
bstrInfo[d] = (WCHAR)(char)(pMMAuthInfo[dwIndex].pAuthInfo[d]);
}
bstrInfo[dwLength] = L'\0';
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
break;
case IKE_SSPI:
//
// pAuthInfo must be NULL
//
break;
default:
//
// IPSec only supports these three values at this point
//
hr = WBEM_E_NOT_SUPPORTED;
}
if (SUCCEEDED(hr))
{
hr = ::SafeArrayPutElement(varInfo.parray, lIndecies, bstrInfo);
if (bstrInfo)
{
::SysFreeString(bstrInfo);
}
}
}
}
//
// every element has been successfully put
//
if (SUCCEEDED(hr))
{
hr = (*ppObj)->Put(g_pszAuthMethod, 0, &varMethod, CIM_EMPTY);
hr = (*ppObj)->Put(g_pszAuthInfo, 0, &varInfo, CIM_EMPTY);
}
}
}
}
//
// we may have created the object, but some mid steps have failed,
// so let's release the object.
//
if (FAILED(hr) && *ppObj != NULL)
{
(*ppObj)->Release();
*ppObj = NULL;
}
return SUCCEEDED(hr) ? WBEM_NO_ERROR : hr;
}
/*
Routine Description:
Name:
CAuthMM::GetMMAuthMethodsFromWbemObj
Functionality:
Will try to get the MM Auth methods if such method already exists.
Otherwise, we will create a new one.
Virtual:
No.
Arguments:
pInst - The wbem object object.
ppMMAuth - Receives the main mode auth method.
pbPreExist - Receives the information whether this object memory is allocated by SPD or not.
Return Value:
Success:
WBEM_NO_ERROR
Failure:
(1) various errors indicated by the returned error codes.
Notes:
*/
HRESULT
CAuthMM::GetMMAuthMethodsFromWbemObj (
IN IWbemClassObject * pInst,
OUT PMM_AUTH_METHODS * ppMMAuth,
OUT bool * pbPreExist
)
{
if (pInst == NULL || ppMMAuth == NULL || pbPreExist == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
*ppMMAuth = NULL;
*pbPreExist = false;
//
// we have to have method id.
//
CComVariant var;
GUID gMMAuthID = GUID_NULL;
HRESULT hr = pInst->Get(g_pszAuthMethodID, 0, &var, NULL, NULL);
if (FAILED(hr) || var.vt != VT_BSTR || var.bstrVal == NULL)
{
hr = WBEM_E_INVALID_OBJECT;
}
else
{
hr = ::CLSIDFromString(var.bstrVal, &gMMAuthID);
}
//
// Do we already have a method with this method ID?
//
if (SUCCEEDED(hr))
{
DWORD dwResumeHandle = 0;
hr = ::FindMMAuthMethodsByID(var.bstrVal, ppMMAuth, &dwResumeHandle);
}
//
// clear it for later use
//
var.Clear();
//
// if we have a method already,
//
if (SUCCEEDED(hr))
{
//
// already exist
//
*pbPreExist = true;
}
else if (hr == WBEM_E_NOT_FOUND)
{
//
// The method doesn't exist yet. We need to create one.
// First, need to know the number of AuthMethodInfos, we must have this
// to know how to allocate!
//
hr = pInst->Get(g_pszNumAuthInfos, 0, &var, NULL, NULL);
if (SUCCEEDED(hr) && var.vt == VT_I4)
{
hr = AllocAuthMethods(var.lVal, ppMMAuth);
}
else if (SUCCEEDED(hr))
{
//
// we don't want to overwrite other errors. That is why
// we test it against success here!
//
hr = WBEM_E_INVALID_OBJECT;
}
if (SUCCEEDED(hr))
{
(*ppMMAuth)->gMMAuthID = gMMAuthID;
}
}
//
// put our properties (inside the wbem object) into the AUTH_INFOs
//
if (SUCCEEDED(hr))
{
//
// set all elements of the pAuthenticationInfo array
//
CComVariant varMethods, varInfos;
hr = pInst->Get(g_pszAuthMethod, 0, &varMethods, NULL, NULL);
if (SUCCEEDED(hr))
{
hr = pInst->Get(g_pszAuthInfo, 0, &varInfos, NULL, NULL);
}
//
// both must be arrays
//
if ( (varMethods.vt & VT_ARRAY) != VT_ARRAY || (varInfos.vt & VT_ARRAY) != VT_ARRAY)
{
hr = WBEM_E_INVALID_OBJECT;
}
if (SUCCEEDED(hr))
{
//
// populate the method object using these arrays
//
hr = UpdateAuthInfos(pbPreExist, &varMethods, &varInfos, *ppMMAuth);
}
}
if (FAILED(hr) && *ppMMAuth != NULL)
{
//
// FreeAuthMethods will reset ppMMAuth to NULL.
//
FreeAuthMethods(ppMMAuth, (*pbPreExist == false));
}
return SUCCEEDED(hr) ? WBEM_NO_ERROR : hr;
}
/*
Routine Description:
Name:
CAuthMM::UpdateAuthInfos
Functionality:
Private helper: will populate the pAuthMethods's pAuthenticationInfo
using the in parameters.
Virtual:
No.
Arguments:
pbPreExist - The flag that indicates whether the method was allocated
by ourselves or not. This flag may be changed when this function
returns as a result of modifying IPSec allocated buffers.
pVarMethods - the AuthMethod member of each IPSEC_MM_AUTH_INFO.
pVarSizes - the dwAuthInfoSize member of each IPSEC_MM_AUTH_INFO.
pAuthMethods - What is to be poluated. It must contain the correct dwNumAuthInfos value
and valid and consistent pAuthenticationInfo.
Return Value:
Success:
WBEM_NO_ERROR
Failure:
(1) various errors indicated by the returned error codes.
Notes:
(1) pAuthMethods contains information as it is passed in. Don't blindly
overwrite it. Only update those that are present by the other parameters
(2) IPSec only support the following methods (pVarMethods' values):
IKE_PRESHARED_KEY=1,IKE_RSA_SIGNATURE=3, IKE_SSPI=5
This leaves IKE_DSS_SIGNATURE=2 and IKE_RSA_ENCRYPTION=4 not supported
For IKE_PRESHARED_KEY, pAuthInfo is a wchar array, but no null terminator, dwAuthInfoSize
is the byte size (not the count of wchars)
For IKE_RSA_SIGNATURE, pAuthInfo is a blob of ASNI chars encoded issuer name of root certs.
dwAuthInfoSize is the byte size (in this case, the same as the count of chars)
For IKE_SSPI, pAuthInfo = NULL, dwAuthInfoSize = 0
Warning: at this point, we don't support modifying existing methods.
*/
HRESULT
CAuthMM::UpdateAuthInfos (
IN OUT bool * pbPreExist,
IN VARIANT * pVarMethods,
IN VARIANT * pVarInfos,
IN OUT PMM_AUTH_METHODS pAuthMethods
)
{
if (NULL == pbPreExist ||
NULL == pVarMethods ||
NULL == pVarInfos ||
NULL == pAuthMethods )
{
return WBEM_E_INVALID_PARAMETER;
}
//
// do a defensive checking: all these safearrays must have the same size
//
//
// lower bound and upper bound of the array
//
long lLB, lUB;
HRESULT hr = ::CheckSafeArraySize(pVarMethods, pAuthMethods->dwNumAuthInfos, &lLB, &lUB);
//
// we don't need the bounds for methods, so OK to overwrite lLB and lUP for them
//
if (SUCCEEDED(hr))
{
hr = ::CheckSafeArraySize(pVarInfos, pAuthMethods->dwNumAuthInfos, &lLB, &lUB);
}
if (FAILED(hr))
{
return hr;
}
//
// if a brand new method
//
if (*pbPreExist == false)
{
//
// need to create the get the entire array from the parameters
//
DWORD* pdwMethods = new DWORD[pAuthMethods->dwNumAuthInfos];
if (pdwMethods == NULL)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
else
{
hr = ::GetDWORDSafeArrayElements(pVarMethods, pAuthMethods->dwNumAuthInfos, pdwMethods);
}
VARIANT varInfo;
varInfo.vt = VT_BSTR;
long lIndexes[1];
//
// Safearray's index is not necessarily 0-based. Pay attention to this.
// For each method, we need to set the PIPSEC_MM_AUTH_INFO.
//
for (long l = lLB; SUCCEEDED(hr) && l <= lUB; l++)
{
lIndexes[0] = l;
//
// for IKE_PRESHARED_KEY=1, IKE_RSA_SIGNATURE=3, IKE_SSPI=5, set the appropriate blob pAuthInfo
//
if (pdwMethods[l - lLB] != IKE_PRESHARED_KEY &&
pdwMethods[l - lLB] != IKE_RSA_SIGNATURE &&
pdwMethods[l - lLB] != IKE_SSPI)
{
hr = WBEM_E_VALUE_OUT_OF_RANGE;
break;
}
//
// for readability
//
PIPSEC_MM_AUTH_INFO pTheInfo = &(pAuthMethods->pAuthenticationInfo[l - lLB]);
//
// set the AuthMethod
//
pTheInfo->AuthMethod = (MM_AUTH_ENUM)(pdwMethods[l - lLB]);
//
// IKE_SSPI, pAuthInfo must be NULL
//
if (IKE_SSPI == pTheInfo->AuthMethod)
{
pTheInfo->dwAuthInfoSize = 0;
pTheInfo->pAuthInfo = NULL;
}
else
{
//
// for other supported IKE (IKE_PRESHARED_KEY/IKE_RSA_SIGNATURE)
// the pAuthInfo is a is a string (unicode/ansi).
//
hr = ::SafeArrayGetElement(pVarInfos->parray, lIndexes, &(varInfo.bstrVal));
if (SUCCEEDED(hr) && varInfo.vt == VT_BSTR)
{
hr = SetAuthInfo(pTheInfo, varInfo.bstrVal);
}
::VariantClear(&varInfo);
varInfo.vt = VT_BSTR;
}
}
delete [] pdwMethods;
}
return hr;
}
/*
Routine Description:
Name:
CAuthMM::UpdateAuthInfos
Functionality:
Private helper: will populate the pAuthMethods's pAuthenticationInfo
using the in parameters.
Virtual:
No.
Arguments:
pInfo - Receives the IPSEC_MM_AUTH_INFO information from the bstr
bstrInfo - The string.
Return Value:
Success:
WBEM_NO_ERROR
Failure:
(1) various errors indicated by the returned error codes.
Notes:
(1) This function is made so complicated to the fact that IPSEC_MM_AUTH_INFO's
pAuthInfo is a string (unicode or ansi), but it doesn't have contain the
0 terminator. Pay close attention to that.
Warning:
(1) This only works for custom allocated auth info. Don't call this function
with IPSec returned auth info. The reason for this limit is due the fact
that we are not supporting modifying existing SPD objects at this time.
(2) Only works for those two IKE enums that needs this conversion:
IKE_PRESHARED_KEY and IKE_RSA_SIGNATURE
*/
HRESULT
CAuthMM::SetAuthInfo (
IN OUT PIPSEC_MM_AUTH_INFO pInfo,
IN BSTR bstrInfo
)
{
if (pInfo == NULL || bstrInfo == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
HRESULT hr = WBEM_NO_ERROR;
DWORD dwLength = wcslen(bstrInfo);
if (IKE_PRESHARED_KEY == pInfo->AuthMethod)
{
//
// IKE_PRESHARED_KEY, pAuthInfo will be an array of wchars (no 0 terminator)
//
//
// size must not count the 0 terminator, pAuthInfo is an array of wchars
//
pInfo->dwAuthInfoSize = dwLength * sizeof(WCHAR);
//
// pAuthInfo must not have the 0 terminator
//
pInfo->pAuthInfo = new BYTE[pInfo->dwAuthInfoSize];
if (pInfo->pAuthInfo)
{
::wcsncpy((LPWSTR)(pInfo->pAuthInfo), bstrInfo, dwLength);
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else if (IKE_RSA_SIGNATURE == pInfo->AuthMethod)
{
//
// IKE_RSA_SIGNATURE, pAuthInfo will be an array of ansi chars (no 0 terminator)
//
LPSTR pMultiBytes = NULL;
//
// convert bstr into an ansi char array
//
//
// first, get the buffer size needed for the conversion
//
long lMultiByteSize = ::WideCharToMultiByte(CP_ACP,
0,
bstrInfo,
dwLength,
pMultiBytes,
0,
NULL,
NULL);
if (lMultiByteSize > 1)
{
//
// convert to a temporary buffer because the conversion needs a null terminator
// must release this memory
//
pMultiBytes = new char[lMultiByteSize];
if (pMultiBytes)
{
lMultiByteSize = ::WideCharToMultiByte(CP_ACP,
0,
bstrInfo,
dwLength,
pMultiBytes,
lMultiByteSize,
NULL, NULL);
//
// lMultiByteSize includes the null terminator
//
if (lMultiByteSize > 1)
{
//
// size must not count the 0 terminator, pAuthInfo is an array of ansi chars
//
pInfo->dwAuthInfoSize = lMultiByteSize;
//
// pAuthInfo must not have the 0 terminator
//
pInfo->pAuthInfo = new BYTE[lMultiByteSize];
if (pInfo->pAuthInfo)
{
//
// copy the bytes
//
memcpy(pInfo->pAuthInfo, pMultiBytes, lMultiByteSize);
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
{
//
// $undone:shawnwu, should get system error (GetLastErr)
//
hr = WBEM_E_FAILED;
}
delete [] pMultiBytes;
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
{
//
// $undone:shawnwu, should get system error (GetLastErr)
//
hr = WBEM_E_FAILED;
}
}
else
{
pInfo->pAuthInfo = NULL;
hr = WBEM_E_NOT_SUPPORTED;
}
return hr;
}
/*
Routine Description:
Name:
CAuthMM::AllocAuthMethods
Functionality:
Private helper: will allocate heap memory for a MM_AUTH_METHODS with
the given number of IPSEC_MM_AUTH_INFO.
Virtual:
No.
Arguments:
dwNumInfos - The count of IPSEC_MM_AUTH_INFO of the MM_AUTH_METHODS.
ppMMAuth - Receives the heap allocated MM_AUTH_METHODS.
Return Value:
Success:
WBEM_NO_ERROR
Failure:
(1) WBEM_E_INVALID_PARAMETER: if ppMMAuth == NULL.
(2) WBEM_E_OUT_OF_MEMORY.
Notes:
*/
HRESULT
CAuthMM::AllocAuthMethods (
IN DWORD dwNumInfos,
IN PMM_AUTH_METHODS * ppMMAuth
)
{
if (ppMMAuth == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
HRESULT hr = WBEM_NO_ERROR;
*ppMMAuth = new MM_AUTH_METHODS;
if (*ppMMAuth != NULL)
{
//
// Set these members to default.
//
(*ppMMAuth)->gMMAuthID = GUID_NULL;
(*ppMMAuth)->dwFlags = DefMMAuthMethodFlag;
//
// We don't update this to the parameter value of dwNumInfos until we can allocate the IPSEC_MM_AUTH_INFO's
//
(*ppMMAuth)->dwNumAuthInfos = 0;
if (dwNumInfos > 0)
{
//
// IPSEC_MM_AUTH_INFO's are allocated by AllocAuthInfos function.
//
hr = AllocAuthInfos(dwNumInfos, &((*ppMMAuth)->pAuthenticationInfo));
if (SUCCEEDED(hr))
{
(*ppMMAuth)->dwNumAuthInfos = dwNumInfos;
}
}
else
{
(*ppMMAuth)->pAuthenticationInfo = NULL;
}
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
return hr;
}
/*
Routine Description:
Name:
CAuthMM::AllocAuthInfos
Functionality:
Private helper: will allocate heap buffer for the given count of IPSEC_MM_AUTH_INFO.
Virtual:
No.
Arguments:
dwNumInfos - The count of IPSEC_MM_AUTH_INFO.
ppAuthInfos - Receives the heap allocated PIPSEC_MM_AUTH_INFO.
Return Value:
Success:
WBEM_NO_ERROR
Failure:
(1) WBEM_E_INVALID_PARAMETER: if ppMMAuth == NULL.
(2) WBEM_E_OUT_OF_MEMORY.
Notes:
*/
HRESULT
CAuthMM::AllocAuthInfos (
IN DWORD dwNumInfos,
OUT PIPSEC_MM_AUTH_INFO * ppAuthInfos
)
{
if (ppAuthInfos == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
HRESULT hr = WBEM_NO_ERROR;
*ppAuthInfos = new IPSEC_MM_AUTH_INFO[dwNumInfos];
if (*ppAuthInfos != NULL)
{
//
// set its members to defaults
//
(*ppAuthInfos)->AuthMethod = DefMMAuthMethod;
(*ppAuthInfos)->dwAuthInfoSize = 0;
(*ppAuthInfos)->pAuthInfo = NULL;
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
return hr;
}
/*
Routine Description:
Name:
CAuthMM::FreeAuthMethods
Functionality:
Private helper: will free memory allocated for the PMM_AUTH_METHODS.
Virtual:
No.
Arguments:
ppMMAuth - The heap buffer for PMM_AUTH_METHODS. Will be set to NULL upon return.
bCustomAlloc - Flag about who allocated the buffer. bCustomAlloc == true if we allocate it
and bCustomAlloc == false if SPD allocated it.
Return Value:
None.
Notes:
Don't use delete to free heap allocated MM_AUTH_METHODS. Our allocation method is totally
different from SPD's and SPD may change its allocation schema in the future.
*/
void
CAuthMM::FreeAuthMethods (
IN OUT PMM_AUTH_METHODS * ppMMAuth,
IN bool bCustomAlloc
)
{
if (ppMMAuth == NULL || *ppMMAuth == NULL)
{
return;
}
if (bCustomAlloc == false)
{
::SPDApiBufferFree(*ppMMAuth);
}
else
{
//
// we allocated IPSEC_MM_AUTH_INFO for pAuthenticationInfo in the standard C++ embedding
// pointer's allocation, i.e., we don't allocated a flat buffer. Instead, the pointers inside
// IPSEC_MM_AUTH_INFO are separately allocated.
//
FreeAuthInfos( (*ppMMAuth)->dwNumAuthInfos, &((*ppMMAuth)->pAuthenticationInfo) );
delete *ppMMAuth;
}
*ppMMAuth = NULL;
}
/*
Routine Description:
Name:
CAuthMM::FreeAuthInfos
Functionality:
Private helper: will free memory allocated for the array of IPSEC_MM_AUTH_INFO.
Virtual:
No.
Arguments:
dwNumInfos - The number of IPSEC_MM_AUTH_INFO of the given ppAuthInfos. Since ppAuthInfos
is an array, we need this count to know the count of the array.
ppAuthInfos - The array of IPSEC_MM_AUTH_INFO to free. Will be set to NULL upon return.
Return Value:
None.
Notes:
Use this method only to free those authentication methods allocated by our
own allocation method AllocAuthMethods. For SPD allocated IPSEC_MM_AUTH_INFO's,
don't use this function. Instead, use SPD's SPDApiBufferFree to free the entire
buffer and you should never need to worry about IPSEC_MM_AUTH_INFO.
*/
void
CAuthMM::FreeAuthInfos (
IN DWORD dwNumInfos,
IN OUT PIPSEC_MM_AUTH_INFO * ppAuthInfos
)
{
if (ppAuthInfos == NULL || *ppAuthInfos == NULL)
{
return;
}
for (DWORD dwIndex = 0; dwIndex < dwNumInfos; ++dwIndex)
{
//
// this is LPBYTE, an array
//
delete [] (*ppAuthInfos)[dwIndex].pAuthInfo;
}
delete [] *ppAuthInfos;
*ppAuthInfos = NULL;
}
/*
Routine Description:
Name:
CAuthMM::Rollback
Functionality:
Static function to rollback those main mode auth methods added by us with
the given token.
Virtual:
No.
Arguments:
pNamespace - The namespace for ourselves.
pszRollbackToken - The token used to record our the action when we add
the methods.
bClearAll - Flag whether we should clear all auth methods. If it's true,
then we will delete all main mode auth methods regardless whether they
are added by us or not. This is a dangerous flag.
Return Value:
Success:
(1) WBEM_NO_ERROR: rollback objects are found and they are deleted.
(2) WBEM_S_FALSE: no rollback objects are found.
Failure:
Various error codes indicating the cause of the failure.
Notes:
We will continue the deletion even if some failure happens. That failure will be
returned, though.
$undone:shawnwu, should we really support ClearAll?
*/
HRESULT
CAuthMM::Rollback (
IN IWbemServices * pNamespace,
IN LPCWSTR pszRollbackToken,
IN bool bClearAll
)
{
if (pNamespace == NULL || pszRollbackToken == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
//if (bClearAll)
//{
// return ClearAllAuthMethods(pNamespace);
//}
//
// we need to find all those main mode auth methods' rollback objects with matching token
//
CComPtr<IEnumWbemClassObject> srpEnum;
HRESULT hr = ::GetClassEnum(pNamespace, pszNspRollbackMMAuth, &srpEnum);
//
// go through all found classes. srpEnum->Next will return WBEM_S_FALSE if instance
// is not found.
//
CComPtr<IWbemClassObject> srpObj;
ULONG nEnum = 0;
hr = srpEnum->Next(WBEM_INFINITE, 1, &srpObj, &nEnum);
bool bHasInst = (SUCCEEDED(hr) && hr != WBEM_S_FALSE && srpObj != NULL);
DWORD dwStatus;
HRESULT hrError = WBEM_NO_ERROR;
while (SUCCEEDED(hr) && hr != WBEM_S_FALSE && srpObj)
{
//
// See if this obj has our matching token (guid).
//
// I tried a query with the given token as part of the where clause.
// that query doesn't return the properly screened objects. That might be a limitation
// of non-dynamic classes of WMI.
//
CComVariant varTokenGuid;
hr = srpObj->Get(g_pszTokenGuid, 0, &varTokenGuid, NULL, NULL);
//
// if we successfully got the token guid from the object, and
// if that token matches (case-insensitively) with our given token, then this is
// the right object we can use to delete a main mode auth method.
//
if (SUCCEEDED(hr) &&
varTokenGuid.vt == VT_BSTR &&
varTokenGuid.bstrVal != NULL &&
(_wcsicmp(pszRollbackToken, pszRollbackAll) == 0 || _wcsicmp(pszRollbackToken, varTokenGuid.bstrVal) == 0 )
)
{
CComVariant varAuthMethodID;
//
// Ask SPD to delete the main mode auth method using the method's ID.
//
hr = srpObj->Get(g_pszAuthMethodID, 0, &varAuthMethodID, NULL, NULL);
GUID guidAuthMethodGuid = GUID_NULL;
if (SUCCEEDED(hr) && varAuthMethodID.vt == VT_BSTR)
{
::CLSIDFromString(varAuthMethodID.bstrVal, &guidAuthMethodGuid);
}
if (SUCCEEDED(hr))
{
hr = DeleteAuthMethods(guidAuthMethodGuid);
}
//
// Clear the rollback object itself if the main mode method has been deleted.
//
if (SUCCEEDED(hr))
{
CComVariant varPath;
if (SUCCEEDED(srpObj->Get(L"__RelPath", 0, &varPath, NULL, NULL)) && varPath.vt == VT_BSTR)
{
hr = pNamespace->DeleteInstance(varPath.bstrVal, 0, NULL, NULL);
}
}
//
// we are tracking the first error
//
if (FAILED(hr) && SUCCEEDED(hrError))
{
hrError = hr;
}
}
//
// ready it for re-use
//
srpObj.Release();
hr = srpEnum->Next(WBEM_INFINITE, 1, &srpObj, &nEnum);
}
if (!bHasInst)
{
return WBEM_S_FALSE;
}
else
{
//
// any failure code will be returned regardless of the final hr
//
if (FAILED(hrError))
{
return hrError;
}
else
{
return SUCCEEDED(hr) ? WBEM_NO_ERROR : hr;
}
}
}
/*
Routine Description:
Name:
CAuthMM::ClearAllAuthMethods
Functionality:
Static function to delete all auth methods in SPD. This is a very dangerous action!
Virtual:
No.
Arguments:
pNamespace - The namespace for ourselves.
Return Value:
Success:
WBEM_NO_ERROR.
Failure:
Various error codes indicating the cause of the failure.
Notes:
We will continue the deletion even if some failure happens. That failure will be
returned, though.
$undone:shawnwu, should we really support this?
*/
HRESULT
CAuthMM::ClearAllAuthMethods (
IN IWbemServices * pNamespace
)
{
DWORD dwResumeHandle = 0;
DWORD dwReturned = 0;
DWORD dwStatus;
PMM_AUTH_METHODS *ppMMAuthMethods = NULL;
HRESULT hr = WBEM_NO_ERROR;
HRESULT hrError = WBEM_NO_ERROR;
//
// get each main mode auth method's ID, which is what deletion needs.
//
dwStatus = ::EnumMMAuthMethods(NULL, ppMMAuthMethods, 1, &dwReturned, &dwResumeHandle);
while (ERROR_SUCCESS == dwStatus && dwReturned > 0)
{
hr = DeleteAuthMethods((*ppMMAuthMethods)->gMMAuthID);
//
// we will track the first error
//
if (FAILED(hr) && SUCCEEDED(hrError))
{
hrError = hr;
}
FreeAuthMethods(ppMMAuthMethods, true);
*ppMMAuthMethods = NULL;
dwReturned = 0;
dwStatus = ::EnumMMAuthMethods(NULL, ppMMAuthMethods, 1, &dwReturned, &dwResumeHandle);
}
//
// Let's clear up all past action information for mm methods rollback objects deposited in the WMI depository
//
hr = ::DeleteRollbackObjects(pNamespace, pszNspRollbackMMAuth);
if (FAILED(hr) && SUCCEEDED(hrError))
{
hrError = hr;
}
return SUCCEEDED(hrError) ? WBEM_NO_ERROR : hrError;
}
/*
Routine Description:
Name:
CAuthMM::AddAuthMethods
Functionality:
Add the given main mode auth method.
Virtual:
No.
Arguments:
bPreExist - Flag whether the main mode auth method already exists in SPD
pMMAuth - The main mode method to add.
Return Value:
Success:
WBEM_NO_ERROR.
Failure:
WBEM_E_FAILED.
Notes:
*/
HRESULT
CAuthMM::AddAuthMethods (
IN bool bPreExist,
IN PMM_AUTH_METHODS pMMAuth
)
{
DWORD dwResult;
if (!bPreExist)
{
dwResult = ::AddMMAuthMethods(NULL, 1, pMMAuth);
}
else
{
dwResult = ::SetMMAuthMethods(NULL, pMMAuth->gMMAuthID, pMMAuth);
}
//
// $undone:shawnwu, need better error code for failures.
//
return (dwResult == ERROR_SUCCESS) ? WBEM_NO_ERROR : WBEM_E_FAILED;
}
/*
Routine Description:
Name:
CAuthMM::AddAuthMethods
Functionality:
Add the given main mode auth method.
Virtual:
No.
Arguments:
pMMAuth - The main mode method to add.
Return Value:
Success:
WBEM_NO_ERROR.
Failure:
WBEM_E_VETO_DELETE.
Notes:
*/
HRESULT
CAuthMM::DeleteAuthMethods (
IN GUID gMMAuthID
)
{
HRESULT hr = WBEM_NO_ERROR;
DWORD dwResult = ::DeleteMMAuthMethods(NULL, gMMAuthID);
if (ERROR_SUCCESS != dwResult)
{
hr = WBEM_E_VETO_DELETE;
}
//
// $undone:shawnwu, need better error code for failures.
//
return hr;
}