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

885 lines
21 KiB
C++

/**********************************************************************/
/** Microsoft Windows/NT **/
/** Copyright(c) Microsoft Corporation, 1998 - 1999 **/
/**********************************************************************/
/*
IASHelper.cpp
Implementation of the following helper classes:
And global functions:
GetSdoInterfaceProperty - Get an interface property from a SDO
through its ISdo interface
FILE HISTORY:
2/18/98 byao Created
*/
#include "Precompiled.h"
#include <limits.h>
#include <winsock2.h>
#include "IASHelper.h"
//+---------------------------------------------------------------------------
//
// Function: IASGetSdoInterfaceProperty
//
// Synopsis: Get an interface property from a SDO through its ISdo interface
//
// Arguments: ISdo *pISdo - Pointer to ISdo
// LONG lPropId - property id
// REFIID riid - ref iid
// void ** ppvObject - pointer to the requested interface property
//
// Returns: HRESULT -
//
// History: Created Header byao 2/12/98 11:12:55 PM
//
//+---------------------------------------------------------------------------
HRESULT IASGetSdoInterfaceProperty(ISdo *pISdo,
LONG lPropID,
REFIID riid,
void ** ppvInterface)
{
TRACE(_T("::IASGetSdoInterfaceProperty()\n"));
CComVariant var;
HRESULT hr;
V_VT(&var) = VT_DISPATCH;
V_DISPATCH(&var) = NULL;
hr = pISdo->GetProperty(lPropID, &var);
//ReportError(hr, IDS_IAS_ERR_SDOERROR_GETPROPERTY, NULL);
_ASSERTE( V_VT(&var) == VT_DISPATCH );
// query the dispatch pointer for interface
hr = V_DISPATCH(&var) -> QueryInterface( riid, ppvInterface);
//ReportError(hr, IDS_IAS_ERR_SDOERROR_QUERYINTERFACE, NULL);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: Hex2DWord
//
// Synopsis: hexadecimal string to dword value
//
// Arguments: TCHAR* tszStr - number in hexadecimal string format "FF"
//
// Returns: DWORD - value
//
// History: Created Header byao 3/6/98 2:46:49 AM
//
//+---------------------------------------------------------------------------
DWORD Hex2DWord(TCHAR* tszStr)
{
TRACE(_T("::Hex2DWord()\n"));
DWORD dwTemp = 0;
DWORD dwDigit = 0;
DWORD dwIndex = 0;
for (dwIndex=0; dwIndex<_tcslen(tszStr); dwIndex++)
{
// get the current digit
if ( tszStr[dwIndex]>= _T('0') && tszStr[dwIndex]<= _T('9') )
dwDigit = tszStr[dwIndex] - _T('0');
else if ( tszStr[dwIndex]>= _T('A') && tszStr[dwIndex]<= _T('F') )
dwDigit = tszStr[dwIndex] - _T('A') + 10;
else if ( tszStr[dwIndex]>= _T('a') && tszStr[dwIndex]<= _T('f') )
dwDigit = tszStr[dwIndex] - _T('a') + 10;
// accumulate the value
dwTemp = dwTemp*16 + dwDigit;
}
return dwTemp;
}
//todo: where should we put these constants?
#define L_INT_SIZE_BYTES 4 // from BaseCamp
// position 0--1: value format
#define I_VENDOR_ID_POS 2 // vendor ID starts from position 2;
#define I_ATTRIBUTE_TYPE_POS 10 // either the vendor attribute type(RFC),
// or raw value (for NONRFC value)
//+---------------------------------------------------------------------------
//
// Function: GetVendorSpecificInfo
//
// Synopsis: Get the information for vendor-specific attribute type
//
// Arguments: [in]::CString& strValue - OctetString value
// [out]int& dVendorId - Vendor ID
// [out]fNonRFC - random/Radius RFC compatible
// [out]dFormat - value format: string, integer, etc.
// [out]int&dType - data type
// [out]::CString&strDispValue - data displayable value
//
// Returns: HRESULT -
//
// History: Created Header byao 2/28/98 12:12:11 AM
//
//+---------------------------------------------------------------------------
HRESULT GetVendorSpecificInfo(::CString& strValue,
DWORD& dVendorId,
BOOL& fNonRFC,
DWORD& dFormat,
DWORD& dType,
::CString& strDispValue)
{
TRACE(_T("::GetVendorSpecificInfo()\n"));
::CString strVSAType;
::CString strVSALen;
::CString strVSAValue;
::CString strVendorId;
::CString strPrefix;
TCHAR tszTempStr[256];
DWORD dwIndex;
if ( strValue.GetLength() < I_ATTRIBUTE_TYPE_POS)
{
// invalid attribute value;
strDispValue = strValue;
fNonRFC = TRUE;
return E_FAIL;
}
strDispValue.Empty();
// is it a RADIUS RFC compatible value?
_tcsncpy(tszTempStr, strValue, 2);
tszTempStr[2] = _T('\0');
switch( _ttoi(tszTempStr) )
{
case 0: fNonRFC = TRUE; dFormat = 0; dType = 0;
break;
case 1: fNonRFC = FALSE; dFormat = 0; // string
break;
case 2: fNonRFC = FALSE; dFormat = 1; // integer
break;
case 4: // ipaddress
fNonRFC = FALSE; dFormat = 3; // hexadecimal
break;
case 3:
default: fNonRFC = FALSE; dFormat = 2; // hexadecimal
break;
}
// Vendor ID
for (dwIndex=0; dwIndex<8; dwIndex++)
{
tszTempStr[dwIndex] = ((LPCTSTR)strValue)[I_VENDOR_ID_POS+dwIndex];
}
tszTempStr[dwIndex] = _T('\0');
dVendorId = Hex2DWord(tszTempStr);
// non RFC data?
if ( fNonRFC )
{
_tcscpy(tszTempStr, (LPCTSTR)strValue + I_ATTRIBUTE_TYPE_POS);
strDispValue = tszTempStr;
}
else
{
// Radius RFC format
// find the attribute type
tszTempStr[0] = ((LPCTSTR)strValue)[I_ATTRIBUTE_TYPE_POS];
tszTempStr[1] = ((LPCTSTR)strValue)[I_ATTRIBUTE_TYPE_POS+1];
tszTempStr[2] = _T('\0');
dType = Hex2DWord(tszTempStr);
TCHAR* tszPrefixStart;
// find the attribute value
switch(dFormat)
{
case 0: // string
{
DWORD jIndex;
TCHAR tszTempChar[3];
TCHAR tszTemp[2];
_tcscpy(tszTempStr, (LPCTSTR)strValue+I_ATTRIBUTE_TYPE_POS+4);
strDispValue = tszTempStr;
/*
jIndex = 0;
while ( jIndex < _tcslen(tszTempStr)-1 )
{
tszTempChar[0] = tszTempStr[jIndex];
tszTempChar[1] = tszTempStr[jIndex+1];
tszTempChar[2] = _T('\0');
tszTemp[0] = (TCHAR) Hex2DWord(tszTempChar);
tszTemp[1] = _T('\0');
strDispValue += tszTemp;
jIndex += 2;
}
*/
}
break;
case 1: // decimal or hexadecimal
tszPrefixStart = _tcsstr(strValue, _T("0x"));
if (tszPrefixStart == NULL)
{
tszPrefixStart = _tcsstr(strValue, _T("0X"));
}
if (tszPrefixStart)
{
// hexadecimal
_tcscpy(tszTempStr, tszPrefixStart);
strDispValue = tszTempStr;
}
else
{
// decimal
_tcscpy(tszTempStr, (LPCTSTR)strValue+I_ATTRIBUTE_TYPE_POS+4);
DWORD dwValue = Hex2DWord(tszTempStr);
wsprintf(tszTempStr, _T("%u"), dwValue);
strDispValue = tszTempStr;
}
break;
case 3: // ip address
{
// like decimal
_tcscpy(tszTempStr, (LPCTSTR)strValue+I_ATTRIBUTE_TYPE_POS+4);
if(_tcslen(tszTempStr) != 0)
{
DWORD dwValue = Hex2DWord(tszTempStr);
in_addr ipaddr;
ipaddr.s_addr = ntohl(dwValue);
strDispValue = inet_ntoa(ipaddr);
}
else
strDispValue = _T("");
}
break;
case 2: // hexadecimal
_tcscpy(tszTempStr, (LPCTSTR)strValue+I_ATTRIBUTE_TYPE_POS+4);
strDispValue = tszTempStr;
break;
}
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: SetVendorSpecificInfo
//
// Synopsis: Set the information for vendor-specific attribute type
//
// Arguments: [out]::CString& strValue - OctetString value
// [in]int& dVendorId - Vendor ID
// [in]fNonRFC - random or RADIUS RFC compatible
// [in]dFormat - attribute format: string, integer; hexadecimal
// [in]int& dType - attribute type
// [in]::CString& strDispValue - data displayable value
//
// Returns: HRESULT -
//
// History: Created Header byao 2/28/98 12:12:11 AM
//
//+---------------------------------------------------------------------------
HRESULT SetVendorSpecificInfo(::CString& strValue,
DWORD& dVendorId,
BOOL& fNonRFC,
DWORD& dFormat,
DWORD& dType,
::CString& strDispValue)
{
TRACE(_T("::SetVendorSpecificInfo()\n"));
USES_CONVERSION;
::CString strVSAType;
::CString strVSALen;
::CString strVSAValue;
::CString strVendorId;
::CString strPrefix;
TCHAR tszTempStr[256];
DWORD dwIndex;
wsprintf(tszTempStr, _T("%08X"), dVendorId);
_tcsupr(tszTempStr);
strValue = tszTempStr; // vendor ID first
if ( !fNonRFC )
{
// RFC compatible format
// prefix determined by type
// 1. VendorType -- an integer between 1-255
wsprintf(tszTempStr, _T("%02X"), dType);
strVSAType = tszTempStr;
// 2. Vendor Format: string, raw or hexadecimal
switch (dFormat)
{
case 0: // string
wsprintf(tszTempStr, _T("%02X"), _tcslen(strDispValue)+2);
strVSALen = tszTempStr;
/* removed per discussion with MKarki on 5/21/98.
String will be saved in original format
for (dwIndex=0; dwIndex<_tcslen(strDispValue); dwIndex++)
{
wsprintf(tszTempStr, _T("%02X"), ((LPCTSTR)strDispValue)[dwIndex]);
strVSAValue += tszTempStr;
}
*/
strVSAValue = strDispValue;
strPrefix = _T("01");
break;
case 3: // IP address : added F; 211265
// the display string is in a.b.c.d format, we need to save it as decimal format
//
{
// ip adress control
unsigned long IpAddr = inet_addr(T2A(strDispValue));
IpAddr = htonl(IpAddr);
strPrefix = _T("04");
wsprintf(tszTempStr, _T("%08lX"), IpAddr);
strVSAValue = tszTempStr;
// length
wsprintf(tszTempStr, _T("%02X"), L_INT_SIZE_BYTES + 2);
strVSALen = tszTempStr;
}
break;
case 1: // raw -- decimal or hexadecimal (0x... format)
if (_tcsstr(strDispValue, _T("0x")) != NULL ||
_tcsstr(strDispValue, _T("0X")) != NULL)
{
// hexadecimal
strVSAValue = strDispValue;
}
else
{
//todo: hexLarge???
wsprintf(tszTempStr, _T("%08lX"), _ttol(strDispValue));
strVSAValue = tszTempStr;
}
// length
wsprintf(tszTempStr, _T("%02X"), L_INT_SIZE_BYTES + 2);
strVSALen = tszTempStr;
strPrefix = _T("02");
break;
case 2: // hexadecimal format
wsprintf(tszTempStr, _T("%02X"), _tcslen(strDispValue)/2+2);
strVSALen = tszTempStr;
strVSAValue = strDispValue;
strPrefix = _T("03");
break;
break;
}
if(strDispValue.IsEmpty()) // special case for nothing for value
{
strVSALen = _T("02");
strVSAValue = _T("");
}
strVSAValue = strVSAType + strVSALen + strVSAValue;
}
else
{
strPrefix = _T("00");
strVSAValue = strDispValue;
}
strValue += strVSAValue;
strValue = strPrefix + strValue;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Data validation and conversion routines: hexadecimal string to integer
// decimal string to integer
//
//+---------------------------------------------------------------------------
#define ISSPACE(ch) ( ( ch==_T(' ') ) || ( ch==_T('\t') ) )
//+---------------------------------------------------------------------------
//
// Function: 'Decimal
//
// Synopsis: Check whether a string is a valid 4-BYTE decimal integer
//
// Arguments: LPCTSTR tszStr - input string
// BOOL fUnsigned - whether this is an unsigned integer
// long *pdValue - return the integer value back here
//
// Returns: BOOL - TRUE: valid decimal integer
// FALSE: otherwise
//
// History: Created Header byao 5/22/98 2:14:14 PM
//
//+---------------------------------------------------------------------------
BOOL IsValidDecimal(LPCTSTR tszStr, BOOL fUnsigned, long *pdValue)
{
if ( !tszStr )
{
return FALSE;
}
*pdValue = 0;
// first, skip the white space
while ( *tszStr && ISSPACE(*tszStr) )
{
tszStr++;
}
if ( ! (*tszStr) )
{
// string has ended already -- which means this string has only
// white space in it
return FALSE;
}
if (_tcslen(tszStr)>11)
{
//
// since we only deal with 4-byte integer here, the standard value range
// is : -2147483648 to 2147483647;
// For unsigned number, that puts us to 0 to 4294967295, which has
// maximum length 10.
//
return FALSE;
}
//
// negative integer?
//
BOOL fNegative = FALSE;
if ( *tszStr == _T('-') )
{
if ( fUnsigned )
{
return FALSE;
}
fNegative = TRUE;
tszStr++;
}
double dbTemp = 0; // we use a temporary double variable here
// so we can check whether the number is out of bounds
while ( *tszStr )
{
if ( *tszStr <= '9' && *tszStr >='0' )
{
dbTemp = dbTemp*10 + (*tszStr - '0');
}
else
{
return FALSE;
}
tszStr++;
}
if ( fUnsigned && dbTemp > UINT_MAX )
{
// out of range
return FALSE;
}
if ( !fUnsigned && fNegative )
{
// negative number??
dbTemp = (-dbTemp);
}
if ( !fUnsigned && ( dbTemp < INT_MIN || dbTemp > INT_MAX ) )
{
// integer out of range
return FALSE;
}
*pdValue = (long)dbTemp;
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: DDV_IntegerStr
//
// Synopsis: custom data verification routine: an integer string.
// the string must be consisted of integer only and must be
// in the right range for 4-byte integer
//
// Arguments: CDataExchange* pDX - data exchange context
// ::CString& strText - string to verify
//
// Returns: void -
//
// History: Created Header byao 3/10/98 11:04:58 PM
//
//+---------------------------------------------------------------------------
void DDV_IntegerStr(CDataExchange* pDX, ::CString& strText)
{
TRACE(_T("DDV_IntegerStr"));
TCHAR wzMessage[MAX_PATH];
::CString strMessage;
int nIndex;
long lTempValue;
BOOL fValid = IsValidDecimal((LPCTSTR)strText, FALSE, &lTempValue);
if ( !fValid )
{
// invalid data
ShowErrorDialog(pDX->m_pDlgWnd->GetSafeHwnd(), IDS_IAS_ERR_INVALIDINTEGER, NULL);
pDX->Fail();
return;
}
TRACE(_T("Valid integer: %ws\n"), (LPCTSTR)strText);
}
//+---------------------------------------------------------------------------
//
// Function: DDV_Unsigned_IntegerStr
//
// Synopsis: custom data verification routine: an unsigned integer string.
// the string must be consisted of integer only and must be in
// the range for a 4-byte unsigned integer
//
// Arguments: CDataExchange* pDX - data exchange context
// ::CString& strText - string to verify
//
// Returns: void -
//
// History: Created Header byao 5/22/98 11:04:58 PM
//
//+---------------------------------------------------------------------------
void DDV_Unsigned_IntegerStr(CDataExchange* pDX, ::CString& strText)
{
TRACE(_T("DDV_Unsigned_IntegerStr\n"));
TCHAR wzMessage[MAX_PATH];
::CString strMessage;
int nIndex;
long lTempValue;
BOOL fValid = IsValidDecimal((LPCTSTR)strText, TRUE, &lTempValue);
if ( !fValid )
{
// invalid data
ShowErrorDialog(pDX->m_pDlgWnd->GetSafeHwnd(), IDS_IAS_ERR_INVALID_UINT, NULL);
pDX->Fail();
return;
}
TRACE(_T("Valid integer: %ws\n"), (LPCTSTR)strText);
}
//+---------------------------------------------------------------------------
//
// Function: GetValidVSAHexString
//
// Synopsis: check whether the input string is a valid VSA hexadecimal string
// and return a pointer to where the string actually starts
//
// A valid VSA hexadecimal string must meet the following criteria:
// MAM 09/15/98 - _may_ start with 0x -- see 203334 -- we don't require 0x anymore.
// 1) _may_ start with 0x (no preceding white space)
// 2) contains only valid hexadecimal digits
// 3) contains even number of digits
// 4) maximum string length is 246.
//
// Arguments: LPCTSTR tszStr - input string
//
// Returns: NULL: invalid VSA hex string
// otherwise return a pointer to the first character of the string
//
// e.g, if the string is: " 0xabcd", then return "abcd"
//
// History: Created Header byao 5/22/98 4:06:57 PM
//
//+---------------------------------------------------------------------------
LPTSTR GetValidVSAHexString(LPCTSTR tszStr)
{
LPTSTR tszStartHex = NULL;
if ( !tszStr )
{
return NULL;
}
// Maximum length: 246.
// We'll check using this below once we've dispensed with
// any "0x" prefix if it exists.
int iMaxLength = 246;
// skip the white space
while ( *tszStr && ISSPACE(*tszStr) )
{
tszStr++;
}
// MAM 09/15/98 - _may_ start with 0x -- see 203334 -- we don't require 0x anymore.
//
// does it start with 0x?
//
if ( tszStr[0]==_T('0') )
{
// If it starts with '0x', skip these two characters.
if ( tszStr[1] == _T('x') || tszStr[1] == _T('X') )
{
// Skip "0x" prefix.
tszStr++;
tszStr++;
}
}
// Check whether exceeds iMaxLength now that we have dispensed
// with "0x" if it was prefixed to the string.
// Also check for minimum length: 2 (must have at least some data)
// Also it must be even number length.
int iLength = _tcslen(tszStr);
if ( iLength > iMaxLength || iLength < 2 || iLength % 2 )
{
return NULL;
}
tszStartHex = (LPTSTR)tszStr;
if ( !(*tszStartHex) )
{
// there's nothing followed by the prefix
return NULL;
}
// does it contain any invalid character?
while ( *tszStr )
{
if (!
((*tszStr >= _T('0') && *tszStr <= _T('9')) ||
(*tszStr >= _T('a') && *tszStr <= _T('f')) ||
(*tszStr >= _T('A') && *tszStr <= _T('F'))
)
)
{
return NULL;
}
tszStr++;
}
// return the pointer
return tszStartHex;
}
//+---------------------------------------------------------------------------
//
// Function: DDV_VSA_HexString
//
// Synopsis: custom data verification routine: VSA hexadecimal string
// A valid VSA hexadecimal string must meet the following criteria:
// MAM 09/15/98 - NO! see 203334 -- we don't require 0x anymore.
// 1) start with 0x (no preceding white space)
// 2) contains only valid hexadecimal digits
// 3) contains even number of digits
// 4) maximum string length is 246.
//
// Arguments: CDataExchange* pDX - data exchange context
// ::CString& strText - string to verify
//
// Returns: void -
//
// History: Created Header byao 5/22/98 11:04:58 PM
//
//+---------------------------------------------------------------------------
void DDV_VSA_HexString(CDataExchange* pDX, ::CString& strText)
{
TRACE(_T("::DDV_VSA_HexString()\n"));
TCHAR wzMessage[MAX_PATH];
::CString strMessage;
LPTSTR tszHex = GetValidVSAHexString( (LPCTSTR)strText );
if ( !tszHex )
{
// invalid data
ShowErrorDialog(pDX->m_pDlgWnd->GetSafeHwnd(), IDS_IAS_ERR_INVALID_VSAHEX, NULL);
pDX -> Fail();
}
else
{
strText = tszHex;
TRACE(_T("Valid VSA hex string %ws\n"), (LPCTSTR)strText);
}
}
//+---------------------------------------------------------------------------
//
// Function: DDV_BoolStr
//
// Synopsis: custom data verification routine: a boolean string.
// the only valid values are "T", "F", "TRUE", "FALSE"
//
// Arguments: CDataExchange* pDX - data exchange context
// ::CString& strText - string to verify
//
// Returns: void -
//
// History: Created Header byao 3/10/98 11:04:58 PM
//
//+---------------------------------------------------------------------------
void DDV_BoolStr(CDataExchange* pDX, ::CString& strText)
{
TRACE(_T("::DDV_BoolStr()\n"));
TCHAR wzMessage[MAX_PATH];
::CString strMessage;
if (! ( _wcsicmp(strText, _T("TRUE")) == 0 || _wcsicmp(strText, _T("FALSE") ) == 0
))
{
// invalid data
ShowErrorDialog(pDX->m_pDlgWnd->GetSafeHwnd(), IDS_IAS_ERR_INVALIDBOOL, NULL);
pDX -> Fail();
}
TRACE(_T("Valid bool value %ws\n"), (LPCTSTR)strText);
}
//////////////////////////////////////////////////////////////////////////////
TCHAR HexChar[] = {
_T('0'), _T('1'), _T('2'), _T('3'), _T('4'), _T('5'), _T('6'), _T('7'),
_T('8'), _T('9'), _T('a'), _T('b'), _T('c'), _T('d'), _T('e'), _T('f')
};
// convert binary data to hex string, bytes 01 01 01 --> _T("0x010101")
size_t BinaryToHexString(char* pData, size_t cch, TCHAR* pTStr, size_t ctLen)
{
int nRequiredLen = (cch * 2 + 2 + 1); // two WCHAR for 1 byte, and 0x at begining and , \0 at end
if(ctLen == 0)
return nRequiredLen;
if(ctLen < nRequiredLen || pTStr == NULL || pData == NULL)
return 0;
// make the output string empty
if(cch == 0)
{
*pTStr = 0;
return 1;
}
// do converstion now
*pTStr = _T('0');
*(pTStr + 1) = _T('x');
// walk through each byte
for(int i = 0; i < cch; i++)
{
int h = ((*(pData + i) & 0xf0) >> 4);
// high 4 bits
*(pTStr + i * 2 + 2) = HexChar[h];
// low 4 bits
h = (*(pData + i) & 0x0f);
*(pTStr + i * 2 + 1+ 2 ) = HexChar[h];
}
*(pTStr + nRequiredLen - 1 ) = _T('\0');
return nRequiredLen;
}
//
#define HexValue(h) \
( ((h) >= _T('a') && (h) <= _T('f')) ? ((h) - _T('a') + 0xa) : \
( ((h) >= _T('A') && (h) <= _T('F')) ? ((h) - _T('A') + 0xa) : \
( ((h) >= _T('0') && (h) <= _T('9')) ? ((h) - _T('0')) : 0)))
// convert HexString to binary value: _T("0x010101") convert to 3 bytes 01 01 01
size_t HexStringToBinary(TCHAR* pStr, char* pData, size_t cch)
{
// need to convert to binary before passing into SafeArray
pStr = GetValidVSAHexString(pStr);
if(pStr == NULL) return 0;
size_t nLen = _tcslen(pStr) / 2;
// if inquery for length
if(cch == 0) return nLen;
// get the binary
for(int i = 0; i < nLen; i++)
{
char h, l;
// high 4 bits
h = (char)HexValue(pStr[i * 2]);
// low 4 bits
l = (char)HexValue(pStr[i * 2 + 1]);
*(pData + i) = (h << 4) + l;
}
return nLen;
}