Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

424 lines
15 KiB

  1. //--------------------------------------------------------------------
  2. // DcInfo - implementation
  3. // Copyright (C) Microsoft Corporation, 1999
  4. //
  5. // Created by: Louis Thomas (louisth), 7-8-99
  6. //
  7. // Gather information about the DCs in a domain
  8. #include "pch.h" // precompiled headers
  9. #include "DcInfo.h"
  10. //####################################################################
  11. // module private functions
  12. //--------------------------------------------------------------------
  13. // Get a list of DCs in this domain from the DS on an up DC.
  14. MODULEPRIVATE HRESULT GetDcListFromDs(const WCHAR * wszDomainName, DcInfo ** prgDcs, unsigned int * pnDcs)
  15. {
  16. HRESULT hr;
  17. NET_API_STATUS dwNetStatus;
  18. DWORD dwDcCount;
  19. unsigned int nIndex;
  20. unsigned int nDcs;
  21. unsigned int nDcIndex;
  22. // varaibles that must be cleaned up
  23. DOMAIN_CONTROLLER_INFOW * pDcInfo=NULL;
  24. HANDLE hDs=NULL;
  25. DS_DOMAIN_CONTROLLER_INFO_1W * rgDsDcInfo=NULL;
  26. DcInfo * rgDcs=NULL;
  27. // initialize out variables
  28. *prgDcs=NULL;
  29. *pnDcs=0;
  30. // Get a DC to seed the algorithm with
  31. dwNetStatus=DsGetDcName(
  32. NULL, // computer name
  33. wszDomainName, // domain name
  34. NULL, // domain guid
  35. NULL, // site name
  36. DS_DIRECTORY_SERVICE_PREFERRED, // flags
  37. &pDcInfo); // DC info
  38. if (NO_ERROR!=dwNetStatus) {
  39. hr=HRESULT_FROM_WIN32(dwNetStatus);
  40. _JumpError(hr, error, "DsGetDcName");
  41. }
  42. if (0==(pDcInfo->Flags&DS_DS_FLAG)) {
  43. hr=HRESULT_FROM_WIN32(ERROR_DS_DST_DOMAIN_NOT_NATIVE); // not an NT5 domain.
  44. _JumpError(hr, error, "DsGetDcName");
  45. }
  46. // Bind to the target DS
  47. dwNetStatus=DsBind(
  48. pDcInfo->DomainControllerName, // DC Address
  49. NULL, // DNS domain name
  50. &hDs ); // DS handle
  51. if (NO_ERROR!=dwNetStatus) {
  52. hr=HRESULT_FROM_WIN32(dwNetStatus);
  53. _JumpError(hr, error, "DsBind");
  54. }
  55. // Get the list of DCs from the target DS.
  56. dwNetStatus=DsGetDomainControllerInfo(
  57. hDs, // DS handle
  58. pDcInfo->DomainName, // domain name
  59. 1, // Info level
  60. &dwDcCount, // number of names returned
  61. (void **)&rgDsDcInfo); // array of names
  62. if (NO_ERROR!=dwNetStatus ) {
  63. hr=HRESULT_FROM_WIN32(dwNetStatus);
  64. _JumpError(hr, error, "DsGetDomainControllerInfo");
  65. }
  66. // figure out how many DCs there are with DNS names
  67. nDcs=0;
  68. for (nIndex=0; nIndex<dwDcCount; nIndex++) {
  69. if (NULL!=rgDsDcInfo[nIndex].DnsHostName) {
  70. nDcs++;
  71. }
  72. }
  73. if (nDcs<dwDcCount) {
  74. DebugWPrintf2(L"Found %u non-DNS DCs out of %u, which will be ignored.\n", dwDcCount-nDcs, dwDcCount);
  75. }
  76. if (0==nDcs) {
  77. hr=HRESULT_FROM_WIN32(ERROR_DOMAIN_CONTROLLER_NOT_FOUND); // no usable DCs
  78. _JumpError(hr, error, "Search rgDsDcInfo for usable DCs");
  79. }
  80. // allocate the list
  81. rgDcs=(DcInfo *)LocalAlloc(LPTR, sizeof(DcInfo)*nDcs);
  82. _JumpIfOutOfMemory(hr, error, rgDcs);
  83. // copy the names into it
  84. nDcIndex=0;
  85. for (nIndex=0; nIndex<dwDcCount; nIndex++) {
  86. if (NULL!=rgDsDcInfo[nIndex].DnsHostName) {
  87. // allocate and copy name
  88. rgDcs[nDcIndex].wszDnsName=(WCHAR *)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(rgDsDcInfo[nIndex].DnsHostName)+1));
  89. _JumpIfOutOfMemory(hr, error, rgDcs[nDcIndex].wszDnsName);
  90. wcscpy(rgDcs[nDcIndex].wszDnsName, rgDsDcInfo[nIndex].DnsHostName);
  91. //_Verify(NULL!=rgDsDcInfo[nIndex].NetbiosName, hr, error);
  92. //rgDcs[nDcIndex].wszDnsName=(WCHAR *)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(rgDsDcInfo[nIndex].NetbiosName)+1));
  93. //_JumpIfOutOfMemory(hr, error, rgDcs[nDcIndex].wszDnsName);
  94. //wcscpy(rgDcs[nDcIndex].wszDnsName, rgDsDcInfo[nIndex].NetbiosName);
  95. // copy PDCness
  96. rgDcs[nDcIndex].bIsPdc=rgDsDcInfo[nIndex].fIsPdc?true:false;
  97. nDcIndex++;
  98. }
  99. }
  100. // move the data to the out parameters
  101. *prgDcs=rgDcs;
  102. rgDcs=NULL;
  103. *pnDcs=nDcs;
  104. hr=S_OK;
  105. error:
  106. if (NULL!=rgDcs) {
  107. for (nIndex=0; nIndex<nDcs; nIndex++) {
  108. FreeDcInfo(&rgDcs[nIndex]);
  109. }
  110. LocalFree(rgDcs);
  111. }
  112. if (NULL!=rgDsDcInfo ) {
  113. DsFreeDomainControllerInfo(1, dwDcCount, rgDsDcInfo);
  114. }
  115. if (NULL!=hDs) {
  116. DsUnBind(&hDs);
  117. }
  118. if (NULL!=pDcInfo) {
  119. NetApiBufferFree(pDcInfo);
  120. }
  121. return hr;
  122. }
  123. //--------------------------------------------------------------------
  124. MODULEPRIVATE HRESULT GetDcListFromNetlogon(const WCHAR * wszDomainName, DcInfo ** prgDcs, unsigned int * pnDcs)
  125. {
  126. HRESULT hr;
  127. NET_API_STATUS dwNetStatus;
  128. DWORD dwEntriesRead;
  129. DWORD dwTotalEntries;
  130. unsigned int nIndex;
  131. unsigned int nDcIndex;
  132. unsigned int nDcs;
  133. // varaibles that must be cleaned up
  134. DcInfo * rgDcs=NULL;
  135. SERVER_INFO_101 * rgsiServerInfo=NULL;
  136. // initialize out variables
  137. *prgDcs=NULL;
  138. *pnDcs=0;
  139. // enumerate all PDC and BDCs
  140. dwNetStatus=NetServerEnum(
  141. NULL, // server to query
  142. 101, // info level
  143. (BYTE **)&rgsiServerInfo, // output buffer
  144. MAX_PREFERRED_LENGTH, // desired return buf size
  145. &dwEntriesRead, // entries in output buffer
  146. &dwTotalEntries, // total number of entries available
  147. SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL, // server type to find
  148. wszDomainName, // domain to search
  149. NULL); // reserved
  150. if (NO_ERROR!=dwNetStatus ) {
  151. hr=HRESULT_FROM_WIN32(dwNetStatus);
  152. _JumpError(hr, error, "NetServerEnum");
  153. }
  154. // count how many NT 5 servers there are
  155. nDcs=0;
  156. for (nIndex=0; nIndex<dwEntriesRead; nIndex++) {
  157. if (0!=(rgsiServerInfo[nIndex].sv101_type&SV_TYPE_NT)
  158. && rgsiServerInfo[nIndex].sv101_version_major>=5) {
  159. nDcs++;
  160. }
  161. }
  162. if (nDcs<dwEntriesRead) {
  163. DebugWPrintf2(L"Found %u non-NT5 DCs out of %u, which will be ignored.\n", dwEntriesRead-nDcs, dwEntriesRead);
  164. }
  165. if (0==nDcs) {
  166. hr=HRESULT_FROM_WIN32(ERROR_DOMAIN_CONTROLLER_NOT_FOUND); // no usable DCs
  167. _JumpError(hr, error, "Search rgsiServerInfo for usable DCs");
  168. }
  169. // allocate the list
  170. rgDcs=(DcInfo *)LocalAlloc(LPTR, sizeof(DcInfo)*nDcs);
  171. _JumpIfOutOfMemory(hr, error, rgDcs);
  172. // copy the names into it
  173. nDcIndex=0;
  174. for (nIndex=0; nIndex<dwEntriesRead; nIndex++) {
  175. if (0!=(rgsiServerInfo[nIndex].sv101_type&SV_TYPE_NT)
  176. && rgsiServerInfo[nIndex].sv101_version_major>=5) {
  177. // allocate and copy name
  178. rgDcs[nDcIndex].wszDnsName=(WCHAR *)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(rgsiServerInfo[nIndex].sv101_name)+1));
  179. _JumpIfOutOfMemory(hr, error, rgDcs[nDcIndex].wszDnsName);
  180. wcscpy(rgDcs[nDcIndex].wszDnsName, rgsiServerInfo[nIndex].sv101_name);
  181. // copy PDCness
  182. rgDcs[nDcIndex].bIsPdc=(rgsiServerInfo[nIndex].sv101_type&SV_TYPE_DOMAIN_CTRL)?true:false;
  183. nDcIndex++;
  184. }
  185. }
  186. // move the data to the out parameters
  187. *prgDcs=rgDcs;
  188. rgDcs=NULL;
  189. *pnDcs=nDcs;
  190. hr=S_OK;
  191. error:
  192. if (NULL!=rgDcs) {
  193. for (nIndex=0; nIndex<nDcs; nIndex++) {
  194. FreeDcInfo(&rgDcs[nIndex]);
  195. }
  196. LocalFree(rgDcs);
  197. }
  198. if (NULL!=rgsiServerInfo) {
  199. NetApiBufferFree(rgsiServerInfo);
  200. }
  201. return hr;
  202. }
  203. //--------------------------------------------------------------------
  204. MODULEPRIVATE HRESULT FillInIpAddresses(DcInfo * pdi) {
  205. HRESULT hr;
  206. DWORD dwDataLen;
  207. unsigned int nIndex;
  208. // pointers that must be cleaned up
  209. HANDLE hSearch=INVALID_HANDLE_VALUE;
  210. WSAQUERYSETW * pqsResult=NULL;
  211. in_addr * rgiaLocalIpAddresses=NULL;
  212. in_addr * rgiaRemoteIpAddresses=NULL;
  213. DebugWPrintf1(L"Looking up server \"%s\":\n", pdi->wszDnsName);
  214. // initialize the search
  215. AFPROTOCOLS apInetUdp={AF_INET, IPPROTO_UDP};
  216. GUID guidNtp=SVCID_NTP_UDP;
  217. WSAQUERYSETW qsSearch;
  218. ZeroMemory(&qsSearch, sizeof(qsSearch));
  219. qsSearch.dwSize=sizeof(qsSearch);
  220. qsSearch.lpszServiceInstanceName=const_cast<WCHAR *>(pdi->wszDnsName);
  221. qsSearch.lpServiceClassId=&guidNtp;
  222. qsSearch.dwNameSpace=NS_ALL;
  223. qsSearch.dwNumberOfProtocols=1;
  224. qsSearch.lpafpProtocols=&apInetUdp;
  225. // begin the search
  226. if (SOCKET_ERROR==WSALookupServiceBegin(&qsSearch, LUP_RETURN_ADDR/*flags*/, &hSearch)) {
  227. hr=HRESULT_FROM_WIN32(WSAGetLastError());
  228. _JumpError(hr, error, "WSALookupServiceBegin");
  229. }
  230. // get the buffer size for the first result set
  231. //dwDataLen=1;
  232. //_Verify(SOCKET_ERROR==WSALookupServiceNext(hSearch, LUP_RETURN_ADDR/*flags*/, &dwDataLen, &qsSearch), hr, error);
  233. //hr=WSAGetLastError();
  234. //if (WSAEFAULT!=hr) {
  235. // hr=HRESULT_FROM_WIN32(hr);
  236. // _JumpError(hr, error, "WSALookupServiceNext(1)");
  237. //}
  238. dwDataLen=5*1024;
  239. // allocate the buffer
  240. pqsResult=(WSAQUERYSETW *)LocalAlloc(LPTR, dwDataLen);
  241. _JumpIfOutOfMemory(hr, error, pqsResult);
  242. // retrieve the result set
  243. if (SOCKET_ERROR==WSALookupServiceNext(hSearch, LUP_RETURN_ADDR/*flags*/, &dwDataLen, pqsResult)) {
  244. hr=HRESULT_FROM_WIN32(WSAGetLastError());
  245. _JumpError(hr, error, "WSALookupServiceNext(2)");
  246. }
  247. _Verify(0!=pqsResult->dwNumberOfCsAddrs, hr, error) ;
  248. // allocate room for the IP addresses
  249. rgiaLocalIpAddresses=(in_addr *)LocalAlloc(LPTR, sizeof(in_addr)*pqsResult->dwNumberOfCsAddrs);
  250. _JumpIfOutOfMemory(hr, error, rgiaLocalIpAddresses);
  251. rgiaRemoteIpAddresses=(in_addr *)LocalAlloc(LPTR, sizeof(in_addr)*pqsResult->dwNumberOfCsAddrs);
  252. _JumpIfOutOfMemory(hr, error, rgiaRemoteIpAddresses);
  253. // copy the IP addresses
  254. for (nIndex=0; nIndex<pqsResult->dwNumberOfCsAddrs; nIndex++) {
  255. // copy local
  256. _Verify(sizeof(sockaddr)==pqsResult->lpcsaBuffer[nIndex].LocalAddr.iSockaddrLength, hr, error);
  257. _Verify(AF_INET==pqsResult->lpcsaBuffer[nIndex].LocalAddr.lpSockaddr->sa_family, hr, error);
  258. rgiaLocalIpAddresses[nIndex].S_un.S_addr=((sockaddr_in *)(pqsResult->lpcsaBuffer[nIndex].LocalAddr.lpSockaddr))->sin_addr.S_un.S_addr;
  259. // copy remote
  260. _Verify(sizeof(sockaddr)==pqsResult->lpcsaBuffer[nIndex].RemoteAddr.iSockaddrLength, hr, error);
  261. _Verify(AF_INET==pqsResult->lpcsaBuffer[nIndex].RemoteAddr.lpSockaddr->sa_family, hr, error);
  262. rgiaRemoteIpAddresses[nIndex].S_un.S_addr=((sockaddr_in *)(pqsResult->lpcsaBuffer[nIndex].RemoteAddr.lpSockaddr))->sin_addr.S_un.S_addr;
  263. }
  264. // move the data to the out parameters
  265. pdi->nIpAddresses=pqsResult->dwNumberOfCsAddrs;
  266. pdi->rgiaLocalIpAddresses=rgiaLocalIpAddresses;
  267. rgiaLocalIpAddresses=NULL;
  268. pdi->rgiaRemoteIpAddresses=rgiaRemoteIpAddresses;
  269. rgiaRemoteIpAddresses=NULL;
  270. hr=S_OK;
  271. error:
  272. if (NULL!=rgiaLocalIpAddresses) {
  273. LocalFree(rgiaLocalIpAddresses);
  274. }
  275. if (NULL!=rgiaRemoteIpAddresses) {
  276. LocalFree(rgiaRemoteIpAddresses);
  277. }
  278. if (NULL!=pqsResult) {
  279. LocalFree(pqsResult);
  280. }
  281. if (INVALID_HANDLE_VALUE!=hSearch) {
  282. if (SOCKET_ERROR==WSALookupServiceEnd(hSearch)) {
  283. HRESULT hr2=HRESULT_FROM_WIN32(WSAGetLastError());
  284. _IgnoreError(hr2, "WSALookupServiceEnd");
  285. }
  286. }
  287. return hr;
  288. }
  289. //####################################################################
  290. // Globals
  291. //--------------------------------------------------------------------
  292. void FreeDcInfo(DcInfo * pdci) {
  293. if (NULL!=pdci->wszDnsName) {
  294. LocalFree(pdci->wszDnsName);
  295. }
  296. if (NULL!=pdci->rgiaLocalIpAddresses) {
  297. LocalFree(pdci->rgiaLocalIpAddresses);
  298. }
  299. if (NULL!=pdci->rgiaRemoteIpAddresses) {
  300. LocalFree(pdci->rgiaRemoteIpAddresses);
  301. }
  302. }
  303. //--------------------------------------------------------------------
  304. // Get a list of DCs in this domain
  305. HRESULT GetDcList(const WCHAR * wszDomainName, bool bGetIps, DcInfo ** prgDcs, unsigned int * pnDcs)
  306. {
  307. HRESULT hr;
  308. unsigned int nDcs;
  309. unsigned int nIndex;
  310. // varaibles that must be cleaned up
  311. DcInfo * rgDcs=NULL;
  312. // initialize out variables
  313. *prgDcs=NULL;
  314. *pnDcs=0;
  315. hr=GetDcListFromDs(wszDomainName, &rgDcs, &nDcs);
  316. if (FAILED(hr)) {
  317. _IgnoreError(hr, "GetDcListFromDs");
  318. hr=GetDcListFromNetlogon(wszDomainName, &rgDcs, &nDcs);
  319. _JumpIfError(hr, error, "GetDcListFromNetlogon");
  320. }
  321. if (bGetIps) {
  322. // get the info about the DCs
  323. for (nIndex=0; nIndex<nDcs; nIndex++) {
  324. hr=FillInIpAddresses(&rgDcs[nIndex]);
  325. if (FAILED(hr)) {
  326. _IgnoreError(hr, "FillInIpAddresses");
  327. if (nIndex!=nDcs-1) {
  328. // swap it with the last one
  329. WCHAR * wszDnsName=rgDcs[nIndex].wszDnsName;
  330. rgDcs[nIndex].wszDnsName=rgDcs[nDcs-1].wszDnsName;
  331. rgDcs[nDcs-1].wszDnsName=wszDnsName;
  332. in_addr * rgiaLocalIpAddresses=rgDcs[nIndex].rgiaLocalIpAddresses;
  333. rgDcs[nIndex].rgiaLocalIpAddresses=rgDcs[nDcs-1].rgiaLocalIpAddresses;
  334. rgDcs[nDcs-1].rgiaLocalIpAddresses=rgiaLocalIpAddresses;
  335. in_addr * rgiaRemoteIpAddresses=rgDcs[nIndex].rgiaRemoteIpAddresses;
  336. rgDcs[nIndex].rgiaRemoteIpAddresses=rgDcs[nDcs-1].rgiaRemoteIpAddresses;
  337. rgDcs[nDcs-1].rgiaRemoteIpAddresses=rgiaRemoteIpAddresses;
  338. // non-pointers can just be copied
  339. rgDcs[nIndex].nIpAddresses=rgDcs[nDcs-1].nIpAddresses;
  340. rgDcs[nIndex].bIsPdc=rgDcs[nDcs-1].bIsPdc;
  341. rgDcs[nIndex].bIsGoodTimeSource=rgDcs[nDcs-1].bIsGoodTimeSource;
  342. }
  343. DebugWPrintf1(L"Dropping '%s' because we cannot get an IP address.\n", rgDcs[nDcs-1].wszDnsName);
  344. nDcs--;
  345. nIndex--;
  346. }
  347. }
  348. }
  349. if (0==nDcs) {
  350. hr=HRESULT_FROM_WIN32(ERROR_DOMAIN_CONTROLLER_NOT_FOUND); // no usable DCs
  351. _JumpError(hr, error, "Getting IP address for at least one DC");
  352. }
  353. // move the data to the out parameters
  354. *prgDcs=rgDcs;
  355. rgDcs=NULL;
  356. *pnDcs=nDcs;
  357. hr=S_OK;
  358. error:
  359. if (NULL!=rgDcs) {
  360. for (nIndex=0; nIndex<nDcs; nIndex++) {
  361. FreeDcInfo(&rgDcs[nIndex]);
  362. }
  363. LocalFree(rgDcs);
  364. }
  365. return hr;
  366. }