/**********************************************************************/ /** 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 #include #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; }