//--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1995 // // File: cenumdom.cxx // // Contents: Windows NT 3.5 Domain Enumeration Code // // CWinNTDomainEnum::CWinNTDomainEnum() // CWinNTDomainEnum::CWinNTDomainEnum // CWinNTDomainEnum::EnumObjects // CWinNTDomainEnum::EnumObjects // // History: //---------------------------------------------------------------------------- #include "winnt.hxx" #pragma hdrstop //+--------------------------------------------------------------------------- // // Function: CWinNTEnumVariant::Create // // Synopsis: // // Arguments: [pCollection] // [ppEnumVariant] // // Returns: HRESULT // // Modifies: // // History: 01-30-95 krishnag Created. // //---------------------------------------------------------------------------- HRESULT CWinNTDomainEnum::Create( CWinNTDomainEnum FAR* FAR* ppenumvariant, LPWSTR ADsPath, LPWSTR DomainName, VARIANT var, CWinNTCredentials& Credentials ) { HRESULT hr = NOERROR; CWinNTDomainEnum FAR* penumvariant = NULL; NET_API_STATUS nasStatus = 0; *ppenumvariant = NULL; penumvariant = new CWinNTDomainEnum(); if (!penumvariant) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } penumvariant->_ADsPath = AllocADsStr( ADsPath); if (!penumvariant->_ADsPath) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr); penumvariant->_DomainName = AllocADsStr( DomainName); if (!penumvariant->_DomainName) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr); hr = ObjectTypeList::CreateObjectTypeList( var, &penumvariant->_pObjList ); BAIL_ON_FAILURE(hr); // // ramv's change. You don't need to do a WinNTGetCachedDCName // to validate a domain here. You might be dealing with a // workgroup. If this call succeeds then we keep a BOOL variable // which tells us next time when it is necessary whether it is a // domain or workgroup // hr = WinNTGetCachedDCName( penumvariant->_DomainName, penumvariant->_szDomainPDCName, Credentials.GetFlags() ); if(SUCCEEDED(hr)){ penumvariant->_fIsDomain = TRUE; } else { penumvariant->_fIsDomain = FALSE; } penumvariant->_Credentials = Credentials; hr = penumvariant->_Credentials.RefDomain(DomainName); BAIL_ON_FAILURE(hr); *ppenumvariant = penumvariant; RRETURN(S_OK); error: delete penumvariant; RRETURN_EXP_IF_ERR(hr); } CWinNTDomainEnum::CWinNTDomainEnum(): _ADsPath(NULL), _DomainName(NULL) { _pObjList = NULL; _pBuffer = NULL; _dwObjectReturned = 0; _dwIndex = 0; _dwObjectCurrentEntry = 0; _dwObjectTotal = 0; _dwNetCount = 0; _hLGroupComputer = NULL; _hGGroupComputer = NULL; _dwGroupArrayIndex = 0; _dwCompObjectReturned = 0; _dwCompObjectCurrentEntry = 0; _dwCompObjectTotal = 0; _pCompBuffer = 0; _dwCompIndex = 0; _pServerInfo = NULL; _fSchemaReturned = FALSE; memset(_szDomainPDCName, 0, sizeof(WCHAR)*MAX_PATH); } CWinNTDomainEnum::CWinNTDomainEnum(ObjectTypeList ObjList): _ADsPath(NULL), _DomainName(NULL) { _pObjList = NULL; _pBuffer = NULL; _dwObjectReturned = 0; _dwObjectCurrentEntry = 0; _dwIndex = 0; _dwNetCount = 0; _hLGroupComputer = NULL; _hGGroupComputer = NULL; _dwGroupArrayIndex = 0; _dwCompObjectReturned = NULL; _dwCompObjectCurrentEntry = NULL; _dwCompObjectTotal = NULL; _dwCompResumeHandle = 0; _pCompBuffer = NULL; _fIsDomain = FALSE; _pServerInfo = NULL; _fSchemaReturned = FALSE; memset(_szDomainPDCName, 0, sizeof(WCHAR)*MAX_PATH); } CWinNTDomainEnum::~CWinNTDomainEnum() { if (_hLGroupComputer) { WinNTCloseComputer( _hLGroupComputer ); } if (_hGGroupComputer) { WinNTCloseComputer( _hGGroupComputer ); } if (_pCompBuffer) { NetApiBufferFree(_pCompBuffer); } if (_DomainName) { FreeADsStr(_DomainName); } if (_ADsPath) { FreeADsStr(_ADsPath); } if (_pObjList) { delete _pObjList; } } HRESULT CWinNTDomainEnum::EnumObjects( DWORD ObjectType, ULONG cElements, VARIANT FAR * pvar, ULONG FAR * pcElementFetched ) { HRESULT hr = S_OK; ULONG cElementGlobal = 0; ULONG cElementLocal = 0; switch (ObjectType) { case WINNT_COMPUTER_ID: hr = EnumComputers(cElements, pvar, pcElementFetched); break; case WINNT_USER_ID: hr = EnumUsers(cElements, pvar, pcElementFetched); break; case WINNT_GROUP_ID: // // for backward compatabillity, "group" includes "local group" and // "global group" during enumeration // // // enum all the global groups first // hr = EnumGlobalGroups( cElements, pvar, &cElementGlobal ); // // enum local groups when there is no more global // if (hr == S_FALSE) { hr = EnumLocalGroups( cElements-cElementGlobal, // we have reduced buffer size! pvar+cElementGlobal, &cElementLocal ); } // // increment instead of just assingment: for consistency with // other switch cases // (*pcElementFetched) += (cElementGlobal+cElementLocal); break; case WINNT_LOCALGROUP_ID: hr = EnumLocalGroups(cElements, pvar, pcElementFetched); break; case WINNT_GLOBALGROUP_ID: hr = EnumGlobalGroups(cElements, pvar, pcElementFetched); break; case WINNT_SCHEMA_ID: hr = EnumSchema(cElements, pvar, pcElementFetched); break; default: RRETURN(S_FALSE); } RRETURN_EXP_IF_ERR(hr); } HRESULT CWinNTDomainEnum::EnumObjects( ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched ) { DWORD i; ULONG cRequested = 0; ULONG cFetchedByPath = 0; ULONG cTotalFetched = 0; VARIANT FAR* pPathvar = pvar; HRESULT hr = S_OK; DWORD ObjectType; for (i = 0; i < cElements; i++) { VariantInit(&pvar[i]); } cRequested = cElements; while (SUCCEEDED(_pObjList->GetCurrentObject(&ObjectType)) && ((hr = EnumObjects(ObjectType, cRequested, pPathvar, &cFetchedByPath)) == S_FALSE )) { pPathvar += cFetchedByPath; cRequested -= cFetchedByPath; cTotalFetched += cFetchedByPath; cFetchedByPath = 0; if (FAILED(_pObjList->Next())){ if (pcElementFetched) *pcElementFetched = cTotalFetched; RRETURN(S_FALSE); } } if (pcElementFetched) { *pcElementFetched = cTotalFetched + cFetchedByPath; } RRETURN_EXP_IF_ERR(hr); } HRESULT CWinNTDomainEnum::EnumSchema( ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched ) { HRESULT hr = S_OK; IDispatch *pDispatch = NULL; if ( _fSchemaReturned ) RRETURN(S_FALSE); if ( cElements > 0 ) { hr = CWinNTSchema::CreateSchema( _ADsPath, TEXT("Schema"), ADS_OBJECT_BOUND, IID_IDispatch, _Credentials, (void **)&pDispatch ); if ( hr == S_OK ) { VariantInit(&pvar[0]); pvar[0].vt = VT_DISPATCH; pvar[0].pdispVal = pDispatch; (*pcElementFetched)++; _fSchemaReturned = TRUE; } } RRETURN(hr); } HRESULT CWinNTDomainEnum::EnumUsers( ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched ) { HRESULT hr = S_OK; IDispatch *pDispatch = NULL; DWORD i = 0; if(!_fIsDomain){ RRETURN(S_FALSE); } while (i < cElements) { hr = GetUserObject(&pDispatch); if (hr == S_FALSE) { break; } VariantInit(&pvar[i]); pvar[i].vt = VT_DISPATCH; pvar[i].pdispVal = pDispatch; (*pcElementFetched)++; i++; } return(hr); } HRESULT CWinNTDomainEnum::GetUserObject( IDispatch ** ppDispatch ) { HRESULT hr = S_OK; NTSTATUS Status; PNET_DISPLAY_USER pUserInfo1 = NULL; NET_API_STATUS nasStatus = 0; DWORD dwResumeHandle = 0; if (!_pBuffer || (_dwObjectCurrentEntry == _dwObjectReturned)) { if (_pBuffer) { NetApiBufferFree(_pBuffer); _pBuffer = NULL; } _dwObjectCurrentEntry = 0; _dwObjectReturned = 0; nasStatus = NetQueryDisplayInformation( _szDomainPDCName, 1, _dwIndex, 1024, MAX_PREFERRED_LENGTH, &_dwObjectReturned, (PVOID *)&_pBuffer ); _dwNetCount++; // // The following if clause is to handle real errors; anything // other than ERROR_SUCCESS and ERROR_MORE_DATA // if ((nasStatus != ERROR_SUCCESS) && (nasStatus != ERROR_MORE_DATA)) { RRETURN(S_FALSE); } // // This one is to handle the termination case - Call completed // successfully but there is no data to retrieve _pBuffer = NULL // if (!_pBuffer) { RRETURN(S_FALSE); } _dwIndex = (_pBuffer + _dwObjectReturned -1)->usri1_next_index; } // // Now send back the current ovbject // pUserInfo1 = (PNET_DISPLAY_USER)_pBuffer; pUserInfo1 += _dwObjectCurrentEntry; hr = CWinNTUser::CreateUser( _ADsPath, WINNT_DOMAIN_ID, _DomainName, NULL, pUserInfo1->usri1_name, ADS_OBJECT_BOUND, &(pUserInfo1->usri1_flags), pUserInfo1->usri1_full_name, pUserInfo1->usri1_comment, NULL, IID_IDispatch, _Credentials, (void **)ppDispatch ); BAIL_IF_ERROR(hr); _dwObjectCurrentEntry++; RRETURN(S_OK); cleanup: *ppDispatch = NULL; RRETURN(S_FALSE); } HRESULT CWinNTDomainEnum::EnumComputers( ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched ) { HRESULT hr = S_OK; IDispatch *pDispatch = NULL; DWORD i = 0; while (i < cElements) { if(_fIsDomain == TRUE){ hr = GetComputerObject(&pDispatch); } else { hr = GetComputerObjectInWorkGroup(&pDispatch); } if (hr == S_FALSE) { break; } VariantInit(&pvar[i]); pvar[i].vt = VT_DISPATCH; pvar[i].pdispVal = pDispatch; (*pcElementFetched)++; i++; } return(hr); } HRESULT CWinNTDomainEnum::GetComputerObject( IDispatch ** ppDispatch ) { HRESULT hr = S_OK; NTSTATUS Status; PNET_DISPLAY_MACHINE pDisplayComp = NULL; NET_API_STATUS nasStatus = 0; DWORD dwResumeHandle = 0; DWORD clen = 0; if (!_pCompBuffer || (_dwCompObjectCurrentEntry == _dwCompObjectReturned)) { if (_pCompBuffer) { NetApiBufferFree(_pCompBuffer); _pCompBuffer = NULL; } _dwCompObjectCurrentEntry = 0; _dwCompObjectReturned = 0; nasStatus = NetQueryDisplayInformation( _szDomainPDCName, 2, _dwCompIndex, 100, MAX_PREFERRED_LENGTH, &_dwCompObjectReturned, (PVOID *)&_pCompBuffer ); // The following if clause is to handle real errors; anything // other than ERROR_SUCCESS and ERROR_MORE_DATA // if ((nasStatus != ERROR_SUCCESS) && (nasStatus != ERROR_MORE_DATA)) { RRETURN(S_FALSE); } // // This one is to handle the termination case - Call completed // successfully but there is no data to retrieve _pBuffer = NULL // if (!_pCompBuffer) { RRETURN(S_FALSE); } _dwCompIndex = (_pCompBuffer + _dwCompObjectReturned -1)->usri2_next_index; } // // Now send back the current object // pDisplayComp = (PNET_DISPLAY_MACHINE)_pCompBuffer; pDisplayComp += _dwCompObjectCurrentEntry; // // The usri2_name is going to be returned back with a // $ character appended. Null set the $ character. // clen = wcslen(pDisplayComp->usri2_name); *(pDisplayComp->usri2_name + clen -1) = L'\0'; hr = CWinNTComputer::CreateComputer( _ADsPath, _DomainName, pDisplayComp->usri2_name, ADS_OBJECT_BOUND, IID_IDispatch, _Credentials, (void **)ppDispatch ); BAIL_IF_ERROR(hr); _dwCompObjectCurrentEntry++; RRETURN(S_OK); cleanup: *ppDispatch = NULL; RRETURN(S_FALSE); } //+--------------------------------------------------------------------------- // // Function: CWinNTDomainEnum::Next // // Synopsis: Returns cElements number of requested NetOle 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: 11-3-95 krishnag Created. // //---------------------------------------------------------------------------- STDMETHODIMP CWinNTDomainEnum::Next( ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched ) { ULONG cElementFetched = 0; HRESULT hr = S_OK; hr = EnumObjects( cElements, pvar, &cElementFetched ); if (pcElementFetched) { *pcElementFetched = cElementFetched; } RRETURN(hr); } HRESULT CWinNTDomainEnum::GetComputerObjectInWorkGroup( IDispatch ** ppDispatch ) { HRESULT hr = S_OK; NTSTATUS Status; PSERVER_INFO_100 pServerInfo = NULL; NET_API_STATUS nasStatus = 0; DWORD clen = 0; if (!_pServerInfo || (_dwCompObjectCurrentEntry == _dwCompObjectReturned)) { if (_pServerInfo) { NetApiBufferFree(_pServerInfo); _pServerInfo = NULL; } if(_dwCompObjectTotal == _dwCompObjectReturned && (_dwCompObjectTotal !=0)){ // // we got all elements already, no need to do another call // RRETURN(S_FALSE); } nasStatus = NetServerEnum( NULL, 100, (LPBYTE *)&_pServerInfo, MAX_PREFERRED_LENGTH, &_dwCompObjectReturned, &_dwCompObjectTotal, SV_TYPE_NT, _DomainName, &_dwCompResumeHandle ); /* nasStatus = NetQueryDisplayInformation( _szDomainPDCName, 2, _dwCompIndex, 100, MAX_PREFERRED_LENGTH, &_dwCompObjectReturned, (PVOID *)&_pServerInfo ); */ // // The following if clause is to handle real errors; anything // other than ERROR_SUCCESS and ERROR_MORE_DATA // if ((nasStatus != ERROR_SUCCESS) && (nasStatus != ERROR_MORE_DATA)) { RRETURN(S_FALSE); } _dwCompObjectCurrentEntry = 0; // // This one is to handle the termination case - Call completed // successfully but there is no data to retrieve _pServerInfo = NULL // if (!_dwCompObjectReturned) { _pServerInfo = NULL; RRETURN(S_FALSE); } } // // Now send back the current object // pServerInfo = (PSERVER_INFO_100)_pServerInfo; pServerInfo += _dwCompObjectCurrentEntry; hr = CWinNTComputer::CreateComputer( _ADsPath, _DomainName, pServerInfo->sv100_name, ADS_OBJECT_BOUND, IID_IDispatch, _Credentials, (void **)ppDispatch ); BAIL_IF_ERROR(hr); _dwCompObjectCurrentEntry++; RRETURN(S_OK); cleanup: *ppDispatch = NULL; RRETURN(S_FALSE); } HRESULT CWinNTDomainEnum::GetGlobalGroupObject( IDispatch ** ppDispatch ) { HRESULT hr = S_OK; LPWINNT_GROUP pWinNTGrp = NULL; LPBYTE pBuffer = NULL; DWORD dwReturned = 0; BOOL dwRet = 0; if (!_hGGroupComputer) { dwRet = WinNTComputerOpen( _DomainName, (_szDomainPDCName + 2), WINNT_DOMAIN_ID, &_hGGroupComputer ); if (!dwRet) { goto error; } } dwRet = WinNTEnumGlobalGroups( _hGGroupComputer, 1, &pBuffer, &dwReturned ); if (!dwRet) { goto error; } pWinNTGrp = (LPWINNT_GROUP)pBuffer; hr = CWinNTGroup::CreateGroup( pWinNTGrp->Parent, WINNT_DOMAIN_ID, pWinNTGrp->Domain, pWinNTGrp->Computer, pWinNTGrp->Name, WINNT_GROUP_GLOBAL, ADS_OBJECT_BOUND, IID_IDispatch, _Credentials, (void **)ppDispatch ); BAIL_ON_FAILURE(hr); hr = S_OK; cleanup: if (pBuffer) { FreeADsMem(pBuffer); } RRETURN(hr); error: *ppDispatch = NULL; hr = S_FALSE; goto cleanup; } HRESULT CWinNTDomainEnum::GetLocalGroupObject( IDispatch ** ppDispatch ) { HRESULT hr = S_OK; LPWINNT_GROUP pWinNTGrp = NULL; LPBYTE pBuffer = NULL; DWORD dwReturned = 0; BOOL dwRet = 0; if (!_hLGroupComputer) { dwRet = WinNTComputerOpen( _DomainName, (_szDomainPDCName + 2), WINNT_DOMAIN_ID, &_hLGroupComputer ); if (!dwRet) { goto error; } } dwRet = WinNTEnumLocalGroups( _hLGroupComputer, 1, &pBuffer, &dwReturned ); if (!dwRet) { goto error; } pWinNTGrp = (LPWINNT_GROUP)pBuffer; hr = CWinNTGroup::CreateGroup( pWinNTGrp->Parent, WINNT_DOMAIN_ID, pWinNTGrp->Domain, pWinNTGrp->Computer, pWinNTGrp->Name, WINNT_GROUP_LOCAL, ADS_OBJECT_BOUND, IID_IDispatch, _Credentials, (void **)ppDispatch ); BAIL_ON_FAILURE(hr); hr = S_OK; cleanup: if (pBuffer) { FreeADsMem(pBuffer); } RRETURN(hr); error: *ppDispatch = NULL; hr = S_FALSE; goto cleanup; } HRESULT CWinNTDomainEnum::EnumGroupObjects( DWORD ObjectType, ULONG cElements, VARIANT FAR * pvar, ULONG FAR * pcElementFetched ) { HRESULT hr; switch (ObjectType) { case WINNT_GROUP_GLOBAL: hr = EnumGlobalGroups(cElements, pvar, pcElementFetched); break; case WINNT_GROUP_LOCAL: hr = EnumLocalGroups(cElements, pvar, pcElementFetched); break; default: hr = S_FALSE; break; } RRETURN(hr); } ULONG GroupTypeArray[] = {WINNT_GROUP_GLOBAL, WINNT_GROUP_LOCAL, 0xFFFFFFFF}; HRESULT CWinNTDomainEnum::EnumGroups( ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched ) { DWORD i; ULONG cRequested = 0; ULONG cFetchedByPath = 0; ULONG cTotalFetched = 0; VARIANT FAR* pPathvar = pvar; HRESULT hr = S_OK; DWORD ObjectType; if(!_fIsDomain){ RRETURN(S_FALSE); } for (i = 0; i < cElements; i++) { VariantInit(&pvar[i]); } cRequested = cElements; while ((GroupTypeArray[_dwGroupArrayIndex] != (ULONG)-1) && ((hr = EnumGroupObjects( GroupTypeArray[_dwGroupArrayIndex], cRequested, pPathvar, &cFetchedByPath)) == S_FALSE )) { pPathvar += cFetchedByPath; cRequested -= cFetchedByPath; cTotalFetched += cFetchedByPath; cFetchedByPath = 0; if (GroupTypeArray[_dwGroupArrayIndex++] == (ULONG)-1){ if (pcElementFetched) *pcElementFetched = cTotalFetched; RRETURN(S_FALSE); } } if (pcElementFetched) { *pcElementFetched = cTotalFetched + cFetchedByPath; } RRETURN(hr); } HRESULT CWinNTDomainEnum::EnumGlobalGroups( ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched ) { HRESULT hr = S_OK; IDispatch *pDispatch = NULL; DWORD i = 0; while (i < cElements) { hr = GetGlobalGroupObject(&pDispatch); if (hr == S_FALSE) { break; } VariantInit(&pvar[i]); pvar[i].vt = VT_DISPATCH; pvar[i].pdispVal = pDispatch; (*pcElementFetched)++; i++; } return(hr); } HRESULT CWinNTDomainEnum::EnumLocalGroups( ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched ) { HRESULT hr = S_OK; IDispatch *pDispatch = NULL; DWORD i = 0; while (i < cElements) { hr = GetLocalGroupObject(&pDispatch); if (hr == S_FALSE) { break; } VariantInit(&pvar[i]); pvar[i].vt = VT_DISPATCH; pvar[i].pdispVal = pDispatch; (*pcElementFetched)++; i++; } return(hr); }