windows-nt/Source/XPSP1/NT/net/ias/mmc/nap/iasstringattributeeditor.cpp
2020-09-26 16:20:57 +08:00

880 lines
19 KiB
C++

//////////////////////////////////////////////////////////////////////////////
/*++
Copyright (C) Microsoft Corporation, 1998 - 1999
Module Name:
IASStringAttributeEditor.cpp
Abstract:
Implementation file for the CIASStringAttributeEditor class.
Revision History:
mmaguire 06/25/98 - created
--*/
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// BEGIN INCLUDES
//
// standard includes:
//
#include "Precompiled.h"
//
// where we can find declaration for main class in this file:
//
#include "IASStringAttributeEditor.h"
//
// where we can find declarations needed in this file:
//
#include "IASStringEditorPage.h"
#include "iashelper.h"
//
// END INCLUDES
//////////////////////////////////////////////////////////////////////////////
BYTE PREFIX___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD[] = {0,0,0,0};
UINT PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD = 4;
UINT PREFIX_OFFSET_DATALENBYTE___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD = 3; // 0 based index -- the fourth byte
UINT PREFIX_LEN_DATALENBYTE___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD = 1; // one byte
//////////////////////////////////////////////////////////////////////////////
/*++
CIASStringAttributeEditor::ShowEditor
--*/
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CIASStringAttributeEditor::ShowEditor( /*[in, out]*/ BSTR *pReserved )
{
TRACE(_T("CIASStringAttributeEditor::ShowEditor\n"));
AFX_MANAGE_STATE(AfxGetStaticModuleState())
HRESULT hr = S_OK;
try
{
// Load page title.
// ::CString strPageTitle;
// strPageTitle.LoadString(IDS_IAS_IP_EDITOR_TITLE);
//
// CPropertySheet propSheet( (LPCTSTR)strPageTitle );
//
// IP Address Editor
//
CIASPgSingleAttr cppPage;
// Initialize the page's data exchange fields with info from IAttributeInfo
CComBSTR bstrName;
CComBSTR bstrSyntax;
ATTRIBUTESYNTAX asSyntax = IAS_SYNTAX_OCTETSTRING;
ATTRIBUTEID Id = ATTRIBUTE_UNDEFINED;
if( m_spIASAttributeInfo )
{
hr = m_spIASAttributeInfo->get_AttributeName( &bstrName );
if( FAILED(hr) ) throw hr;
hr = m_spIASAttributeInfo->get_SyntaxString( &bstrSyntax );
if( FAILED(hr) ) throw hr;
hr = m_spIASAttributeInfo->get_AttributeSyntax( &asSyntax );
if( FAILED(hr) ) throw hr;
hr = m_spIASAttributeInfo->get_AttributeID( &Id );
if( FAILED(hr) ) throw hr;
}
cppPage.m_strAttrName = bstrName;
cppPage.m_AttrSyntax = asSyntax;
cppPage.m_nAttrId = Id;
cppPage.m_strAttrFormat = bstrSyntax;
// Attribute type is actually attribute ID in string format
WCHAR szTempId[MAX_PATH];
wsprintf(szTempId, _T("%ld"), Id);
cppPage.m_strAttrType = szTempId;
// Initialize the page's data exchange fields with info from VARIANT value passed in.
if ( V_VT(m_pvarValue) != VT_EMPTY )
{
EStringType sp;
CComBSTR bstrTemp;
get_ValueAsStringEx( &bstrTemp, &sp );
cppPage.m_strAttrValue = bstrTemp;
cppPage.m_OctetStringType = sp;
}
// propSheet.AddPage(&cppPage);
// int iResult = propSheet.DoModal();
int iResult = cppPage.DoModal();
if (IDOK == iResult)
{
CComBSTR bstrTemp = (LPCTSTR)cppPage.m_strAttrValue;
put_ValueAsStringEx( bstrTemp, cppPage.m_OctetStringType);
}
else
{
hr = S_FALSE;
}
//
// delete the property page pointer
//
// propSheet.RemovePage(&cppPage);
}
catch( HRESULT & hr )
{
return hr;
}
catch(...)
{
return hr = E_FAIL;
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
/*++
CIASStringAttributeEditor::SetAttributeValue
--*/
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CIASStringAttributeEditor::SetAttributeValue(VARIANT * pValue)
{
TRACE(_T("CIASStringAttributeEditor::SetAttributeValue\n"));
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// Check for preconditions.
if( ! pValue )
{
return E_INVALIDARG;
}
// From Baogang's old code, it appears that this editor should accept
// either VT_BSTR, VT_BOOL, VT_I4 or VT_EMPTY.
if( V_VT(pValue) != VT_BSTR
&& V_VT(pValue) != VT_BOOL
&& V_VT(pValue) != VT_I4
&& V_VT(pValue) != VT_EMPTY
&& V_VT(pValue) != (VT_ARRAY | VT_UI1))
{
return E_INVALIDARG;
}
m_pvarValue = pValue;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
/*++
CIASStringAttributeEditor::get_ValueAsString
--*/
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CIASStringAttributeEditor::get_ValueAsString(BSTR * pbstrDisplayText )
{
TRACE(_T("CIASStringAttributeEditor::get_ValueAsString\n"));
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// Check for preconditions.
if( ! pbstrDisplayText )
{
return E_INVALIDARG;
}
if( ! m_spIASAttributeInfo || ! m_pvarValue )
{
// We are not initialized properly.
return OLE_E_BLANK;
}
HRESULT hr = S_OK;
try
{
CComBSTR bstrDisplay;
VARTYPE vType = V_VT(m_pvarValue);
switch( vType )
{
case VT_BOOL:
{
if( V_BOOL(m_pvarValue) )
{
// ISSUE: This is not localizable!!!
// Should it be? Ask Ashwin about this as some of
// Baogang's error checking code was specifically looking
// for either hardcoded "TRUE" or "FALSE".
// ISSUE: I think that for Boolean syntax attributes,
// we should be popping up the same type of attribute
// editor as for the enumerables only with TRUE and FALSE in it.
bstrDisplay = L"TRUE";
}
else
{
bstrDisplay = L"FALSE";
}
}
break;
case VT_I4:
{
// The variant is some type which must be coerced to a bstr.
CComVariant varValue;
// Make sure you pass a VT_EMPTY variant to VariantChangeType
// or it will assert.
// So don't do: V_VT(&varValue) = VT_BSTR;
hr = VariantChangeType(&varValue, m_pvarValue, VARIANT_NOVALUEPROP, VT_BSTR);
if( FAILED( hr ) ) throw hr;
bstrDisplay = V_BSTR(&varValue);
}
break;
case VT_BSTR:
bstrDisplay = V_BSTR(m_pvarValue);
break;
case VT_UI1 | VT_ARRAY: // Treat as Octet string
{
EStringType t;
return get_ValueAsStringEx(pbstrDisplayText, &t);
}
break;
default:
// need to check what is happening here,
ASSERT(0);
break;
case VT_EMPTY:
// do nothing -- we will fall through and return a blank string.
break;
}
*pbstrDisplayText = bstrDisplay.Copy();
}
catch( HRESULT &hr )
{
return hr;
}
catch(...)
{
return E_FAIL;
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
/*++
CIASStringAttributeEditor::put_ValueAsString
--*/
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CIASStringAttributeEditor::put_ValueAsString(BSTR newVal)
{
TRACE(_T("CIASStringAttributeEditor::put_ValueAsString\n"));
AFX_MANAGE_STATE(AfxGetStaticModuleState())
if( ! m_pvarValue )
{
// We are not initialized properly.
return OLE_E_BLANK;
}
if( m_spIASAttributeInfo == NULL )
{
// We are not initialized properly.
return OLE_E_BLANK;
}
HRESULT hr = S_OK;
try
{
CComBSTR bstrTemp = newVal;
CComVariant varValue;
V_VT(&varValue) = VT_BSTR;
V_BSTR(&varValue) = bstrTemp.Copy();
VARTYPE vType = V_VT(m_pvarValue);
// Initialize the variant that was passed in.
VariantClear(m_pvarValue);
{
ATTRIBUTESYNTAX asSyntax;
hr = m_spIASAttributeInfo->get_AttributeSyntax( &asSyntax );
if( FAILED(hr) ) throw hr;
// if this Octet string, this should be BSTR, no matter what it was before.
if(asSyntax == IAS_SYNTAX_OCTETSTRING)
vType = VT_BSTR;
if ( VT_EMPTY == vType)
{
// decide the value type:
switch (asSyntax)
{
case IAS_SYNTAX_BOOLEAN:
vType = VT_BOOL;
break;
case IAS_SYNTAX_INTEGER:
case IAS_SYNTAX_UNSIGNEDINTEGER:
case IAS_SYNTAX_ENUMERATOR:
case IAS_SYNTAX_INETADDR:
vType = VT_I4;
break;
case IAS_SYNTAX_STRING:
case IAS_SYNTAX_UTCTIME:
case IAS_SYNTAX_PROVIDERSPECIFIC:
case IAS_SYNTAX_OCTETSTRING:
vType = VT_BSTR;
break;
default:
_ASSERTE(FALSE);
vType = VT_BSTR;
break;
}
}
}
hr = VariantChangeType(m_pvarValue, &varValue, VARIANT_NOVALUEPROP, vType);
if( FAILED( hr ) ) throw hr;
}
catch( HRESULT &hr )
{
return hr;
}
catch(...)
{
return E_FAIL;
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
/*++
CIASStringAttributeEditor::get_ValueAsStringEx
--*/
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CIASStringAttributeEditor::get_ValueAsStringEx(BSTR * pbstrDisplayText, EStringType* pType )
{
TRACE(_T("CIASStringAttributeEditor::get_ValueAsString\n"));
AFX_MANAGE_STATE(AfxGetStaticModuleState())
ATTRIBUTESYNTAX asSyntax;
m_spIASAttributeInfo->get_AttributeSyntax( &asSyntax );
if(asSyntax != IAS_SYNTAX_OCTETSTRING)
{
if(pType)
*pType = STRING_TYPE_NORMAL;
return get_ValueAsString(pbstrDisplayText);
}
// only care about IAS_SYNTAX_OCTETSTRING
ASSERT(pType);
VARTYPE vType = V_VT(m_pvarValue);
SAFEARRAY* psa = NULL;
HRESULT hr = S_OK;
switch(vType)
{
case VT_ARRAY | VT_UI1:
psa = V_ARRAY(m_pvarValue);
break;
case VT_EMPTY:
if(pType)
*pType = STRING_TYPE_NULL;
return get_ValueAsString(pbstrDisplayText);
break;
case VT_BSTR:
if(pType)
*pType = STRING_TYPE_NORMAL;
return get_ValueAsString(pbstrDisplayText);
break;
default:
ASSERT(0); // should not happen, should correct some code
if(pType)
*pType = STRING_TYPE_NORMAL;
return get_ValueAsString(pbstrDisplayText);
break;
};
// no data is available , or the safe array is not valid, don't intepret the string
if(psa == NULL || psa->cDims != 1 || psa->cbElements != 1)
{
*pType = STRING_TYPE_NULL;
return hr;
}
// need to figure out how to convert the binary to text
char* pData = NULL;
int nBytes = 0;
WCHAR* pWStr = NULL;
int nWStr = 0;
DWORD dwErr = 0;
BOOL bStringConverted = FALSE;
CComBSTR bstrDisplay;
EStringType sType = STRING_TYPE_NULL;
hr = ::SafeArrayAccessData( psa, (void**)&pData);
if(hr != S_OK)
return hr;
nBytes = psa->rgsabound[0].cElements;
ASSERT(pData);
if(!pData) goto Error;
#ifdef __WE_WANT_TO_USE_UTF8_FOR_NORMAL_STRING_AS_WELL_
// UTF8 requires the flag to be 0
nWStr = MultiByteToWideChar(CP_UTF8, 0, pData, nBytes, NULL, 0);
if(nWStr == 0)
dwErr = GetLastError();
#endif
try{
#ifdef __WE_WANT_TO_USE_UTF8_FOR_NORMAL_STRING_AS_WELL_
if(nWStr != 0) // succ
{
pWStr = new WCHAR[nWStr + 2]; // for the 2 "s
int i = 0;
nWStr == MultiByteToWideChar(CP_UTF8, 0, pData, nBytes, pWStr , nWStr);
// if every char is printable
for(i = 0; i < nWStr -1; i++)
{
if(iswprint(pWStr[i]) == 0)
break;
}
if(0 == nWStr || i != nWStr - 1 || pWStr[i] != L'\0')
{
delete[] pWStr;
pWStr = NULL;
}
else
{
// added quotes
memmove(pWStr + 1, pWStr, nWStr * sizeof(WCHAR));
pWStr[0] = L'"';
pWStr[nWStr] = L'"';
pWStr[nWStr + 1 ] = 0; // new end of string
bStringConverted = TRUE; // to prevent from furthe convertion to HEX
sType = STRING_TYPE_UNICODE;
}
}
#endif // __WE_WANT_TO_USE_UTF8_FOR_NORMAL_STRING_AS_WELL_
// check if the attriabute is RADIUS_ATTRIBUTE_TUNNEL_PASSWORD,
// this attribute has special format --- remove 0's from the binary and
// try to conver to text
{
ATTRIBUTEID Id;
hr = m_spIASAttributeInfo->get_AttributeID( &Id );
if( FAILED(hr) ) goto Error;
if ( Id == RADIUS_ATTRIBUTE_TUNNEL_PASSWORD)
{
//BYTE PREFIX___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD[] = {0,0,0,0};
//UINT PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD = 4;
//UINT PREFIX_OFFSET_DATALENBYTE___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD = 3; // 0 based index -- the fourth byte
//UINT PREFIX_LEN_DATALENBYTE___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD = 1
if(PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD <=nBytes &&
memcmp(pData,
PREFIX___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD,
PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD - PREFIX_LEN_DATALENBYTE___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD) == 0)
{
// correct prefix,
// remove the prefix
pData += PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD;
nBytes -= PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD;
// try to convert to UNICODE TEXT using CP_ACP -- get length
nWStr = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, pData, nBytes, NULL, 0);
if(nWStr != 0) // which means, we can not convert
{
pWStr = new WCHAR[nWStr + 1];
// try to convert to UNICODE TEXT using CP_ACP
nWStr = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, pData, nBytes, pWStr, nWStr);
if(nWStr != 0)
{
int i = 0;
for(i = 0; i < nWStr; i++)
{
if(iswprint(pWStr[i]) == 0)
break;
}
if( i == nWStr) // all printable
{
bStringConverted = TRUE;
pWStr[nWStr] = 0; // NULL terminator
}
}
if (!bStringConverted) // undo the thing
{
// release the buffer
delete[] pWStr;
pWStr = NULL;
nWStr = 0;
}
}
}
}
}
if(!bStringConverted) // not converted above, convert to HEX string
{
nWStr = BinaryToHexString(pData, nBytes, NULL, 0); // find out the size of the buffer
pWStr = new WCHAR[nWStr];
ASSERT(pWStr); // should have thrown if there is not enough memory
BinaryToHexString(pData, nBytes, pWStr, nWStr);
bStringConverted = TRUE; // to prevent from furthe convertion to HEX
sType = STRING_TYPE_HEX_FROM_BINARY;
}
if(bStringConverted)
{
bstrDisplay = pWStr;
// fill in the output parameters
*pbstrDisplayText = bstrDisplay.Copy();
*pType = sType;
delete[] pWStr;
pWStr = NULL;
}
}
catch(...)
{
hr = E_OUTOFMEMORY;
goto Error;
}
Error:
if(pWStr)
delete[] pWStr;
if(psa)
::SafeArrayUnaccessData(psa);
return hr;
}
//////////////////////////////////////////////////////////////////////////////
/*++
*/
//////////////////////////////////////////////////////////////////////////////
/*++
CIASStringAttributeEditor::put_ValueAsStringEx
--*/
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CIASStringAttributeEditor::put_ValueAsStringEx(BSTR newVal, EStringType type)
{
TRACE(_T("CIASStringAttributeEditor::put_ValueAsStringEx\n"));
AFX_MANAGE_STATE(AfxGetStaticModuleState())
ATTRIBUTESYNTAX asSyntax;
m_spIASAttributeInfo->get_AttributeSyntax( &asSyntax );
if(asSyntax != IAS_SYNTAX_OCTETSTRING)
return put_ValueAsString(newVal);
// only care about IAS_SYNTAX_OCTETSTRING
HRESULT hr = S_OK;
char* pData = NULL;
int nLen = 0;
switch(type)
{
case STRING_TYPE_NULL:
// remove the data
break;
case STRING_TYPE_NORMAL:
case STRING_TYPE_UNICODE:
#ifdef __WE_WANT_TO_USE_UTF8_FOR_NORMAL_STRING_AS_WELL_
// need to convert UTF8 before passing into SafeArray
nLen = WideCharToMultiByte(CP_UTF8, 0, newVal, -1, NULL, 0, NULL, NULL);
if(nLen != 0) // when == 0 , need not to do anything
{
try{
pData = new char[nLen];
nLen = WideCharToMultiByte(CP_UTF8, 0, newVal, -1, pData, nLen, NULL, NULL);
}
catch(...)
{
hr = E_OUTOFMEMORY;
goto Error;
}
}
break;
#else
// check if the attriabute is RADIUS_ATTRIBUTE_TUNNEL_PASSWORD,
// this attribute has special format --- remove 0's from the binary and
// try to conver to text
{
ATTRIBUTEID Id;
hr = m_spIASAttributeInfo->get_AttributeID( &Id );
if( FAILED(hr) ) goto Error;
if ( Id == RADIUS_ATTRIBUTE_TUNNEL_PASSWORD)
{
BOOL bUsedDefault = FALSE;
UINT nStrLen = wcslen(newVal);
// try to convert to UNICODE TEXT using CP_ACP -- get length
nLen = ::WideCharToMultiByte(CP_ACP, 0, newVal, nStrLen, NULL, 0, NULL, &bUsedDefault);
if(nLen != 0) // which means, we can not convert
{
try{
pData = new char[nLen];
ASSERT(pData);
// try to convert to UNICODE TEXT using CP_ACP
nLen = ::WideCharToMultiByte(CP_ACP, 0, newVal, nStrLen, pData, nLen, NULL, &bUsedDefault);
}
catch(...)
{
hr = E_OUTOFMEMORY;
goto Error;
}
}
if(nLen == 0 || bUsedDefault) // failed to convert, then error message
{
// ANSI code page is allowed
hr = E_INVALIDARG;
AfxMessageBox(IDS_IAS_ERR_INVALIDCHARINPASSWORD);
goto Error;
}
}
else
return put_ValueAsString(newVal);
}
break;
#endif
case STRING_TYPE_HEX_FROM_BINARY:
// need to convert to binary before passing into SafeArray
if(wcslen(newVal) != 0)
{
newVal = GetValidVSAHexString(newVal);
if(newVal == NULL)
{
hr = E_INVALIDARG;
goto Error;
}
nLen = HexStringToBinary(newVal, NULL, 0); // find out the size of the buffer
}
else
nLen = 0;
// get the binary
try{
pData = new char[nLen];
ASSERT(pData);
HexStringToBinary(newVal, pData, nLen);
}
catch(...)
{
hr = E_OUTOFMEMORY;
goto Error;
}
break;
default:
ASSERT(0); // this should not happen
break;
}
// check if the attriabute is RADIUS_ATTRIBUTE_TUNNEL_PASSWORD,
// this attribute has special format --- remove 0's from the binary and
// try to conver to text
{
ATTRIBUTEID Id;
hr = m_spIASAttributeInfo->get_AttributeID( &Id );
if( FAILED(hr) ) goto Error;
if ( Id == RADIUS_ATTRIBUTE_TUNNEL_PASSWORD)
{
char* pData1 = NULL;
// get the binary
//BYTE PREFIX___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD[] = {0,0,0,0};
//UINT PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD = 4;
//UINT PREFIX_OFFSET_DATALENBYTE___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD = 3; // 0 based index -- the fourth byte
//UINT PREFIX_LEN_DATALENBYTE___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD = 1
try{
pData1 = new char[nLen + PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD];
ASSERT(pData1);
memcpy(pData1, PREFIX___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD, PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD);
unsigned char lenByte = (unsigned char)nLen;
memcpy(pData1 + PREFIX_OFFSET_DATALENBYTE___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD, &lenByte, PREFIX_LEN_DATALENBYTE___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD);
}
catch(...)
{
hr = E_OUTOFMEMORY;
goto Error;
}
if(pData)
{
memcpy(pData1 + PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD, pData, nLen);
delete [] pData;
pData = pData1;
nLen += PREFIX_LEN___RADIUS_ATTRIBUTE_TUNNEL_PASSWORD;
}
}
}
// put the data into the safe array
VariantClear(m_pvarValue);
if(pData) // need to put data to safe array
{
SAFEARRAY* psa = NULL;
SAFEARRAYBOUND sab[1];
sab[0].cElements = nLen;
sab[0].lLbound = 0;
try{
psa = SafeArrayCreate(VT_UI1, 1, sab);
char* pByte = NULL;
if(S_OK == SafeArrayAccessData(psa, (void**)&pByte))
{
ASSERT(pByte);
memcpy(pByte, pData, nLen);
SafeArrayUnaccessData(psa);
V_VT(m_pvarValue) = VT_ARRAY | VT_UI1;
V_ARRAY(m_pvarValue) = psa;
}
else
SafeArrayDestroy(psa);
}
catch(...)
{
hr = E_OUTOFMEMORY;
goto Error;
}
psa = NULL;
};
Error:
if(pData)
{
delete [] pData;
pData = NULL;
}
return hr;
}