windows-nt/Source/XPSP1/NT/ds/security/services/w32time/lib/dcinfo.cpp
2020-09-26 16:20:57 +08:00

425 lines
14 KiB
C++

//--------------------------------------------------------------------
// 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;
}