// Class to enumerate Naming contexts // Copyright (c) 2001 Microsoft Corporation // Nov 2001 lucios // This class is an informal gathering of all // that is necessary to enummerate naming contexts // in order to fix the bug 472876 // NTRAID#NTBUG9-472876-2001/11/30-lucios #include "pch.h" #include #include "enumncs.hpp" #define BREAK_ON_FAILED_HRESULT(hr) if(FAILED(hr)) break; // connects to "LDAP://RootDSE" HRESULT enumNCsAux::connectToRootDse(IADs** pDSO) { HRESULT hr= AdminToolsOpenObject ( L"LDAP://RootDSE", 0, 0, ADS_SECURE_AUTHENTICATION, IID_IADs, reinterpret_cast(pDSO) ); return hr; } // gets any property as a variant HRESULT enumNCsAux::getProperty ( const wstring &name, CComVariant &property, IADs *pADObj ) { return ( pADObj->Get ( CComBSTR(name.c_str()), &property ) ); } // Gets a string property HRESULT enumNCsAux::getStringProperty ( const wstring &name, wstring &property, IADs *pADObj ) { CComVariant propertyVar; HRESULT hr = getProperty(name,propertyVar,pADObj); if(FAILED(hr)) return(hr); if(propertyVar.vt!=VT_BSTR) return E_FAIL; property= V_BSTR(&propertyVar); return S_OK; } // Gets a long property HRESULT enumNCsAux::getLongProperty ( const wstring &name, long &property, IADs *pADObj ) { CComVariant propertyVar; HRESULT hr = getProperty(name,propertyVar,pADObj); if(FAILED(hr)) return(hr); if(propertyVar.vt!=VT_I4) return E_FAIL; property= V_I4(&propertyVar); return S_OK; } // Gets CN=Configuration from a connected rootDse IADs HRESULT enumNCsAux::getConfigurationDn(wstring &confDn,IADs *pDSO) { return ( getStringProperty ( LDAP_OPATT_CONFIG_NAMING_CONTEXT_W, confDn, pDSO ) ); } // gets the IADsContainer from a distinguished name path HRESULT enumNCsAux::getContainer(const wstring &path,IADsContainer **pCont) { return ( ADsGetObject ( path.c_str(), IID_IADsContainer, reinterpret_cast(pCont) ) ); } // Gets the IEnumVARIANT from a container HRESULT enumNCsAux::getContainerEnumerator ( IADsContainer* pPart, IEnumVARIANT** ppiEnum ) { HRESULT hr=S_OK; CComPtr spUnkEnum; do { hr=pPart->get__NewEnum(&spUnkEnum); BREAK_ON_FAILED_HRESULT(hr); CComQIPtr spRet(spUnkEnum); if(!spRet) return E_FAIL; *ppiEnum = spRet.Detach(); } while(0); return hr; } // calls IADsObj->get_Class and returns a wstring from it HRESULT enumNCsAux::getObjectClass ( wstring &className, IADs *IADsObj ) { BSTR classBstr; HRESULT hr=IADsObj->get_Class(&classBstr); if(FAILED(hr)) return hr; className=(const wchar_t*)classBstr; return S_OK; } // Gets the IDispatch from the variant and queries // for a IADs(returned in IADsObj) HRESULT enumNCsAux::getIADsFromDispatch ( const CComVariant &dispatchVar, IADs **ppiIADsObj ) { if(dispatchVar.vt!=VT_DISPATCH) return E_INVALIDARG; IDispatch *pDisp=V_DISPATCH(&dispatchVar); if(pDisp==NULL) return E_FAIL; CComQIPtr spRet(pDisp); if(!spRet) return E_FAIL; *ppiIADsObj=spRet.Detach(); return S_OK; } // Enumerate the names of the naming contexts. // The names are from the crossRef objects in CN=configuration,CN=Partitions // that have FLAG_CR_NTDS_DOMAIN set. The property used to extract the names // is NCName. HRESULT enumNCsAux::enumerateNCs(set &ncs) { HRESULT hr=S_OK; try { ncs.clear(); do { // first of all: connect. CComPtr spDSO; //for rootDse hr=connectToRootDse(&spDSO); BREAK_ON_FAILED_HRESULT(hr); wstring partPath; // then get the path to CN=Configuration,... hr=getConfigurationDn(partPath,spDSO); BREAK_ON_FAILED_HRESULT(hr); // .. and complete it with CN=Partitions partPath=L"LDAP://CN=Partitions,"+partPath; // then get the container for the partition.. CComPtr spPart; // or the partitions container hr=getContainer(partPath,&spPart); BREAK_ON_FAILED_HRESULT(hr); // and enumerate the partition container CComPtr spPartEnum;//for the enumeration of partition objects hr=getContainerEnumerator(spPart,&spPartEnum); BREAK_ON_FAILED_HRESULT(hr); CComVariant partitionVar; ULONG lFetch=0; while ( S_OK == (hr=spPartEnum->Next(1,&partitionVar,&lFetch)) ) { if (lFetch != 1) continue; CComPtr spPartitionObj; hr=getIADsFromDispatch(partitionVar,&spPartitionObj); BREAK_ON_FAILED_HRESULT(hr); do { wstring className; HRESULT hrAux; // Not getting a property/class is not a fatal error // so we use an auxilliary HRESULT hrAux hrAux=getObjectClass(className,spPartitionObj); BREAK_ON_FAILED_HRESULT(hrAux); if(_wcsicmp(className.c_str(),L"crossref")==0) { long systemFlags; hrAux=getLongProperty ( L"systemFlags", systemFlags, spPartitionObj ); BREAK_ON_FAILED_HRESULT(hrAux); if ( (systemFlags & FLAG_CR_NTDS_DOMAIN) == FLAG_CR_NTDS_DOMAIN ) { wstring NCName; hrAux=getStringProperty ( L"NCName", NCName, spPartitionObj ); BREAK_ON_FAILED_HRESULT(hrAux); ncs.insert(NCName); } } } while(0); BREAK_ON_FAILED_HRESULT(hr); } if(SUCCEEDED(hr)) hr=S_OK; BREAK_ON_FAILED_HRESULT(hr); } while(0); } catch( const std::bad_alloc& ) { hr=E_FAIL; } return hr; }