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