////////////////////////////////////////////////////////////////////////////// // // Copyright (C) Microsoft Corporation // // Module Name: // // IASAttrList.cpp // //Abstract: // // Implementation of the CIASAttrList class. // CIASAttrList: a list of IIASAttributeInfo interface pointers // ////////////////////////////////////////////////////////////////////////////// #include "precompiled.h" #include "IasAttrList.h" #include "iasdebug.h" #include "SafeArray.h" #include "vendors.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CIASAttrList::CIASAttrList() { TRACE_FUNCTION("CIASAttrList::CIASAttrList"); m_fInitialized = FALSE; } CIASAttrList::~CIASAttrList() { TRACE_FUNCTION("CIASAttrList::~CIASAttrList"); } //+--------------------------------------------------------------------------- // // Function: CIASAttrList::CreateAttribute // // Synopsis: Create and initialize an IIASAttributeInfo object // // Arguments: pIDictionary - Dictionary pointer // AttrId - Attribute id // tszAttrName - attribute name // // // Returns: IIASAttributeInfo* - a pointer to the newly created attribute object // NULL if anything fails // // History: Created Header byao 3/20/98 11:16:07 AM // //+--------------------------------------------------------------------------- IIASAttributeInfo* CIASAttrList::CreateAttribute( ISdoDictionaryOld* pIDictionary, ATTRIBUTEID AttrId, LPTSTR tszAttrName ) { TRACE_FUNCTION("CIASAttrList::CreateAttribute"); // // create a safearray to get the attribuet information // CSafeArray InfoIds = Dim(4); InfoIds.Lock(); InfoIds[0] = SYNTAX; InfoIds[1] = RESTRICTIONS; InfoIds[2] = VENDORID; InfoIds[3] = DESCRIPTION; InfoIds.Unlock(); CComVariant vInfoIds, vInfoValues; SAFEARRAY sa = (SAFEARRAY)InfoIds; V_VT(&vInfoIds) = VT_ARRAY; V_ARRAY(&vInfoIds) = &sa; // get the attribuet info HRESULT hr = S_OK; hr = pIDictionary->GetAttributeInfo(AttrId, &vInfoIds, &vInfoValues); if ( FAILED(hr) ) { ErrorTrace(ERROR_NAPMMC_IASATTR,"GetAttributeInfo() failed, err = %x", hr); ShowErrorDialog(NULL , IDS_ERROR_SDO_ERROR_GETATTRINFO , NULL , hr ); return NULL; } _ASSERTE(V_VT(&vInfoValues) == (VT_ARRAY|VT_VARIANT) ); CSafeArray InfoValues = V_ARRAY(&vInfoValues); InfoValues.Lock(); ATTRIBUTESYNTAX asSyntax= (ATTRIBUTESYNTAX) V_I4(&InfoValues[0]); DWORD dwRestriction = V_I4(&InfoValues[1]); DWORD dwVendorId = V_I4(&InfoValues[2]); CComBSTR bstrDescription= V_BSTR(&InfoValues[3]); InfoValues.Unlock(); // // check whether tszDESC could be NULL -- this happens when there's no // description for this attribute. // if ( ! bstrDescription ) { bstrDescription = L" "; } // create the attribute ONLY if it can be in a profile or a condition const DWORD flags = ALLOWEDINCONDITION | ALLOWEDINPROFILE | ALLOWEDINPROXYCONDITION | ALLOWEDINPROXYPROFILE; if (!( dwRestriction & flags )) { // don't create this attribute 'cause it's useless for us return NULL; } CComPtr spIASAttributeInfo; try { HRESULT hr; // Decide which kind of AttributeInfo object we will need to pass attribute // info around in -- enumerable attributes are a special case and need to // support the IIASEnumerableAttributeInfo interface. if ( asSyntax == IAS_SYNTAX_ENUMERATOR ) { hr = CoCreateInstance( CLSID_IASEnumerableAttributeInfo, NULL, CLSCTX_INPROC_SERVER, IID_IIASAttributeInfo, (LPVOID *) &spIASAttributeInfo ); } else { hr = CoCreateInstance( CLSID_IASAttributeInfo, NULL, CLSCTX_INPROC_SERVER, IID_IIASAttributeInfo, (LPVOID *) &spIASAttributeInfo ); } if( FAILED(hr) ) return NULL; // Determine the prog ID for the editor which should be used to edit // this attribute. Make a decision based on attribute ID and/or syntax. CComBSTR bstrEditorProgID; if ( AttrId == RADIUS_ATTRIBUTE_VENDOR_SPECIFIC ) { bstrEditorProgID = L"IAS.VendorSpecificAttributeEditor"; } else if( (AttrId == MS_ATTRIBUTE_QUARANTINE_IPFILTER) || (AttrId == MS_ATTRIBUTE_FILTER) ) { bstrEditorProgID = L"IAS.IPFilterAttributeEditor"; } else { switch(asSyntax) { case IAS_SYNTAX_ENUMERATOR: { bstrEditorProgID = L"IAS.EnumerableAttributeEditor"; break; } case IAS_SYNTAX_INETADDR: { bstrEditorProgID = L"IAS.IPAttributeEditor"; break; } case IAS_SYNTAX_BOOLEAN: { bstrEditorProgID = L"IAS.BooleanAttributeEditor"; break; } default: { bstrEditorProgID = L"IAS.StringAttributeEditor"; } } } // Store the editor Prog ID in the attribute info object. hr = spIASAttributeInfo->put_EditorProgID( bstrEditorProgID ); if( FAILED( hr ) ) throw hr; // Store the rest of the attribute information. hr = spIASAttributeInfo->put_AttributeID(AttrId); if( FAILED( hr ) ) throw hr; hr = spIASAttributeInfo->put_AttributeSyntax(asSyntax); if( FAILED( hr ) ) throw hr; hr = spIASAttributeInfo->put_AttributeRestriction(dwRestriction); if( FAILED( hr ) ) throw hr; hr = spIASAttributeInfo->put_VendorID(dwVendorId); if( FAILED( hr ) ) throw hr; hr = spIASAttributeInfo->put_AttributeDescription( bstrDescription ); if( FAILED( hr ) ) throw hr; CComBSTR bstrName = tszAttrName; hr = spIASAttributeInfo->put_AttributeName( bstrName ); if( FAILED( hr ) ) throw hr; // Now get the vendor name and store in the attribute. CComBSTR bstrVendorName; CComPtr spIASNASVendors; hr = CoCreateInstance( CLSID_IASNASVendors, NULL, CLSCTX_INPROC_SERVER, IID_IIASNASVendors, (LPVOID *) &spIASNASVendors ); if( SUCCEEDED(hr) ) { LONG lIndex; hr = spIASNASVendors->get_VendorIDToOrdinal(dwVendorId, &lIndex); if( S_OK == hr ) { hr = spIASNASVendors->get_VendorName( lIndex, &bstrVendorName ); } else hr = ::MakeVendorNameFromVendorID(dwVendorId, &bstrVendorName ); } // Note: If any of the above calls to the Vendor object failed, // we will keep going, using a NULL vendor name. hr = spIASAttributeInfo->put_VendorName( bstrVendorName ); if( FAILED( hr ) ) throw hr; // Now store an string form describing the attribute syntax. CComBSTR bstrSyntax; // ISSUE: Should these all have been localized or are they some kind // of RADIUS RFC standard? I think they should have been loaded from resources. switch(asSyntax) { case IAS_SYNTAX_BOOLEAN : bstrSyntax = L"Boolean"; break; case IAS_SYNTAX_INTEGER : bstrSyntax = L"Integer"; break; case IAS_SYNTAX_ENUMERATOR : bstrSyntax = L"Enumerator"; break; case IAS_SYNTAX_INETADDR : bstrSyntax = L"InetAddr"; break; case IAS_SYNTAX_STRING : bstrSyntax = L"String"; break; case IAS_SYNTAX_OCTETSTRING : bstrSyntax = L"OctetString"; break; case IAS_SYNTAX_UTCTIME : bstrSyntax = L"UTCTime"; break; case IAS_SYNTAX_PROVIDERSPECIFIC : bstrSyntax = L"ProviderSpecific"; break; case IAS_SYNTAX_UNSIGNEDINTEGER : bstrSyntax = L"UnsignedInteger"; break; default : bstrSyntax = L"Unknown Type"; break; } hr = spIASAttributeInfo->put_SyntaxString( bstrSyntax ); if( FAILED(hr) ) throw hr; } catch (...) { _ASSERTE( FALSE ); ErrorTrace(ERROR_NAPMMC_IASATTRLIST, "Can't create the attribute ,err = %x", GetLastError()); return NULL; } // clean up -- we don't need to clean up vInfoIds. It's deleted by ~CSafeArray() // VariantClear(&vInfoValues); // // 3) get the value list for this attribute, if it's enumerator // if ( asSyntax == IAS_SYNTAX_ENUMERATOR ) { // get the enumerable list for this attribute CComVariant varValueIds, varValueNames; hr = pIDictionary->EnumAttributeValues(AttrId, &varValueIds, &varValueNames); if ( SUCCEEDED(hr) ) { _ASSERTE(V_VT(&varValueNames) == (VT_ARRAY|VT_VARIANT) ); _ASSERTE(V_VT(&varValueIds) & (VT_ARRAY|VT_I4) ); // Up above, if the attribute was enumerable, we created // an attribute info object which implements the IIASEnumerableAttributeInfo // interface. We query for this interface now // and load all the enumerates from pAttr into that // interface of the shema attribute. CComQIPtr< IIASEnumerableAttributeInfo, &IID_IIASEnumerableAttributeInfo > spIASEnumerableAttributeInfo( spIASAttributeInfo ); if( ! spIASEnumerableAttributeInfo ) return NULL; // Make sure that the list of enumerates in consistent. // There should be a 1-1 correspondence between ID's and description strings. //ISSUE: todo _ASSERTE( lSize == pAttr->m_arrValueIdList.GetSize() ); // get the safearray data CSafeArray ValueIds = V_ARRAY(&varValueIds); CSafeArray ValueNames = V_ARRAY(&varValueNames); ValueIds.Lock(); ValueNames.Lock(); int iSize = ValueIds.Elements(); for (int iValueIndex=0; iValueIndex < iSize; iValueIndex++) { // ISSUE: Make sure this deep copies the name. CComBSTR bstrValueName = V_BSTR(&ValueNames[iValueIndex]); hr = spIASEnumerableAttributeInfo->AddEnumerateDescription( bstrValueName ); if( FAILED( hr ) ) return NULL; VARIANT * pVar = &ValueIds[iValueIndex]; long lID = V_I4( pVar ); hr = spIASEnumerableAttributeInfo->AddEnumerateID( lID ); if( FAILED( hr ) ) return NULL; } ValueIds.Unlock(); ValueNames.Unlock(); } else { // can't get the list. //todo: need any action here? hr = S_OK; } } // Note: We have a bit of a RefCounting issue here. // As soon as we leave this function, desstructor for CComPtr // will be called, Release'ing the IIASAttributeInfo interface. // This will happen before the CComPtr on the other side has // had a chance to AddRef it. // As a temporary hack, we AddRef here and release on the other side. spIASAttributeInfo.p->AddRef(); return spIASAttributeInfo.p; } //+--------------------------------------------------------------------------- // // Function: Init // // Class: CIASAttrList // // Synopsis: Populate the condition attribute list. Do nothing // if the list is already populated // // Arguments: [in]ISdo *pIDictionarySdo: dictionary sdo // // Returns: HRESULT - // // History: Created Header byao 2/16/98 4:57:07 PM // //+--------------------------------------------------------------------------- HRESULT CIASAttrList::Init(ISdoDictionaryOld *pIDictionarySdo) { TRACE_FUNCTION("CIASAttrList::Init"); _ASSERTE( pIDictionarySdo != NULL ); if (m_fInitialized) { // // the list has already been populated -- do nothing // return S_OK; } // The push_back call below can throw an exception. try { // // Get all the attributes that can be used in a condition // int iIndex; HRESULT hr = S_OK; CComVariant vNames; CComVariant vIds; hr = pIDictionarySdo -> EnumAttributes(&vIds, &vNames); if ( FAILED(hr) ) { ErrorTrace(ERROR_NAPMMC_IASATTRLIST, "EnumAttributes() failed, err = %x", hr); ShowErrorDialog(NULL , IDS_ERROR_SDO_ERROR_ENUMATTR , NULL , hr ); return hr; } _ASSERTE(V_VT(&vIds) == (VT_ARRAY|VT_I4) ); _ASSERTE(V_VT(&vNames) == (VT_ARRAY|VT_VARIANT) ); CSafeArray AttrIds = V_ARRAY(&vIds); CSafeArray AttrNames = V_ARRAY(&vNames); AttrIds.Lock(); AttrNames.Lock(); for (iIndex = 0; iIndex < AttrIds.Elements(); iIndex++) { // create an attribute object DebugTrace(DEBUG_NAPMMC_IASATTRLIST, "Creating an attribute, name = %ws", V_BSTR(&AttrNames[iIndex]) ); _ASSERTE( V_BSTR(&AttrNames[iIndex]) ); CComPtr spAttributeInfo = CreateAttribute(pIDictionarySdo, (ATTRIBUTEID)AttrIds[iIndex], V_BSTR(&AttrNames[iIndex]) ); if ( ! spAttributeInfo ) { continue; // create the next attribute } // See note in CreateAttribute for why we Release here. spAttributeInfo.p->Release(); m_AttrList.push_back(spAttributeInfo); } // for AttrIds.Unlock(); AttrNames.Unlock(); m_fInitialized = TRUE; } catch(...) { return E_FAIL; } return S_OK; } //+--------------------------------------------------------------------------- // // Function: GetSize // // Class: CIASAttrList // // Synopsis: get the number of elements in the condition attribute list // // Arguments: None // // Returns: DWORD - list length // // History: Created Header byao 2/16/98 8:11:17 PM // //+--------------------------------------------------------------------------- DWORD CIASAttrList::size() const { if (!m_fInitialized) { ::MessageBox(NULL,L"populate the list first!", L"", MB_OK); return E_NOTIMPL; } else { return m_AttrList.size(); } } //+--------------------------------------------------------------------------- // // Function: operator[] // // Class: CIASAttrList // // Synopsis: get the condition attribute pointer at index [nIndex] // // Arguments: int nIndex - index // // Returns: IIASAttributeInfo* : pointer to a condition attribute object // // History: Created Header byao 2/16/98 8:16:37 PM // //+--------------------------------------------------------------------------- IIASAttributeInfo* CIASAttrList:: operator[] (int nIndex) const { if (!m_fInitialized) { ::MessageBox(NULL,L"populate the list first!", L"", MB_OK); return NULL; } else { _ASSERTE(nIndex >= 0 && nIndex < m_AttrList.size()); return m_AttrList[nIndex].p; } } //+--------------------------------------------------------------------------- // // Function: GetAt() // // Class: CIASAttrList // // Synopsis: get the condition attribute pointer at nIndex // // Arguments: int nIndex - index // // Returns: IIASAttributeInfo* : pointer to a condition attribute object // // History: Created Header byao 2/16/98 8:16:37 PM // //+--------------------------------------------------------------------------- IIASAttributeInfo* CIASAttrList:: GetAt(int nIndex) const { TRACE_FUNCTION("CIASAttrList::GetAt"); if (!m_fInitialized) { ErrorTrace(ERROR_NAPMMC_IASATTRLIST, "The list is NOT initialized!"); return NULL; } else { _ASSERTE(nIndex >= 0 && nIndex < m_AttrList.size()); return m_AttrList[nIndex].p; } } //+--------------------------------------------------------------------------- // // Function: CIASAttrList::Find // // Synopsis: Find an attribute based on attribute ID // // Arguments: ATTRIBUTEID AttrId - attribute id // // Returns: int - index in the list // // History: Created Header 2/22/98 1:52:36 AM // //+--------------------------------------------------------------------------- int CIASAttrList::Find(ATTRIBUTEID AttrId) { int iIndex; // The operator [] below can throw exceptions. try { for (iIndex=0; iIndexget_AttributeID( &id ); if( id == AttrId ) { // found return iIndex; } } } catch(...) { // Just catch the exception -- we'll return -1 below. } // not found return -1; }