//--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1996 // // File: cenumns.cxx // // Contents: LDAP Enumerator Code // // History: //---------------------------------------------------------------------------- #include "ldap.hxx" #pragma hdrstop DWORD GetDefaultServer( DWORD dwPort, BOOL fVerify, LPWSTR szDomainDnsName, LPWSTR szServerName, BOOL fWriteable ); DWORD GetDefaultLdapServer( LPWSTR Addresses[], LPDWORD Count, BOOL Verify, DWORD dwPort ) ; //+--------------------------------------------------------------------------- // // Function: CLDAPNamespaceEnum::Create // // Synopsis: // // Arguments: [pCollection] // [ppEnumVariant] // // Returns: HRESULT // // Modifies: // // History: 01-30-95 krishnag Created. // //---------------------------------------------------------------------------- HRESULT CLDAPNamespaceEnum::Create( CLDAPNamespaceEnum FAR* FAR* ppenumvariant, VARIANT var, CCredentials& Credentials, LPTSTR pszNamespace ) { HRESULT hr = S_OK; CLDAPNamespaceEnum FAR* penumvariant = NULL; penumvariant = new CLDAPNamespaceEnum(); if (penumvariant == NULL){ hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } hr = ObjectTypeList::CreateObjectTypeList( var, &penumvariant->_pObjList ); BAIL_ON_FAILURE(hr); penumvariant->_Credentials = Credentials; penumvariant->_pszNamespace = AllocADsStr(pszNamespace); if (!(penumvariant->_pszNamespace)) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } if( IsGCNamespace(pszNamespace) ) penumvariant->_dwPort = (DWORD) USE_DEFAULT_GC_PORT; else penumvariant->_dwPort = (DWORD) USE_DEFAULT_LDAP_PORT; *ppenumvariant = penumvariant; RRETURN(hr); error: if (penumvariant) { delete penumvariant; } RRETURN_EXP_IF_ERR(hr); } //+--------------------------------------------------------------------------- // // Function: CLDAPNamespaceEnum::CLDAPNamespaceEnum // // Synopsis: // // // Arguments: // // // Returns: // // Modifies: // // History: 01-30-95 krishnag Created. // //---------------------------------------------------------------------------- CLDAPNamespaceEnum::CLDAPNamespaceEnum() { _dwIndex = 0; _pObjList = NULL; } //+--------------------------------------------------------------------------- // // Function: CLDAPNamespaceEnum::~CLDAPNamespaceEnum // // Synopsis: // // // Arguments: // // Returns: // // Modifies: // // History: 01-30-95 krishnag Created. // //---------------------------------------------------------------------------- CLDAPNamespaceEnum::~CLDAPNamespaceEnum() { if (_pszNamespace) FreeADsMem(_pszNamespace); if ( _pObjList ) delete _pObjList; } //+--------------------------------------------------------------------------- // // Function: CLDAPNamespaceEnum::Next // // Synopsis: Returns cElements number of requested ADs objects in the // array supplied in pvar. // // Arguments: [cElements] -- The number of elements requested by client // [pvar] -- ptr to array of VARIANTs to for return objects // [pcElementFetched] -- if non-NULL, then number of elements // -- actually returned is placed here // // Returns: HRESULT -- S_OK if number of elements requested are returned // -- S_FALSE if number of elements is < requested // // Modifies: // // History: // //---------------------------------------------------------------------------- STDMETHODIMP CLDAPNamespaceEnum::Next( ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched ) { ULONG cElementFetched = 0; HRESULT hr = S_OK; if ( _dwIndex > 0 ) // only your default ds will be returned, one element { if (pcElementFetched) *pcElementFetched = 0; RRETURN(S_FALSE); } hr = EnumObjects( cElements, pvar, &cElementFetched ); if (pcElementFetched) { *pcElementFetched = cElementFetched; } RRETURN_EXP_IF_ERR(hr); } HRESULT CLDAPNamespaceEnum::EnumObjects( ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched ) { HRESULT hr = S_FALSE; IDispatch *pDispatch = NULL; DWORD i = 0; while (i < cElements) { if ( _dwIndex > 0 ) // only your default ds will be returned, // i.e. one element only { hr = S_FALSE; break; } _dwIndex++; hr = GetTreeObject(&pDispatch); if (hr == S_FALSE) { break; } VariantInit(&pvar[i]); pvar[i].vt = VT_DISPATCH; pvar[i].pdispVal = pDispatch; (*pcElementFetched)++; i++; } RRETURN_EXP_IF_ERR(hr); } HRESULT CLDAPNamespaceEnum::GetTreeObject( IDispatch ** ppDispatch ) { DWORD err = NO_ERROR; HRESULT hr = S_OK; LPTSTR *aValuesNamingContext = NULL; LPTSTR *aValuesObjectClass = NULL; int nCountValues = 0; TCHAR *pszLDAPPathName = NULL; TCHAR szADsClassName[64]; WCHAR szDomainName[MAX_PATH]; WCHAR szServerName[MAX_PATH]; TCHAR *pszNewADsPath = NULL; TCHAR *pszLast = NULL; LPWSTR pszNamingContext = NULL; LPWSTR pszNewADsParent = NULL; LPWSTR pszNewADsCommonName = NULL; DWORD fVerify = FALSE; *ppDispatch = NULL; ADS_LDP *ld = NULL; BOOL fGCDefaulted = FALSE; // // Now send back the current object // RetryGetDefaultServer: if ( err = GetDefaultServer( _dwPort, fVerify, szDomainName, szServerName, TRUE) ){ hr = HRESULT_FROM_WIN32(err); BAIL_ON_FAILURE(hr); } // // Read the naming contexts // if (_dwPort == USE_DEFAULT_GC_PORT) { fGCDefaulted = TRUE; pszNamingContext = NULL; } else { pszNamingContext = TEXT(LDAP_OPATT_DEFAULT_NAMING_CONTEXT); } hr = LdapOpenObject2( szDomainName, szServerName, NULL, &ld, _Credentials, _dwPort ); if (((hr == HRESULT_FROM_WIN32(ERROR_BAD_NETPATH)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_SERVER_DOWN))) && !fVerify) { fVerify = TRUE; goto RetryGetDefaultServer ; } BAIL_ON_FAILURE(hr); if (!fGCDefaulted) { hr = LdapReadAttributeFast( ld, NULL, pszNamingContext, &aValuesNamingContext, &nCountValues ); BAIL_ON_FAILURE(hr); if ( nCountValues == 0 ) { // // The hr will be modified at the end of the function to S_FALSE // in case of error BAIL_ON_FAILURE(hr = E_FAIL); } hr = BuildADsPathFromLDAPPath2( FALSE, //Server is present till DSSnapin Works _pszNamespace, szDomainName, _dwPort, fGCDefaulted ? TEXT("") : aValuesNamingContext[0], &pszNewADsPath ); } else { // // In this case we want to force it to be GC://yourDomain // so that all searches will be truly global // hr = BuildADsPathFromLDAPPath2( TRUE, // server is present _pszNamespace, szDomainName, _dwPort, TEXT(""), &pszNewADsPath ); } BAIL_ON_FAILURE(hr); // this part is common to both code paths hr = BuildADsParentPath( pszNewADsPath, &pszNewADsParent, &pszNewADsCommonName ); BAIL_ON_FAILURE(hr); nCountValues = 0; // // Read the object class of the path if necessary // if (!fGCDefaulted) { hr = LdapReadAttributeFast( ld, aValuesNamingContext[0], L"objectClass", &aValuesObjectClass, &nCountValues ); BAIL_ON_FAILURE(hr); } if ( nCountValues == 0 && !fGCDefaulted) { // This object exists but does not contain objectClass attribute // which is required for all DS objects. Hence, ignore the object // and return error. hr = E_ADS_BAD_PATHNAME; BAIL_ON_FAILURE(hr); } // // Create the object // if (fGCDefaulted) { hr = CLDAPGenObject::CreateGenericObject( pszNewADsParent, pszNewADsCommonName, L"top", _Credentials, ADS_OBJECT_BOUND, IID_IUnknown, (void **) ppDispatch ); } else { // // Send all the classes so we can load all extensions // hr = CLDAPGenObject::CreateGenericObject( pszNewADsParent, pszNewADsCommonName, aValuesObjectClass, nCountValues, _Credentials, ADS_OBJECT_BOUND, IID_IDispatch, (void **) ppDispatch ); } BAIL_ON_FAILURE(hr); error: if ( aValuesNamingContext ) LdapValueFree( aValuesNamingContext ); if ( aValuesObjectClass ) LdapValueFree( aValuesObjectClass ); if ( pszNewADsPath ) FreeADsStr( pszNewADsPath ); if ( pszNewADsParent) { FreeADsStr(pszNewADsParent); } if (pszNewADsCommonName) { FreeADsStr(pszNewADsCommonName); } if ( ld ){ LdapCloseObject( ld ); } RRETURN_ENUM_STATUS(hr); }