|
|
//--------------------------------------------------------------------
// DcInfo - implementation
// Copyright (C) Microsoft Corporation, 1999
//
// Created by: Louis Thomas (louisth), 7-8-99
//
// Gather information about the DCs in a domain
#include "pch.h" // precompiled headers
#include "DcInfo.h"
//####################################################################
// module private functions
//--------------------------------------------------------------------
// Get a list of DCs in this domain from the DS on an up DC.
MODULEPRIVATE HRESULT GetDcListFromDs(const WCHAR * wszDomainName, DcInfo ** prgDcs, unsigned int * pnDcs) { HRESULT hr; NET_API_STATUS dwNetStatus; DWORD dwDcCount; unsigned int nIndex; unsigned int nDcs; unsigned int nDcIndex;
// varaibles that must be cleaned up
DOMAIN_CONTROLLER_INFOW * pDcInfo=NULL; HANDLE hDs=NULL; DS_DOMAIN_CONTROLLER_INFO_1W * rgDsDcInfo=NULL; DcInfo * rgDcs=NULL;
// initialize out variables
*prgDcs=NULL; *pnDcs=0;
// Get a DC to seed the algorithm with
dwNetStatus=DsGetDcName( NULL, // computer name
wszDomainName, // domain name
NULL, // domain guid
NULL, // site name
DS_DIRECTORY_SERVICE_PREFERRED, // flags
&pDcInfo); // DC info
if (NO_ERROR!=dwNetStatus) { hr=HRESULT_FROM_WIN32(dwNetStatus); _JumpError(hr, error, "DsGetDcName"); } if (0==(pDcInfo->Flags&DS_DS_FLAG)) { hr=HRESULT_FROM_WIN32(ERROR_DS_DST_DOMAIN_NOT_NATIVE); // not an NT5 domain.
_JumpError(hr, error, "DsGetDcName"); }
// Bind to the target DS
dwNetStatus=DsBind( pDcInfo->DomainControllerName, // DC Address
NULL, // DNS domain name
&hDs ); // DS handle
if (NO_ERROR!=dwNetStatus) { hr=HRESULT_FROM_WIN32(dwNetStatus); _JumpError(hr, error, "DsBind"); }
// Get the list of DCs from the target DS.
dwNetStatus=DsGetDomainControllerInfo( hDs, // DS handle
pDcInfo->DomainName, // domain name
1, // Info level
&dwDcCount, // number of names returned
(void **)&rgDsDcInfo); // array of names
if (NO_ERROR!=dwNetStatus ) { hr=HRESULT_FROM_WIN32(dwNetStatus); _JumpError(hr, error, "DsGetDomainControllerInfo"); }
// figure out how many DCs there are with DNS names
nDcs=0; for (nIndex=0; nIndex<dwDcCount; nIndex++) { if (NULL!=rgDsDcInfo[nIndex].DnsHostName) { nDcs++; } } if (nDcs<dwDcCount) { DebugWPrintf2(L"Found %u non-DNS DCs out of %u, which will be ignored.\n", dwDcCount-nDcs, dwDcCount); } if (0==nDcs) { hr=HRESULT_FROM_WIN32(ERROR_DOMAIN_CONTROLLER_NOT_FOUND); // no usable DCs
_JumpError(hr, error, "Search rgDsDcInfo for usable DCs"); }
// allocate the list
rgDcs=(DcInfo *)LocalAlloc(LPTR, sizeof(DcInfo)*nDcs); _JumpIfOutOfMemory(hr, error, rgDcs);
// copy the names into it
nDcIndex=0; for (nIndex=0; nIndex<dwDcCount; nIndex++) { if (NULL!=rgDsDcInfo[nIndex].DnsHostName) {
// allocate and copy name
rgDcs[nDcIndex].wszDnsName=(WCHAR *)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(rgDsDcInfo[nIndex].DnsHostName)+1)); _JumpIfOutOfMemory(hr, error, rgDcs[nDcIndex].wszDnsName); wcscpy(rgDcs[nDcIndex].wszDnsName, rgDsDcInfo[nIndex].DnsHostName);
//_Verify(NULL!=rgDsDcInfo[nIndex].NetbiosName, hr, error);
//rgDcs[nDcIndex].wszDnsName=(WCHAR *)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(rgDsDcInfo[nIndex].NetbiosName)+1));
//_JumpIfOutOfMemory(hr, error, rgDcs[nDcIndex].wszDnsName);
//wcscpy(rgDcs[nDcIndex].wszDnsName, rgDsDcInfo[nIndex].NetbiosName);
// copy PDCness
rgDcs[nDcIndex].bIsPdc=rgDsDcInfo[nIndex].fIsPdc?true:false; nDcIndex++; } }
// move the data to the out parameters
*prgDcs=rgDcs; rgDcs=NULL; *pnDcs=nDcs;
hr=S_OK;
error: if (NULL!=rgDcs) { for (nIndex=0; nIndex<nDcs; nIndex++) { FreeDcInfo(&rgDcs[nIndex]); } LocalFree(rgDcs); } if (NULL!=rgDsDcInfo ) { DsFreeDomainControllerInfo(1, dwDcCount, rgDsDcInfo); } if (NULL!=hDs) { DsUnBind(&hDs); } if (NULL!=pDcInfo) { NetApiBufferFree(pDcInfo); } return hr; }
//--------------------------------------------------------------------
MODULEPRIVATE HRESULT GetDcListFromNetlogon(const WCHAR * wszDomainName, DcInfo ** prgDcs, unsigned int * pnDcs) { HRESULT hr; NET_API_STATUS dwNetStatus; DWORD dwEntriesRead; DWORD dwTotalEntries; unsigned int nIndex; unsigned int nDcIndex; unsigned int nDcs;
// varaibles that must be cleaned up
DcInfo * rgDcs=NULL; SERVER_INFO_101 * rgsiServerInfo=NULL;
// initialize out variables
*prgDcs=NULL; *pnDcs=0;
// enumerate all PDC and BDCs
dwNetStatus=NetServerEnum( NULL, // server to query
101, // info level
(BYTE **)&rgsiServerInfo, // output buffer
MAX_PREFERRED_LENGTH, // desired return buf size
&dwEntriesRead, // entries in output buffer
&dwTotalEntries, // total number of entries available
SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL, // server type to find
wszDomainName, // domain to search
NULL); // reserved
if (NO_ERROR!=dwNetStatus ) { hr=HRESULT_FROM_WIN32(dwNetStatus); _JumpError(hr, error, "NetServerEnum"); }
// count how many NT 5 servers there are
nDcs=0; for (nIndex=0; nIndex<dwEntriesRead; nIndex++) { if (0!=(rgsiServerInfo[nIndex].sv101_type&SV_TYPE_NT) && rgsiServerInfo[nIndex].sv101_version_major>=5) { nDcs++; } } if (nDcs<dwEntriesRead) { DebugWPrintf2(L"Found %u non-NT5 DCs out of %u, which will be ignored.\n", dwEntriesRead-nDcs, dwEntriesRead); } if (0==nDcs) { hr=HRESULT_FROM_WIN32(ERROR_DOMAIN_CONTROLLER_NOT_FOUND); // no usable DCs
_JumpError(hr, error, "Search rgsiServerInfo for usable DCs"); }
// allocate the list
rgDcs=(DcInfo *)LocalAlloc(LPTR, sizeof(DcInfo)*nDcs); _JumpIfOutOfMemory(hr, error, rgDcs);
// copy the names into it
nDcIndex=0; for (nIndex=0; nIndex<dwEntriesRead; nIndex++) { if (0!=(rgsiServerInfo[nIndex].sv101_type&SV_TYPE_NT) && rgsiServerInfo[nIndex].sv101_version_major>=5) { // allocate and copy name
rgDcs[nDcIndex].wszDnsName=(WCHAR *)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(rgsiServerInfo[nIndex].sv101_name)+1)); _JumpIfOutOfMemory(hr, error, rgDcs[nDcIndex].wszDnsName); wcscpy(rgDcs[nDcIndex].wszDnsName, rgsiServerInfo[nIndex].sv101_name);
// copy PDCness
rgDcs[nDcIndex].bIsPdc=(rgsiServerInfo[nIndex].sv101_type&SV_TYPE_DOMAIN_CTRL)?true:false; nDcIndex++; } }
// move the data to the out parameters
*prgDcs=rgDcs; rgDcs=NULL; *pnDcs=nDcs;
hr=S_OK;
error: if (NULL!=rgDcs) { for (nIndex=0; nIndex<nDcs; nIndex++) { FreeDcInfo(&rgDcs[nIndex]); } LocalFree(rgDcs); } if (NULL!=rgsiServerInfo) { NetApiBufferFree(rgsiServerInfo); } return hr; }
//--------------------------------------------------------------------
MODULEPRIVATE HRESULT FillInIpAddresses(DcInfo * pdi) { HRESULT hr; DWORD dwDataLen; unsigned int nIndex;
// pointers that must be cleaned up
HANDLE hSearch=INVALID_HANDLE_VALUE; WSAQUERYSETW * pqsResult=NULL; in_addr * rgiaLocalIpAddresses=NULL; in_addr * rgiaRemoteIpAddresses=NULL;
DebugWPrintf1(L"Looking up server \"%s\":\n", pdi->wszDnsName);
// initialize the search
AFPROTOCOLS apInetUdp={AF_INET, IPPROTO_UDP}; GUID guidNtp=SVCID_NTP_UDP; WSAQUERYSETW qsSearch; ZeroMemory(&qsSearch, sizeof(qsSearch)); qsSearch.dwSize=sizeof(qsSearch); qsSearch.lpszServiceInstanceName=const_cast<WCHAR *>(pdi->wszDnsName); qsSearch.lpServiceClassId=&guidNtp; qsSearch.dwNameSpace=NS_ALL; qsSearch.dwNumberOfProtocols=1; qsSearch.lpafpProtocols=&apInetUdp;
// begin the search
if (SOCKET_ERROR==WSALookupServiceBegin(&qsSearch, LUP_RETURN_ADDR/*flags*/, &hSearch)) { hr=HRESULT_FROM_WIN32(WSAGetLastError()); _JumpError(hr, error, "WSALookupServiceBegin"); }
// get the buffer size for the first result set
//dwDataLen=1;
//_Verify(SOCKET_ERROR==WSALookupServiceNext(hSearch, LUP_RETURN_ADDR/*flags*/, &dwDataLen, &qsSearch), hr, error);
//hr=WSAGetLastError();
//if (WSAEFAULT!=hr) {
// hr=HRESULT_FROM_WIN32(hr);
// _JumpError(hr, error, "WSALookupServiceNext(1)");
//}
dwDataLen=5*1024;
// allocate the buffer
pqsResult=(WSAQUERYSETW *)LocalAlloc(LPTR, dwDataLen); _JumpIfOutOfMemory(hr, error, pqsResult); // retrieve the result set
if (SOCKET_ERROR==WSALookupServiceNext(hSearch, LUP_RETURN_ADDR/*flags*/, &dwDataLen, pqsResult)) { hr=HRESULT_FROM_WIN32(WSAGetLastError()); _JumpError(hr, error, "WSALookupServiceNext(2)"); } _Verify(0!=pqsResult->dwNumberOfCsAddrs, hr, error) ;
// allocate room for the IP addresses
rgiaLocalIpAddresses=(in_addr *)LocalAlloc(LPTR, sizeof(in_addr)*pqsResult->dwNumberOfCsAddrs); _JumpIfOutOfMemory(hr, error, rgiaLocalIpAddresses); rgiaRemoteIpAddresses=(in_addr *)LocalAlloc(LPTR, sizeof(in_addr)*pqsResult->dwNumberOfCsAddrs); _JumpIfOutOfMemory(hr, error, rgiaRemoteIpAddresses);
// copy the IP addresses
for (nIndex=0; nIndex<pqsResult->dwNumberOfCsAddrs; nIndex++) { // copy local
_Verify(sizeof(sockaddr)==pqsResult->lpcsaBuffer[nIndex].LocalAddr.iSockaddrLength, hr, error); _Verify(AF_INET==pqsResult->lpcsaBuffer[nIndex].LocalAddr.lpSockaddr->sa_family, hr, error); rgiaLocalIpAddresses[nIndex].S_un.S_addr=((sockaddr_in *)(pqsResult->lpcsaBuffer[nIndex].LocalAddr.lpSockaddr))->sin_addr.S_un.S_addr; // copy remote
_Verify(sizeof(sockaddr)==pqsResult->lpcsaBuffer[nIndex].RemoteAddr.iSockaddrLength, hr, error); _Verify(AF_INET==pqsResult->lpcsaBuffer[nIndex].RemoteAddr.lpSockaddr->sa_family, hr, error); rgiaRemoteIpAddresses[nIndex].S_un.S_addr=((sockaddr_in *)(pqsResult->lpcsaBuffer[nIndex].RemoteAddr.lpSockaddr))->sin_addr.S_un.S_addr; }
// move the data to the out parameters
pdi->nIpAddresses=pqsResult->dwNumberOfCsAddrs; pdi->rgiaLocalIpAddresses=rgiaLocalIpAddresses; rgiaLocalIpAddresses=NULL; pdi->rgiaRemoteIpAddresses=rgiaRemoteIpAddresses; rgiaRemoteIpAddresses=NULL;
hr=S_OK;
error: if (NULL!=rgiaLocalIpAddresses) { LocalFree(rgiaLocalIpAddresses); } if (NULL!=rgiaRemoteIpAddresses) { LocalFree(rgiaRemoteIpAddresses); } if (NULL!=pqsResult) { LocalFree(pqsResult); } if (INVALID_HANDLE_VALUE!=hSearch) { if (SOCKET_ERROR==WSALookupServiceEnd(hSearch)) { HRESULT hr2=HRESULT_FROM_WIN32(WSAGetLastError()); _IgnoreError(hr2, "WSALookupServiceEnd"); } }
return hr; }
//####################################################################
// Globals
//--------------------------------------------------------------------
void FreeDcInfo(DcInfo * pdci) { if (NULL!=pdci->wszDnsName) { LocalFree(pdci->wszDnsName); } if (NULL!=pdci->rgiaLocalIpAddresses) { LocalFree(pdci->rgiaLocalIpAddresses); } if (NULL!=pdci->rgiaRemoteIpAddresses) { LocalFree(pdci->rgiaRemoteIpAddresses); } }
//--------------------------------------------------------------------
// Get a list of DCs in this domain
HRESULT GetDcList(const WCHAR * wszDomainName, bool bGetIps, DcInfo ** prgDcs, unsigned int * pnDcs) { HRESULT hr; unsigned int nDcs; unsigned int nIndex;
// varaibles that must be cleaned up
DcInfo * rgDcs=NULL;
// initialize out variables
*prgDcs=NULL; *pnDcs=0;
hr=GetDcListFromDs(wszDomainName, &rgDcs, &nDcs); if (FAILED(hr)) { _IgnoreError(hr, "GetDcListFromDs"); hr=GetDcListFromNetlogon(wszDomainName, &rgDcs, &nDcs); _JumpIfError(hr, error, "GetDcListFromNetlogon"); } if (bGetIps) { // get the info about the DCs
for (nIndex=0; nIndex<nDcs; nIndex++) { hr=FillInIpAddresses(&rgDcs[nIndex]); if (FAILED(hr)) { _IgnoreError(hr, "FillInIpAddresses"); if (nIndex!=nDcs-1) { // swap it with the last one
WCHAR * wszDnsName=rgDcs[nIndex].wszDnsName; rgDcs[nIndex].wszDnsName=rgDcs[nDcs-1].wszDnsName; rgDcs[nDcs-1].wszDnsName=wszDnsName;
in_addr * rgiaLocalIpAddresses=rgDcs[nIndex].rgiaLocalIpAddresses; rgDcs[nIndex].rgiaLocalIpAddresses=rgDcs[nDcs-1].rgiaLocalIpAddresses; rgDcs[nDcs-1].rgiaLocalIpAddresses=rgiaLocalIpAddresses;
in_addr * rgiaRemoteIpAddresses=rgDcs[nIndex].rgiaRemoteIpAddresses; rgDcs[nIndex].rgiaRemoteIpAddresses=rgDcs[nDcs-1].rgiaRemoteIpAddresses; rgDcs[nDcs-1].rgiaRemoteIpAddresses=rgiaRemoteIpAddresses;
// non-pointers can just be copied
rgDcs[nIndex].nIpAddresses=rgDcs[nDcs-1].nIpAddresses; rgDcs[nIndex].bIsPdc=rgDcs[nDcs-1].bIsPdc; rgDcs[nIndex].bIsGoodTimeSource=rgDcs[nDcs-1].bIsGoodTimeSource; } DebugWPrintf1(L"Dropping '%s' because we cannot get an IP address.\n", rgDcs[nDcs-1].wszDnsName); nDcs--; nIndex--; } } }
if (0==nDcs) { hr=HRESULT_FROM_WIN32(ERROR_DOMAIN_CONTROLLER_NOT_FOUND); // no usable DCs
_JumpError(hr, error, "Getting IP address for at least one DC"); }
// move the data to the out parameters
*prgDcs=rgDcs; rgDcs=NULL; *pnDcs=nDcs;
hr=S_OK;
error: if (NULL!=rgDcs) { for (nIndex=0; nIndex<nDcs; nIndex++) { FreeDcInfo(&rgDcs[nIndex]); } LocalFree(rgDcs); } return hr; }
|