Source code of Windows XP (NT5)
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.

1847 lines
54 KiB

  1. //++
  2. //
  3. // Copyright (C) Microsoft Corporation, 1987 - 1999
  4. //
  5. // Module Name:
  6. //
  7. // dclist.c
  8. //
  9. // Abstract:
  10. //
  11. // Queries into network drivers
  12. //
  13. // Author:
  14. //
  15. // Anilth - 4-20-1998
  16. //
  17. // Environment:
  18. //
  19. // User mode only.
  20. // Contains NT-specific code.
  21. //
  22. // Revision History:
  23. //
  24. //--
  25. #include "precomp.h"
  26. BOOL
  27. GetDcListFromDs(
  28. IN NETDIAG_PARAMS* pParams,
  29. IN OUT NETDIAG_RESULT* pResults,
  30. IN PTESTED_DOMAIN TestedDomain
  31. );
  32. BOOL
  33. GetDcListFromSam(
  34. IN NETDIAG_PARAMS* pParams,
  35. IN OUT NETDIAG_RESULT* pResults,
  36. IN PTESTED_DOMAIN TestedDomain
  37. );
  38. NET_API_STATUS
  39. GetBrowserServerList(
  40. IN PUNICODE_STRING TransportName,
  41. IN LPCWSTR Domain,
  42. OUT LPWSTR *BrowserList[],
  43. OUT PULONG BrowserListLength,
  44. IN BOOLEAN ForceRescan
  45. );
  46. NET_API_STATUS
  47. EnumServersForTransport(
  48. IN PUNICODE_STRING TransportName,
  49. IN LPCWSTR DomainName OPTIONAL,
  50. IN ULONG level,
  51. IN ULONG prefmaxlen,
  52. IN ULONG servertype,
  53. IN LPWSTR CurrentComputerName,
  54. OUT PINTERIM_SERVER_LIST InterimServerList,
  55. OUT PULONG TotalEntriesOnThisTransport,
  56. IN LPCWSTR FirstNameToReturn,
  57. IN BOOLEAN WannishTransport,
  58. IN BOOLEAN RasTransport,
  59. IN BOOLEAN IpxTransport
  60. );
  61. NET_API_STATUS NET_API_FUNCTION
  62. LocalNetServerEnumEx(
  63. IN LPCWSTR servername OPTIONAL,
  64. IN DWORD level,
  65. OUT LPBYTE *bufptr,
  66. IN DWORD prefmaxlen,
  67. OUT LPDWORD entriesread,
  68. OUT LPDWORD totalentries,
  69. IN DWORD servertype,
  70. IN LPCWSTR domain OPTIONAL,
  71. IN LPCWSTR FirstNameToReturnArg OPTIONAL,
  72. IN NETDIAG_PARAMS *pParams,
  73. IN OUT NETDIAG_RESULT *pResults
  74. );
  75. BOOL GetDcListFromDc(IN NETDIAG_PARAMS *pParams,
  76. IN OUT NETDIAG_RESULT *pResults,
  77. IN PTESTED_DOMAIN TestedDomain);
  78. HRESULT
  79. DcListTest(NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults)
  80. /*++
  81. Routine Description:
  82. This test builds a list of all the DCs in the tested domains.
  83. Arguments:
  84. None.
  85. Return Value:
  86. TRUE: Test suceeded.
  87. FALSE: Test failed
  88. --*/
  89. {
  90. HRESULT hrRetVal = S_OK;
  91. PTESTED_DOMAIN pTestedDomain = (PTESTED_DOMAIN) pParams->pDomain;
  92. NET_API_STATUS NetStatus;
  93. PSERVER_INFO_101 ServerInfo101 = NULL;
  94. DWORD EntriesRead;
  95. DWORD TotalEntries;
  96. PTESTED_DC TestedDc = NULL;
  97. PLIST_ENTRY ListEntry;
  98. ULONG i;
  99. PrintStatusMessage(pParams, 0, IDS_DCLIST_STATUS_MSG, pTestedDomain->PrintableDomainName);
  100. //if the machine is a member machine or DC, DcListTest will get called.
  101. //Otherwise, DcList test will be skipped
  102. pResults->DcList.fPerformed = TRUE;
  103. //the Dclist test will be called for every domain, but we only want to initialize
  104. //the message list once.
  105. if(pResults->DcList.lmsgOutput.Flink == NULL)
  106. InitializeListHead( &pResults->DcList.lmsgOutput );
  107. //
  108. // First try getting the list of DCs from the DS
  109. //
  110. if ( !GetDcListFromDs( pParams, pResults, pTestedDomain ) ) {
  111. pResults->DcList.hr = S_FALSE;
  112. hrRetVal = S_FALSE;
  113. }
  114. //
  115. // If that failed,
  116. // then try using the browser.
  117. //
  118. if( FHrOK(pResults->DcList.hr) )
  119. {
  120. if ( pTestedDomain->NetbiosDomainName )
  121. {
  122. NetStatus = LocalNetServerEnumEx(
  123. NULL,
  124. 101,
  125. (LPBYTE *)&ServerInfo101,
  126. MAX_PREFERRED_LENGTH,
  127. &EntriesRead,
  128. &TotalEntries,
  129. SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL,
  130. pTestedDomain->NetbiosDomainName,
  131. NULL, // Resume handle
  132. pParams,
  133. pResults);
  134. if ( NetStatus != NERR_Success && NetStatus != ERROR_MORE_DATA )
  135. {
  136. // "NetServerEnum failed. [%s]\n"
  137. SetMessage(&pResults->DcList.msgErr, Nd_Quiet,
  138. IDS_DCLIST_NETSERVERENUM_FAILED, NetStatusToString(NetStatus));
  139. pResults->DcList.hr = HResultFromWin32(NetStatus);
  140. hrRetVal = S_FALSE;
  141. goto LERROR;
  142. }
  143. for ( i=0; i<EntriesRead; i++ )
  144. {
  145. //
  146. // Skip non-NT entries
  147. //
  148. if ( (ServerInfo101[i].sv101_type & SV_TYPE_NT) == 0 ) {
  149. continue;
  150. }
  151. AddTestedDc( pParams,
  152. pResults,
  153. pTestedDomain,
  154. ServerInfo101[i].sv101_name,
  155. ServerInfo101[i].sv101_version_major >= 5 ?
  156. DC_IS_NT5 :
  157. DC_IS_NT4 );
  158. }
  159. }
  160. else
  161. {
  162. if ( pParams->fDebugVerbose )
  163. {
  164. // "'%ws' is not a Netbios domain name. Cannot use NetServerEnum to find DCs\n"
  165. PrintMessage(pParams, IDS_DCLIST_NOT_A_NETBIOS_DOMAIN,
  166. pTestedDomain->PrintableDomainName);
  167. }
  168. }
  169. }
  170. //
  171. // If we're really interested,
  172. // get a list from SAM on the discovered DC.
  173. // (But it's really slow)
  174. //
  175. if ( pParams->fDcAccountEnum ) {
  176. if ( !GetDcListFromSam( pParams, pResults, pTestedDomain ) ) {
  177. pResults->DcList.hr = S_FALSE;
  178. hrRetVal = S_FALSE;
  179. }
  180. }
  181. LERROR:
  182. return hrRetVal;
  183. }
  184. NET_API_STATUS
  185. GetBrowserServerList(
  186. IN PUNICODE_STRING TransportName,
  187. IN LPCWSTR Domain,
  188. OUT LPWSTR *BrowserList[],
  189. OUT PULONG BrowserListLength,
  190. IN BOOLEAN ForceRescan
  191. )
  192. /*++
  193. Routine Description:
  194. This function will return a list of browser servers.
  195. Arguments:
  196. IN PUNICODE_STRING TransportName - Transport to return list.
  197. Return Value:
  198. NET_API_STATUS - NERR_Success or reason for failure.
  199. --*/
  200. {
  201. NET_API_STATUS Status;
  202. HANDLE BrowserHandle;
  203. PLMDR_REQUEST_PACKET RequestPacket = NULL;
  204. // DbgPrint("Getting browser server list for transport %wZ\n", TransportName);
  205. Status = OpenBrowser(&BrowserHandle);
  206. if (Status != NERR_Success) {
  207. return Status;
  208. }
  209. RequestPacket = Malloc( sizeof(LMDR_REQUEST_PACKET)+(DNLEN*sizeof(WCHAR))+TransportName->MaximumLength);
  210. if (RequestPacket == NULL) {
  211. NtClose(BrowserHandle);
  212. return(GetLastError());
  213. }
  214. ZeroMemory( RequestPacket, sizeof(LMDR_REQUEST_PACKET)+(DNLEN*sizeof(WCHAR))+TransportName->MaximumLength );
  215. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  216. RequestPacket->Level = 0;
  217. RequestPacket->Parameters.GetBrowserServerList.ForceRescan = ForceRescan;
  218. if (Domain != NULL)
  219. {
  220. wcscpy(RequestPacket->Parameters.GetBrowserServerList.DomainName, Domain);
  221. RequestPacket->Parameters.GetBrowserServerList.DomainNameLength = (USHORT)wcslen(Domain) * sizeof(WCHAR);
  222. }
  223. else
  224. {
  225. RequestPacket->Parameters.GetBrowserServerList.DomainNameLength = 0;
  226. RequestPacket->Parameters.GetBrowserServerList.DomainName[0] = L'\0';
  227. }
  228. RequestPacket->TransportName.Buffer = (PWSTR)((PCHAR)RequestPacket+sizeof(LMDR_REQUEST_PACKET)+DNLEN*sizeof(WCHAR));
  229. RequestPacket->TransportName.MaximumLength = TransportName->MaximumLength;
  230. RtlCopyUnicodeString(&RequestPacket->TransportName, TransportName);
  231. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, NULL );
  232. RequestPacket->Parameters.GetBrowserServerList.ResumeHandle = 0;
  233. Status = DeviceControlGetInfo(
  234. BrowserHandle,
  235. IOCTL_LMDR_GET_BROWSER_SERVER_LIST,
  236. RequestPacket,
  237. sizeof(LMDR_REQUEST_PACKET)+
  238. (DNLEN*sizeof(WCHAR))+TransportName->MaximumLength,
  239. (PVOID *)BrowserList,
  240. 0xffffffff,
  241. 4096,
  242. NULL);
  243. if (Status == NERR_Success)
  244. {
  245. *BrowserListLength = RequestPacket->Parameters.GetBrowserServerList.EntriesRead;
  246. }
  247. NtClose(BrowserHandle);
  248. Free(RequestPacket);
  249. return Status;
  250. }
  251. #define API_SUCCESS(x) ((x) == NERR_Success || (x) == ERROR_MORE_DATA)
  252. NET_API_STATUS
  253. EnumServersForTransport(
  254. IN PUNICODE_STRING TransportName,
  255. IN LPCWSTR DomainName OPTIONAL,
  256. IN ULONG level,
  257. IN ULONG prefmaxlen,
  258. IN ULONG servertype,
  259. IN LPWSTR CurrentComputerName,
  260. OUT PINTERIM_SERVER_LIST InterimServerList,
  261. OUT PULONG TotalEntriesOnThisTransport,
  262. IN LPCWSTR FirstNameToReturn,
  263. IN BOOLEAN WannishTransport,
  264. IN BOOLEAN RasTransport,
  265. IN BOOLEAN IpxTransport
  266. )
  267. {
  268. PWSTR *BrowserList = NULL;
  269. ULONG BrowserListLength = 0;
  270. NET_API_STATUS Status;
  271. PVOID ServerList = NULL;
  272. ULONG EntriesInList = 0;
  273. ULONG ServerIndex = 0;
  274. //
  275. // Skip over IPX transports - we can't contact machines over them anyway.
  276. //
  277. *TotalEntriesOnThisTransport = 0;
  278. if (IpxTransport) {
  279. return NERR_Success;
  280. }
  281. //
  282. // Retrieve a new browser list. Do not force a revalidation.
  283. //
  284. Status = GetBrowserServerList(TransportName,
  285. DomainName,
  286. &BrowserList,
  287. &BrowserListLength,
  288. FALSE);
  289. //
  290. // If a domain name was specified and we were unable to find the browse
  291. // master for the domain and we are running on a wannish transport,
  292. // invoke the "double hop" code and allow a local browser server
  293. // remote the API to the browse master for that domain (we assume that
  294. // this means that the workgroup is on a different subnet of a WAN).
  295. //
  296. if (!API_SUCCESS(Status) &&
  297. DomainName != NULL) {
  298. Status = GetBrowserServerList(TransportName,
  299. NULL,
  300. &BrowserList,
  301. &BrowserListLength,
  302. FALSE);
  303. }
  304. //
  305. // If we were able to retrieve the list, remote the API. Otherwise
  306. // return.
  307. //
  308. if (API_SUCCESS(Status)) {
  309. do {
  310. LPWSTR Transport;
  311. LPWSTR ServerName;
  312. BOOL AlreadyInTree;
  313. //
  314. // Remote the API to that server.
  315. //
  316. Transport = TransportName->Buffer;
  317. ServerName = BrowserList[0];
  318. *TotalEntriesOnThisTransport = 0;
  319. Status = RxNetServerEnum(
  320. ServerName,
  321. Transport,
  322. level,
  323. (LPBYTE *)&ServerList,
  324. prefmaxlen,
  325. &EntriesInList,
  326. TotalEntriesOnThisTransport,
  327. servertype,
  328. DomainName,
  329. FirstNameToReturn );
  330. if ( !API_SUCCESS(Status)) {
  331. NET_API_STATUS GetBListStatus;
  332. //
  333. // If we failed to remote the API for some reason,
  334. // we want to regenerate the bowsers list of browser
  335. // servers.
  336. //
  337. if (BrowserList != NULL) {
  338. LocalFree(BrowserList);
  339. BrowserList = NULL;
  340. }
  341. GetBListStatus = GetBrowserServerList(TransportName,
  342. DomainName,
  343. &BrowserList,
  344. &BrowserListLength,
  345. TRUE);
  346. if (GetBListStatus != NERR_Success) {
  347. //
  348. // If we were unable to reload the list,
  349. // try the next transport.
  350. //
  351. break;
  352. }
  353. ServerIndex += 1;
  354. //
  355. // If we've looped more times than we got servers
  356. // in the list, we're done.
  357. //
  358. if ( ServerIndex > BrowserListLength ) {
  359. break;
  360. }
  361. } else {
  362. NET_API_STATUS TempStatus;
  363. TempStatus = MergeServerList(
  364. InterimServerList,
  365. level,
  366. ServerList,
  367. EntriesInList,
  368. *TotalEntriesOnThisTransport );
  369. if ( TempStatus != NERR_Success ) {
  370. Status = TempStatus;
  371. }
  372. //
  373. // The remote API succeeded.
  374. //
  375. // Now free up the remaining parts of the list.
  376. //
  377. if (ServerList != NULL) {
  378. NetApiBufferFree(ServerList);
  379. ServerList = NULL;
  380. }
  381. // We're done regardless of the success or failure of MergeServerList.
  382. break;
  383. }
  384. } while ( !API_SUCCESS(Status) );
  385. }
  386. //
  387. // Free up the browser list.
  388. //
  389. if (BrowserList != NULL) {
  390. LocalFree(BrowserList);
  391. BrowserList = NULL;
  392. }
  393. return Status;
  394. }
  395. NET_API_STATUS NET_API_FUNCTION
  396. LocalNetServerEnumEx(
  397. IN LPCWSTR servername OPTIONAL,
  398. IN DWORD level,
  399. OUT LPBYTE *bufptr,
  400. IN DWORD prefmaxlen,
  401. OUT LPDWORD entriesread,
  402. OUT LPDWORD totalentries,
  403. IN DWORD servertype,
  404. IN LPCWSTR domain OPTIONAL,
  405. IN LPCWSTR FirstNameToReturnArg OPTIONAL,
  406. IN NETDIAG_PARAMS *pParams,
  407. IN OUT NETDIAG_RESULT *pResults
  408. )
  409. /*++
  410. Routine Description:
  411. This is identical to the real NetServerEnumEx except it only uses the
  412. Netbt transport that the nettest utility has found.
  413. Arguments:
  414. servername - Supplies the name of server to execute this function
  415. level - Supplies the requested level of information.
  416. bufptr - Returns a pointer to a buffer which contains the
  417. requested transport information.
  418. prefmaxlen - Supplies the number of bytes of information
  419. to return in the buffer. If this value is MAXULONG, we will try
  420. to return all available information if there is enough memory
  421. resource.
  422. entriesread - Returns the number of entries read into the buffer. This
  423. value is returned only if the return code is NERR_Success or
  424. ERROR_MORE_DATA.
  425. totalentries - Returns the total number of entries available. This value
  426. is returned only if the return code is NERR_Success or ERROR_MORE_DATA.
  427. servertype - Supplies the type of server to enumerate.
  428. domain - Supplies the name of one of the active domains to enumerate the
  429. servers from. If NULL, servers from the primary domain, logon domain
  430. and other domains are enumerated.
  431. FirstNameToReturnArg - Supplies the name of the first domain or server entry to return.
  432. The caller can use this parameter to implement a resume handle of sorts by passing
  433. the name of the last entry returned on a previous call. (Notice that the specified
  434. entry will, also, be returned on this call unless it has since been deleted.)
  435. Pass NULL (or a zero length string) to start with the first entry available.
  436. Return Value:
  437. NET_API_STATUS - NERR_Success or reason for failure.
  438. ERROR_MORE_DATA - More servers are available to be enumerated.
  439. It is possible to return ERROR_MORE_DATA and zero entries in the case
  440. where the browser server used doesn't support enumerating all the entries
  441. it has. (e.g., an NT 3.5x Domain Master Browser that downloaded a domain
  442. list from WINS and the WINS list is more than 64Kb long.) The caller
  443. should simply ignore the additional data.
  444. It is possible to fail to return ERROR_MORE_DATA and return a truncated
  445. list. (e.g., an NT 3.5x Backup browser or WIN 95 backup browser in the
  446. above mentioned domain. Such a backup browser replicates only 64kb
  447. of data from the DMB (PDC) then represents that list as the entire list.)
  448. The caller should ignore this problem. The site should upgrade its
  449. browser servers.
  450. --*/
  451. {
  452. INTERIM_SERVER_LIST InterimServerList;
  453. NET_API_STATUS Status;
  454. DWORD DomainNameSize = 0;
  455. WCHAR DomainName[DNLEN + 1];
  456. WCHAR FirstNameToReturn[DNLEN+1];
  457. DWORD LocalTotalEntries;
  458. BOOLEAN AnyTransportHasMoreData = FALSE;
  459. //
  460. // Canonicalize the input parameters to make later comparisons easier.
  461. //
  462. if (ARGUMENT_PRESENT(domain)) {
  463. if ( I_NetNameCanonicalize(
  464. NULL,
  465. (LPWSTR) domain,
  466. DomainName,
  467. (DNLEN + 1) * sizeof(WCHAR),
  468. NAMETYPE_WORKGROUP,
  469. LM2X_COMPATIBLE
  470. ) != NERR_Success) {
  471. return ERROR_INVALID_PARAMETER;
  472. }
  473. DomainNameSize = wcslen(DomainName) * sizeof(WCHAR);
  474. domain = DomainName;
  475. }
  476. if (ARGUMENT_PRESENT(FirstNameToReturnArg) && *FirstNameToReturnArg != L'\0') {
  477. if ( I_NetNameCanonicalize(
  478. NULL,
  479. (LPWSTR) FirstNameToReturnArg,
  480. FirstNameToReturn,
  481. sizeof(FirstNameToReturn),
  482. NAMETYPE_WORKGROUP,
  483. LM2X_COMPATIBLE
  484. ) != NERR_Success) {
  485. return ERROR_INVALID_PARAMETER;
  486. }
  487. } else {
  488. FirstNameToReturn[0] = L'\0';
  489. }
  490. if ((servername != NULL) &&
  491. ( *servername != L'\0')) {
  492. //
  493. // Call downlevel version of the API
  494. //
  495. Status = RxNetServerEnum(
  496. servername,
  497. NULL,
  498. level,
  499. bufptr,
  500. prefmaxlen,
  501. entriesread,
  502. totalentries,
  503. servertype,
  504. domain,
  505. FirstNameToReturn );
  506. return Status;
  507. }
  508. //
  509. // Only levels 100 and 101 are valid
  510. //
  511. if ((level != 100) && (level != 101)) {
  512. return ERROR_INVALID_LEVEL;
  513. }
  514. if (servertype != SV_TYPE_ALL) {
  515. if (servertype & SV_TYPE_DOMAIN_ENUM) {
  516. if (servertype != SV_TYPE_DOMAIN_ENUM) {
  517. return ERROR_INVALID_FUNCTION;
  518. }
  519. }
  520. }
  521. //
  522. // Initialize the buffer to a known value.
  523. //
  524. *bufptr = NULL;
  525. *entriesread = 0;
  526. *totalentries = 0;
  527. Status = InitializeInterimServerList(&InterimServerList, NULL, NULL, NULL, NULL);
  528. try {
  529. BOOL AnyEnumServersSucceeded = FALSE;
  530. LPWSTR MyComputerName = NULL;
  531. PLIST_ENTRY ListEntry;
  532. PNETBT_TRANSPORT NetbtTransport;
  533. Status = NetpGetComputerName( &MyComputerName);
  534. if ( Status != NERR_Success ) {
  535. goto try_exit;
  536. }
  537. //
  538. // Loop through the list of netbt transports browsing on each one
  539. //
  540. for ( ListEntry = pResults->NetBt.Transports.Flink ;
  541. ListEntry != &pResults->NetBt.Transports ;
  542. ListEntry = ListEntry->Flink ) {
  543. UNICODE_STRING TransportName;
  544. //
  545. // If the transport names match,
  546. // return the entry
  547. //
  548. NetbtTransport = CONTAINING_RECORD( ListEntry, NETBT_TRANSPORT, Next );
  549. if ( (NetbtTransport->Flags & BOUND_TO_BOWSER) == 0 ) {
  550. continue;
  551. }
  552. RtlInitUnicodeString( &TransportName, NetbtTransport->pswzTransportName );
  553. Status = EnumServersForTransport(&TransportName,
  554. domain,
  555. level,
  556. prefmaxlen,
  557. servertype,
  558. MyComputerName,
  559. &InterimServerList,
  560. &LocalTotalEntries,
  561. FirstNameToReturn,
  562. FALSE,
  563. FALSE,
  564. FALSE );
  565. if (API_SUCCESS(Status)) {
  566. if ( Status == ERROR_MORE_DATA ) {
  567. AnyTransportHasMoreData = TRUE;
  568. }
  569. AnyEnumServersSucceeded = TRUE;
  570. if ( LocalTotalEntries > *totalentries ) {
  571. *totalentries = LocalTotalEntries;
  572. }
  573. }
  574. }
  575. if ( MyComputerName != NULL ) {
  576. (void) NetApiBufferFree( MyComputerName );
  577. }
  578. if (AnyEnumServersSucceeded) {
  579. //
  580. // Pack the interim server list into its final form.
  581. //
  582. Status = PackServerList(&InterimServerList,
  583. level,
  584. servertype,
  585. prefmaxlen,
  586. (PVOID *)bufptr,
  587. entriesread,
  588. &LocalTotalEntries, // Pack thinks it has ALL the entries
  589. NULL ); // The server has already returned us the right entries
  590. if ( API_SUCCESS( Status ) ) {
  591. if ( LocalTotalEntries > *totalentries ) {
  592. *totalentries = LocalTotalEntries;
  593. }
  594. }
  595. }
  596. try_exit:NOTHING;
  597. } finally {
  598. UninitializeInterimServerList(&InterimServerList);
  599. }
  600. if ( API_SUCCESS( Status )) {
  601. //
  602. // At this point,
  603. // *totalentries is the largest of:
  604. // The TotalEntries returned from any transport.
  605. // The actual number of entries read.
  606. //
  607. // Adjust TotalEntries returned for reality.
  608. //
  609. if ( Status == NERR_Success ) {
  610. *totalentries = *entriesread;
  611. } else {
  612. if ( *totalentries <= *entriesread ) {
  613. *totalentries = *entriesread + 1;
  614. }
  615. }
  616. //
  617. // Ensure we return ERROR_MORE_DATA if any transport has more data.
  618. //
  619. if ( AnyTransportHasMoreData ) {
  620. Status = ERROR_MORE_DATA;
  621. }
  622. }
  623. return Status;
  624. }
  625. BOOL
  626. GetDcListFromDs(
  627. IN NETDIAG_PARAMS* pParams,
  628. IN OUT NETDIAG_RESULT* pResults,
  629. IN PTESTED_DOMAIN TestedDomain
  630. )
  631. /*++
  632. Routine Description:
  633. Get a list of DCs in this domain from the DS on an up DC.
  634. Arguments:
  635. TestedDomain - Domain to get the DC list for
  636. Return Value:
  637. TRUE: Test suceeded.
  638. FALSE: Test failed
  639. --*/
  640. {
  641. NET_API_STATUS NetStatus;
  642. PDS_DOMAIN_CONTROLLER_INFO_1W DcInfo = NULL;
  643. HANDLE DsHandle = NULL;
  644. DWORD DcCount;
  645. BOOL RetVal = TRUE;
  646. ULONG i;
  647. const WCHAR c_szDcPrefix[] = L"\\\\";
  648. LPWSTR pwszDcName;
  649. LPTSTR pszDcType;
  650. PTESTED_DC TestedDc;
  651. //
  652. // Get a DC to seed the algorithm with
  653. //
  654. if ( TestedDomain->DcInfo == NULL ) {
  655. if ( TestedDomain->fTriedToFindDcInfo ) {
  656. //" '%ws': Cannot find DC to get DC list from.\n"
  657. AddMessageToList(&pResults->DcList.lmsgOutput, Nd_Quiet, IDS_DCLIST_NO_DC,
  658. TestedDomain->PrintableDomainName );
  659. RetVal = FALSE;
  660. goto Cleanup;
  661. }
  662. pszDcType = LoadAndAllocString(IDS_DCTYPE_DC);
  663. NetStatus = DoDsGetDcName( pParams,
  664. pResults,
  665. &pResults->DcList.lmsgOutput,
  666. TestedDomain,
  667. DS_DIRECTORY_SERVICE_PREFERRED,
  668. pszDcType,
  669. FALSE,
  670. &TestedDomain->DcInfo );
  671. Free(pszDcType);
  672. TestedDomain->fTriedToFindDcInfo = TRUE;
  673. if ( NetStatus != NO_ERROR ) {
  674. //" '%ws': Cannot find DC to get DC list from.\n"
  675. AddMessageToList(&pResults->DcList.lmsgOutput, Nd_Quiet, IDS_DCLIST_NO_DC);
  676. AddIMessageToList(&pResults->DcList.lmsgOutput, Nd_Quiet, 4,
  677. IDS_GLOBAL_STATUS, NetStatusToString(NetStatus) );
  678. RetVal = FALSE;
  679. goto Cleanup;
  680. }
  681. }
  682. // if the DC doesn't support DS, we should not try to call DsBindW()
  683. if (!(TestedDomain->DcInfo->Flags & DS_DS_FLAG))
  684. goto Cleanup;
  685. //
  686. // Get a DC that's UP.
  687. //
  688. TestedDc = GetUpTestedDc( TestedDomain );
  689. if ( TestedDc == NULL ) {
  690. //IDS_DCLIST_NO_DC_UP " '%ws': No DCs are up.\n"
  691. AddMessageToList(&pResults->DcList.lmsgOutput, Nd_Quiet, IDS_DCLIST_NO_DC_UP,
  692. TestedDomain->PrintableDomainName );
  693. PrintGuruMessage2(" '%ws': No DCs are up.\n", TestedDomain->PrintableDomainName );
  694. PrintGuru( 0, DSGETDC_GURU );
  695. RetVal = FALSE;
  696. goto Cleanup;
  697. }
  698. //
  699. // Bind to the target DC
  700. //
  701. pwszDcName = Malloc((wcslen(TestedDc->ComputerName) + wcslen(c_szDcPrefix) + 1) * sizeof(WCHAR));
  702. if (pwszDcName == NULL)
  703. {
  704. DebugMessage("Out of Memory!");
  705. RetVal = FALSE;
  706. goto Cleanup;
  707. }
  708. wcscpy(pwszDcName, c_szDcPrefix);
  709. assert(TestedDc->ComputerName);
  710. if (TestedDc->ComputerName)
  711. {
  712. wcscat(pwszDcName, TestedDc->ComputerName);
  713. }
  714. NetStatus = DsBindW( pwszDcName,
  715. NULL,
  716. &DsHandle );
  717. Free(pwszDcName);
  718. if ( NetStatus != NO_ERROR ) {
  719. //
  720. // Only warn if we don't have access
  721. //
  722. if ( NetStatus == ERROR_ACCESS_DENIED ) {
  723. //IDS_DCLIST_NO_ACCESS_DSBIND " You don't have access to DsBind to %ws (%ws) (Trying NetServerEnum). [%s]\n"
  724. AddMessageToList(&pResults->DcList.lmsgOutput, Nd_ReallyVerbose, IDS_DCLIST_NO_ACCESS_DSBIND,
  725. TestedDc->NetbiosDcName,
  726. TestedDc->DcIpAddress,
  727. NetStatusToString(NetStatus));
  728. } else {
  729. //IDS_DCLIST_ERR_DSBIND " [WARNING] Cannot call DsBind to %ws (%ws). [%s]\n"
  730. AddMessageToList(&pResults->DcList.lmsgOutput, Nd_Quiet, IDS_DCLIST_ERR_DSBIND,
  731. TestedDc->ComputerName,
  732. TestedDc->DcIpAddress,
  733. NetStatusToString(NetStatus));
  734. PrintGuruMessage3(" [WARNING] Cannot call DsBind to %ws (%ws).\n",
  735. TestedDc->NetbiosDcName,
  736. TestedDc->DcIpAddress );
  737. PrintGuru( NetStatus, DS_GURU );
  738. }
  739. RetVal = FALSE;
  740. goto Cleanup;
  741. }
  742. //
  743. // Get the list of DCs from the target DC.
  744. //
  745. NetStatus = DsGetDomainControllerInfoW(
  746. DsHandle,
  747. TestedDomain->DnsDomainName != NULL ?
  748. TestedDomain->DnsDomainName :
  749. TestedDomain->NetbiosDomainName,
  750. 1, // Info level
  751. &DcCount,
  752. &DcInfo );
  753. if ( NetStatus != NO_ERROR ) {
  754. //IDS_DCLIST_ERR_GETDCINFO " [WARNING] Cannot call DsGetDomainControllerInfoW to %ws (%ws). [%s]\n"
  755. AddMessageToList( &pResults->DcList.lmsgOutput, Nd_Quiet, IDS_DCLIST_ERR_GETDCINFO,
  756. TestedDc->NetbiosDcName,
  757. TestedDc->DcIpAddress, NetStatusToString(NetStatus) );
  758. PrintGuruMessage3(" [WARNING] Cannot call DsGetDomainControllerInfoW to %ws (%ws).",
  759. TestedDc->NetbiosDcName,
  760. TestedDc->DcIpAddress );
  761. PrintGuru( NetStatus, DS_GURU );
  762. RetVal = FALSE;
  763. goto Cleanup;
  764. }
  765. //
  766. // Loop though the list of DCs.
  767. //
  768. if(pParams->fDebugVerbose)
  769. {
  770. // IDS_DCLIST_DCS " DC list for domain %ws:\n"
  771. PrintMessage(pParams, IDS_DCLIST_DCS, TestedDomain->PrintableDomainName);
  772. }
  773. for ( i=0; i<DcCount; i++ )
  774. {
  775. if ( pParams->fDebugVerbose )
  776. {
  777. //IDS_DCLIST_13421 " %ws"
  778. PrintMessage(pParams, IDS_DCLIST_13421,
  779. DcInfo[i].DnsHostName != NULL ?
  780. DcInfo[i].DnsHostName :
  781. DcInfo[i].NetbiosName );
  782. if ( DcInfo[i].fIsPdc ) {
  783. //IDS_DCLIST_13422 " [PDC emulator]"
  784. //if is NT4 DC, just say PDC
  785. PrintMessage(pParams, DcInfo[i].fDsEnabled ? IDS_DCLIST_13422 : IDS_DCLIST_NT4_PDC);
  786. }
  787. if ( DcInfo[i].fDsEnabled ) {
  788. //IDS_DCLIST_13423 " [DS]"
  789. PrintMessage(pParams, IDS_DCLIST_13423);
  790. }
  791. if ( DcInfo[i].SiteName != NULL ) {
  792. //IDS_DCLIST_13424 " Site: %ws"
  793. PrintMessage(pParams, IDS_DCLIST_13424, DcInfo[i].SiteName );
  794. }
  795. //IDS_DCLIST_13425 "\n"
  796. PrintMessage(pParams, IDS_DCLIST_13425);
  797. }
  798. //
  799. // Add this DC to the list of DCs to test.
  800. //
  801. AddTestedDc( pParams,
  802. pResults,
  803. TestedDomain,
  804. DcInfo[i].DnsHostName != NULL ?
  805. DcInfo[i].DnsHostName :
  806. DcInfo[i].NetbiosName,
  807. DcInfo[i].fDsEnabled ?
  808. DC_IS_NT5 :
  809. DC_IS_NT4 );
  810. }
  811. //
  812. // Cleanup locally used resources
  813. //
  814. Cleanup:
  815. if ( DcInfo != NULL ) {
  816. DsFreeDomainControllerInfoW( 1, DcCount, DcInfo );
  817. }
  818. if ( DsHandle != NULL ) {
  819. DsUnBindW( &DsHandle );
  820. }
  821. return RetVal;
  822. }
  823. BOOL
  824. GetDcListFromSam(
  825. IN NETDIAG_PARAMS* pParams,
  826. IN OUT NETDIAG_RESULT* pResults,
  827. IN PTESTED_DOMAIN TestedDomain
  828. )
  829. /*++
  830. Routine Description:
  831. Get a list of DCs in this domain from SAM on the current DC.
  832. Arguments:
  833. TestedDomain - Domain to get the DC list for
  834. Return Value:
  835. TRUE: Test suceeded.
  836. FALSE: Test failed
  837. --*/
  838. {
  839. NET_API_STATUS NetStatus;
  840. NTSTATUS Status;
  841. BOOL RetVal = TRUE;
  842. SAM_HANDLE LocalSamHandle = NULL;
  843. SAM_HANDLE DomainHandle = NULL;
  844. LSA_HANDLE LSAPolicyHandle = NULL;
  845. OBJECT_ATTRIBUTES LSAObjectAttributes;
  846. PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL;
  847. PDOMAIN_DISPLAY_MACHINE MachineInformation = NULL;
  848. NTSTATUS SamStatus;
  849. ULONG SamIndex;
  850. LPTSTR pszDcType;
  851. //
  852. // Get a DC to seed the algorithm with
  853. //
  854. if ( TestedDomain->DcInfo == NULL ) {
  855. if ( TestedDomain->fTriedToFindDcInfo ) {
  856. if(pParams->fDebugVerbose)
  857. {
  858. //IDS_DCLIST_13426 " Cannot find DC to get DC list from (Test skipped).\n"
  859. PrintMessage(pParams, IDS_DCLIST_13426 );
  860. }
  861. goto Cleanup;
  862. }
  863. pszDcType = LoadAndAllocString(IDS_DCTYPE_DC);
  864. NetStatus = DoDsGetDcName( pParams,
  865. pResults,
  866. &pResults->DcList.lmsgOutput,
  867. TestedDomain,
  868. DS_DIRECTORY_SERVICE_PREFERRED,
  869. pszDcType,
  870. FALSE,
  871. &TestedDomain->DcInfo );
  872. Free(pszDcType);
  873. TestedDomain->fTriedToFindDcInfo = TRUE;
  874. if ( NetStatus != NO_ERROR ) {
  875. if(pParams->fDebugVerbose)
  876. {
  877. //IDS_DCLIST_13427 " Cannot find DC to get DC list from (Test skipped). [%s]\n"
  878. PrintMessage(pParams, IDS_DCLIST_13427, NetStatusToString(NetStatus) );
  879. PrintMessage(pParams, IDS_GLOBAL_STATUS, NetStatusToString( NetStatus ));
  880. }
  881. goto Cleanup;
  882. }
  883. }
  884. if ( pParams->fReallyVerbose ) {
  885. //IDS_DCLIST_13428 " Get list of DC accounts from SAM in domain '%ws'.\n"
  886. PrintMessage(pParams, IDS_DCLIST_13428, TestedDomain->PrintableDomainName);
  887. }
  888. //
  889. // Connect to the SAM server
  890. //
  891. Status = NettestSamConnect( pParams,
  892. TestedDomain->DcInfo->DomainControllerName,
  893. &LocalSamHandle );
  894. if ( !NT_SUCCESS(Status)) {
  895. if ( Status == STATUS_ACCESS_DENIED ) {
  896. RetVal = FALSE;
  897. }
  898. goto Cleanup;
  899. }
  900. //
  901. // If we don't have a domain sid,
  902. // find out what it is.
  903. //
  904. if ( TestedDomain->DomainSid == NULL ) {
  905. UNICODE_STRING ServerNameString;
  906. //
  907. // Open LSA to read account domain info.
  908. //
  909. InitializeObjectAttributes( &LSAObjectAttributes,
  910. NULL, // Name
  911. 0, // Attributes
  912. NULL, // Root
  913. NULL ); // Security Descriptor
  914. RtlInitUnicodeString( &ServerNameString, TestedDomain->DcInfo->DomainControllerName );
  915. Status = LsaOpenPolicy( &ServerNameString,
  916. &LSAObjectAttributes,
  917. POLICY_VIEW_LOCAL_INFORMATION,
  918. &LSAPolicyHandle );
  919. if( !NT_SUCCESS(Status) ) {
  920. if(pParams->fDebugVerbose)
  921. {
  922. //IDS_DCLIST_13429 " [FATAL] Cannot LsaOpenPolicy to LSA on '%ws'."
  923. PrintMessage(pParams, IDS_DCLIST_13429, TestedDomain->DcInfo->DomainControllerName );
  924. }
  925. PrintGuruMessage2(" [FATAL] Cannot LsaOpenPolicy to LSA on '%ws'." , TestedDomain->DcInfo->DomainControllerName );
  926. PrintGuru( NetpNtStatusToApiStatus( Status ), LSA_GURU );
  927. RetVal = FALSE;
  928. goto Cleanup;
  929. }
  930. //
  931. // Now read account domain info from LSA.
  932. //
  933. Status = LsaQueryInformationPolicy(
  934. LSAPolicyHandle,
  935. PolicyAccountDomainInformation,
  936. (PVOID *) &AccountDomainInfo );
  937. if( !NT_SUCCESS(Status) ) {
  938. AccountDomainInfo = NULL;
  939. if(pParams->fDebugVerbose)
  940. {
  941. //IDS_DCLIST_13430 " [FATAL] Cannot LsaQueryInformationPolicy (AccountDomainInfor) to LSA on '%ws'."
  942. PrintMessage(pParams, IDS_DCLIST_13430, TestedDomain->DcInfo->DomainControllerName );
  943. }
  944. PrintGuruMessage2(" [FATAL] Cannot LsaQueryInformationPolicy (AccountDomainInfor) to LSA on '%ws'.", TestedDomain->DcInfo->DomainControllerName );
  945. PrintGuru( NetpNtStatusToApiStatus( Status ), LSA_GURU );
  946. RetVal = FALSE;
  947. goto Cleanup;
  948. }
  949. //
  950. // Save the domain sid for other tests
  951. //
  952. pResults->Global.pMemberDomain->DomainSid =
  953. Malloc( RtlLengthSid( AccountDomainInfo->DomainSid ) );
  954. if ( pResults->Global.pMemberDomain->DomainSid == NULL ) {
  955. //IDS_DCLIST_13431 "Out of memory\n"
  956. PrintMessage(pParams, IDS_DCLIST_13431);
  957. RetVal = FALSE;
  958. goto Cleanup;
  959. }
  960. RtlCopyMemory( pResults->Global.pMemberDomain->DomainSid,
  961. AccountDomainInfo->DomainSid,
  962. RtlLengthSid( AccountDomainInfo->DomainSid ) );
  963. if ( pParams->fReallyVerbose ) {
  964. //IDS_DCLIST_13432 " Domain Sid: "
  965. PrintMessage(pParams, IDS_DCLIST_13432);
  966. PrintSid( pParams, pResults->Global.pMemberDomain->DomainSid );
  967. }
  968. }
  969. //
  970. // Open the domain.
  971. //
  972. Status = SamOpenDomain( LocalSamHandle,
  973. DOMAIN_LIST_ACCOUNTS |
  974. DOMAIN_LOOKUP,
  975. pResults->Global.pMemberDomain->DomainSid,
  976. &DomainHandle );
  977. if ( !NT_SUCCESS( Status ) ) {
  978. if(pParams->fDebugVerbose)
  979. {
  980. //IDS_DCLIST_13433 " [FATAL] Cannot SamOpenDomain on '%ws'."
  981. PrintMessage(pParams, IDS_DCLIST_13433, TestedDomain->DcInfo->DomainControllerName );
  982. }
  983. PrintGuruMessage2(" [FATAL] Cannot SamOpenDomain on '%ws'.", TestedDomain->DcInfo->DomainControllerName );
  984. PrintGuru( NetpNtStatusToApiStatus( Status ), SAM_GURU );
  985. RetVal = FALSE;
  986. goto Cleanup;
  987. }
  988. //
  989. // Loop building a list of DC names from SAM.
  990. //
  991. // On each iteration of the loop,
  992. // get the next several machine accounts from SAM.
  993. // determine which of those names are DC names.
  994. // Merge the DC names into the list we're currently building of all DCs.
  995. //
  996. SamIndex = 0;
  997. do {
  998. //
  999. // Arguments to SamQueryDisplayInformation
  1000. //
  1001. ULONG TotalBytesAvailable;
  1002. ULONG BytesReturned;
  1003. ULONG EntriesRead;
  1004. DWORD i;
  1005. //
  1006. // Get the list of machine accounts from SAM
  1007. //
  1008. SamStatus = SamQueryDisplayInformation (
  1009. DomainHandle,
  1010. DomainDisplayMachine,
  1011. SamIndex,
  1012. 4096, // Machines per pass
  1013. 0xFFFFFFFF, // PrefMaxLen
  1014. &TotalBytesAvailable,
  1015. &BytesReturned,
  1016. &EntriesRead,
  1017. &MachineInformation );
  1018. if ( !NT_SUCCESS(SamStatus) ) {
  1019. Status = SamStatus;
  1020. if(pParams->fDebugVerbose)
  1021. {
  1022. //IDS_DCLIST_13434 " [FATAL] Cannot SamQueryDisplayInformation on '%ws'."
  1023. PrintMessage(pParams, IDS_DCLIST_13434, TestedDomain->DcInfo->DomainControllerName );
  1024. }
  1025. PrintGuruMessage2(" [FATAL] Cannot SamQueryDisplayInformation on '%ws'.", TestedDomain->DcInfo->DomainControllerName );
  1026. PrintGuru( NetpNtStatusToApiStatus( Status ), SAM_GURU );
  1027. RetVal = FALSE;
  1028. goto Cleanup;
  1029. }
  1030. //
  1031. // Set up for the next call to Sam.
  1032. //
  1033. if ( SamStatus == STATUS_MORE_ENTRIES ) {
  1034. SamIndex = MachineInformation[EntriesRead-1].Index;
  1035. }
  1036. //
  1037. // Loop though the list of machine accounts finding the Server accounts.
  1038. //
  1039. for ( i=0; i<EntriesRead; i++ ) {
  1040. //
  1041. // Ensure the machine account is a server account.
  1042. //
  1043. if ( MachineInformation[i].AccountControl &
  1044. USER_SERVER_TRUST_ACCOUNT ) {
  1045. WCHAR LocalComputerName[CNLEN+1];
  1046. ULONG LocalComputerNameLength;
  1047. //
  1048. // Insert the server session.
  1049. //
  1050. if(pParams->fDebugVerbose)
  1051. {
  1052. //IDS_DCLIST_13435 "%wZ %ld\n"
  1053. PrintMessage(pParams, IDS_DCLIST_13435, &MachineInformation[i].Machine, MachineInformation[i].Rid );
  1054. }
  1055. LocalComputerNameLength =
  1056. min( MachineInformation[i].Machine.Length/sizeof(WCHAR) - 1,
  1057. CNLEN );
  1058. RtlCopyMemory( LocalComputerName,
  1059. MachineInformation[i].Machine.Buffer,
  1060. LocalComputerNameLength * sizeof(WCHAR) );
  1061. LocalComputerName[LocalComputerNameLength] = '\0';
  1062. AddTestedDc( pParams,
  1063. pResults,
  1064. TestedDomain, LocalComputerName, 0 );
  1065. }
  1066. }
  1067. //
  1068. // Free the buffer returned from SAM.
  1069. //
  1070. if ( MachineInformation != NULL ) {
  1071. SamFreeMemory( MachineInformation );
  1072. MachineInformation = NULL;
  1073. }
  1074. } while ( SamStatus == STATUS_MORE_ENTRIES );
  1075. //
  1076. // Cleanup locally used resources
  1077. //
  1078. Cleanup:
  1079. if ( DomainHandle != NULL ) {
  1080. (VOID) SamCloseHandle( DomainHandle );
  1081. }
  1082. if ( AccountDomainInfo != NULL ) {
  1083. LsaFreeMemory( AccountDomainInfo );
  1084. AccountDomainInfo = NULL;
  1085. }
  1086. if ( LocalSamHandle != NULL ) {
  1087. (VOID) SamCloseHandle( LocalSamHandle );
  1088. }
  1089. if( LSAPolicyHandle != NULL ) {
  1090. LsaClose( LSAPolicyHandle );
  1091. }
  1092. return RetVal;
  1093. }
  1094. //(nsun) _delete
  1095. /*
  1096. BOOL
  1097. GetDcListFromDc(
  1098. IN NETDIAG_PARAMS *pParams,
  1099. IN OUT NETDIAG_RESULT *pResults,
  1100. IN PTESTED_DOMAIN pTestedDomain
  1101. )
  1102. *++
  1103. Routine Description:
  1104. Get a list of DCs in this domain from the current DC.
  1105. Arguments:
  1106. pTestedDomain - Domain to get the DC list for
  1107. Return Value:
  1108. TRUE: Test suceeded.
  1109. FALSE: Test failed
  1110. --*
  1111. {
  1112. NET_API_STATUS NetStatus;
  1113. NTSTATUS Status;
  1114. BOOL RetVal = TRUE;
  1115. SAM_HANDLE LocalSamHandle = NULL;
  1116. SAM_HANDLE DomainHandle = NULL;
  1117. LSA_HANDLE LSAPolicyHandle = NULL;
  1118. OBJECT_ATTRIBUTES LSAObjectAttributes;
  1119. PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL;
  1120. PDOMAIN_DISPLAY_MACHINE MachineInformation = NULL;
  1121. NTSTATUS SamStatus;
  1122. ULONG SamIndex;
  1123. LPWSTR LocalShareName = NULL;
  1124. PTESTED_DC pTestedDC;
  1125. //
  1126. // Get a DC to seed the algorithm with
  1127. //
  1128. if ( pTestedDomain->DcInfo == NULL )
  1129. {
  1130. NetStatus = GetADc( pParams,
  1131. pResults,
  1132. DsGetDcNameW,
  1133. pTestedDomain,
  1134. DS_DIRECTORY_SERVICE_PREFERRED,
  1135. &pTestedDomain->DcInfo );
  1136. if ( NetStatus != NO_ERROR )
  1137. {
  1138. //IDS_DCLIST_13436 " [FATAL] Cannot find DC to get DC list from."
  1139. // PrintMessage(pParams, IDS_DCLIST_13436 );
  1140. RetVal = FALSE;
  1141. goto Cleanup;
  1142. }
  1143. }
  1144. // if ( pParams->fVerbose )
  1145. // {
  1146. //IDS_DCLIST_13437 " Get list of DC account in domain '%ws'.\n"
  1147. // PrintMessage(pParams, IDS_DCLIST_13437, pTestedDomain->DomainName);
  1148. // }
  1149. //
  1150. // Connect to the SAM server
  1151. //
  1152. Status = NettestSamConnect(
  1153. pParams,
  1154. pTestedDomain->DcInfo->DomainControllerName,
  1155. &LocalSamHandle,
  1156. &LocalShareName );
  1157. if ( !NT_SUCCESS(Status)) {
  1158. RetVal = FALSE;
  1159. goto Cleanup;
  1160. }
  1161. //
  1162. // If we don't have a domain sid,
  1163. // find out what it is.
  1164. //
  1165. if ( pTestedDomain->DomainSid == NULL ) {
  1166. UNICODE_STRING ServerNameString;
  1167. //
  1168. // Open LSA to read account domain info.
  1169. //
  1170. InitializeObjectAttributes( &LSAObjectAttributes,
  1171. NULL, // Name
  1172. 0, // Attributes
  1173. NULL, // Root
  1174. NULL ); // Security Descriptor
  1175. RtlInitUnicodeString( &ServerNameString, pTestedDomain->DcInfo->DomainControllerName );
  1176. Status = LsaOpenPolicy( &ServerNameString,
  1177. &LSAObjectAttributes,
  1178. POLICY_VIEW_LOCAL_INFORMATION,
  1179. &LSAPolicyHandle );
  1180. if( !NT_SUCCESS(Status) )
  1181. {
  1182. // " [FATAL] Cannot LsaOpenPolicy to LSA on '%ws'.",
  1183. if (pParams->fDebugVerbose)
  1184. PrintMessage(pParams, IDS_DCLIST_LSAOPENPOLICY,
  1185. pTestedDomain->DcInfo->DomainControllerName );
  1186. RetVal = FALSE;
  1187. goto Cleanup;
  1188. }
  1189. //
  1190. // Now read account domain info from LSA.
  1191. //
  1192. Status = LsaQueryInformationPolicy(
  1193. LSAPolicyHandle,
  1194. PolicyAccountDomainInformation,
  1195. (PVOID *) &AccountDomainInfo );
  1196. if( !NT_SUCCESS(Status) )
  1197. {
  1198. AccountDomainInfo = NULL;
  1199. // " [FATAL] Cannot LsaQueryInformationPolicy (AccountDomainInfor) to LSA on '%ws'."
  1200. if (pParams->fDebugVerbose)
  1201. PrintMessage(pParams, IDS_DCLIST_LSAQUERYINFO,
  1202. pTestedDomain->DcInfo->DomainControllerName);
  1203. RetVal = FALSE;
  1204. goto Cleanup;
  1205. }
  1206. //
  1207. // Save the domain sid for other tests
  1208. //
  1209. pResults->Global.pMemberDomain->DomainSid =
  1210. Malloc( RtlLengthSid( AccountDomainInfo->DomainSid ) );
  1211. if ( pResults->Global.pMemberDomain->DomainSid == NULL )
  1212. {
  1213. RetVal = FALSE;
  1214. goto Cleanup;
  1215. }
  1216. // We have the domain SID
  1217. pResults->Global.pMemberDomain->fDomainSid = TRUE;
  1218. RtlCopyMemory( pResults->Global.pMemberDomain->DomainSid,
  1219. AccountDomainInfo->DomainSid,
  1220. RtlLengthSid( AccountDomainInfo->DomainSid ) );
  1221. // if ( pParams->fVerbose ) {
  1222. //IDS_DCLIST_13438 " Domain Sid: "
  1223. // PrintMessage(pParams, IDS_DCLIST_13438);
  1224. // NlpDumpSid( pResults->Global.pMemberDomain->DomainSid );
  1225. // }
  1226. }
  1227. //
  1228. // Open the domain.
  1229. //
  1230. Status = SamOpenDomain( LocalSamHandle,
  1231. DOMAIN_LIST_ACCOUNTS |
  1232. DOMAIN_LOOKUP,
  1233. pResults->Global.pMemberDomain->DomainSid,
  1234. &DomainHandle );
  1235. if ( !NT_SUCCESS( Status ) )
  1236. {
  1237. // " [FATAL] Cannot SamOpenDomain on '%ws'."
  1238. if (pParams->fDebugVerbose)
  1239. PrintMessage(pParams, IDS_DCLIST_SAMOPENDOMAIN,
  1240. pTestedDomain->DcInfo->DomainControllerName);
  1241. RetVal = FALSE;
  1242. goto Cleanup;
  1243. }
  1244. //
  1245. // Loop building a list of DC names from SAM.
  1246. //
  1247. // On each iteration of the loop,
  1248. // get the next several machine accounts from SAM.
  1249. // determine which of those names are DC names.
  1250. // Merge the DC names into the list we're currently building of all DCs.
  1251. //
  1252. SamIndex = 0;
  1253. do {
  1254. //
  1255. // Arguments to SamQueryDisplayInformation
  1256. //
  1257. ULONG TotalBytesAvailable;
  1258. ULONG BytesReturned;
  1259. ULONG EntriesRead;
  1260. DWORD i;
  1261. //
  1262. // Get the list of machine accounts from SAM
  1263. //
  1264. SamStatus = SamQueryDisplayInformation (
  1265. DomainHandle,
  1266. DomainDisplayMachine,
  1267. SamIndex,
  1268. 4096, // Machines per pass
  1269. 0xFFFFFFFF, // PrefMaxLen
  1270. &TotalBytesAvailable,
  1271. &BytesReturned,
  1272. &EntriesRead,
  1273. &MachineInformation );
  1274. if ( !NT_SUCCESS(SamStatus) )
  1275. {
  1276. Status = SamStatus;
  1277. if (pParams->fDebugVerbose)
  1278. {
  1279. // " [FATAL] Cannot SamQueryDisplayInformation on '%ws'."
  1280. PrintMessage(pParams, IDS_DCLIST_SAMQUERYDISPLAYINFO,
  1281. pTestedDomain->DcInfo->DomainControllerName);
  1282. }
  1283. RetVal = FALSE;
  1284. goto Cleanup;
  1285. }
  1286. //
  1287. // Set up for the next call to Sam.
  1288. //
  1289. if ( SamStatus == STATUS_MORE_ENTRIES ) {
  1290. SamIndex = MachineInformation[EntriesRead-1].Index;
  1291. }
  1292. //
  1293. // Loop though the list of machine accounts finding the Server accounts.
  1294. //
  1295. for ( i=0; i<EntriesRead; i++ ) {
  1296. //
  1297. // Ensure the machine account is a server account.
  1298. //
  1299. if ( MachineInformation[i].AccountControl &
  1300. USER_SERVER_TRUST_ACCOUNT ) {
  1301. WCHAR LocalComputerName[CNLEN+1];
  1302. ULONG LocalComputerNameLength;
  1303. //
  1304. // Insert the server session.
  1305. //
  1306. //IDS_DCLIST_13439 "%wZ %ld\n"
  1307. // PrintMessage(pParams, IDS_DCLIST_13439, &MachineInformation[i].Machine, MachineInformation[i].Rid );
  1308. LocalComputerNameLength =
  1309. min( MachineInformation[1].Machine.Length/sizeof(WCHAR) - 1,
  1310. CNLEN );
  1311. RtlCopyMemory( LocalComputerName,
  1312. MachineInformation[1].Machine.Buffer,
  1313. LocalComputerNameLength * sizeof(WCHAR) );
  1314. LocalComputerName[LocalComputerNameLength] = '\0';
  1315. pTestedDC = AddTestedDc( pParams,
  1316. pResults,
  1317. pTestedDomain,
  1318. LocalComputerName,
  1319. 0 );
  1320. pTestedDC->Rid = MachineInformation[i].Rid;
  1321. }
  1322. }
  1323. //
  1324. // Free the buffer returned from SAM.
  1325. //
  1326. if ( MachineInformation != NULL ) {
  1327. SamFreeMemory( MachineInformation );
  1328. MachineInformation = NULL;
  1329. }
  1330. } while ( SamStatus == STATUS_MORE_ENTRIES );
  1331. //
  1332. // Cleanup locally used resources
  1333. //
  1334. Cleanup:
  1335. if ( DomainHandle != NULL ) {
  1336. (VOID) SamCloseHandle( DomainHandle );
  1337. }
  1338. if ( AccountDomainInfo != NULL ) {
  1339. LsaFreeMemory( AccountDomainInfo );
  1340. AccountDomainInfo = NULL;
  1341. }
  1342. if ( LocalSamHandle != NULL ) {
  1343. (VOID) SamCloseHandle( LocalSamHandle );
  1344. }
  1345. if( LSAPolicyHandle != NULL ) {
  1346. LsaClose( LSAPolicyHandle );
  1347. }
  1348. if ( LocalShareName != NULL )
  1349. {
  1350. NET_API_STATUS TempStatus;
  1351. TempStatus = NetUseDel( NULL, LocalShareName, FALSE );
  1352. if ( (TempStatus != NERR_Success) && (pParams->fDebugVerbose) )
  1353. {
  1354. // " [WARNING] Cannot NetUseDel '%ws' NULL session."
  1355. PrintMessage(pParams, IDS_DCLIST_NETUSEDEL, LocalShareName );
  1356. }
  1357. NetpMemoryFree( LocalShareName );
  1358. }
  1359. return RetVal;
  1360. }
  1361. */
  1362. /*!--------------------------------------------------------------------------
  1363. DcListGlobalPrint
  1364. -
  1365. Author: KennT
  1366. ---------------------------------------------------------------------------*/
  1367. void DcListGlobalPrint( NETDIAG_PARAMS* pParams,
  1368. NETDIAG_RESULT* pResults)
  1369. {
  1370. LIST_ENTRY * pListEntry;
  1371. LIST_ENTRY * pListEntryDC;
  1372. TESTED_DOMAIN * pDomain;
  1373. TESTED_DC * pTestedDC;
  1374. int i;
  1375. if (!pResults->IpConfig.fEnabled)
  1376. {
  1377. return;
  1378. }
  1379. if (pParams->fVerbose || !FHrOK(pResults->DcList.hr))
  1380. {
  1381. PrintNewLine(pParams, 2);
  1382. PrintTestTitleResult(pParams, IDS_DCLIST_LONG, IDS_DCLIST_SHORT,
  1383. pResults->DcList.fPerformed,
  1384. pResults->DcList.hr, 0);
  1385. PrintNdMessage(pParams, &pResults->DcList.msgErr);
  1386. //The message list contains the error info
  1387. PrintMessageList(pParams, &pResults->DcList.lmsgOutput);
  1388. if (pParams->fReallyVerbose)
  1389. {
  1390. // Iterate through the list of tested domain
  1391. // Iterate through each domain
  1392. for (pListEntry = pResults->Global.listTestedDomains.Flink;
  1393. pListEntry != &pResults->Global.listTestedDomains;
  1394. pListEntry = pListEntry->Flink)
  1395. {
  1396. pDomain = CONTAINING_RECORD(pListEntry, TESTED_DOMAIN, Next);
  1397. // " List of DCs in Domain '%ws':\n"
  1398. PrintMessage(pParams, IDS_DCLIST_DOMAIN_HEADER,
  1399. pDomain->PrintableDomainName);
  1400. if (pDomain->fDomainSid)
  1401. {
  1402. // print out the sid for the domain
  1403. PrintMessage(pParams, IDS_DCLIST_DOMAIN_SID);
  1404. PrintSid( pParams, pResults->Global.pMemberDomain->DomainSid );
  1405. }
  1406. for (pListEntryDC = pDomain->TestedDcs.Flink;
  1407. pListEntryDC != &pDomain->TestedDcs;
  1408. pListEntryDC = pListEntryDC->Flink)
  1409. {
  1410. pTestedDC = CONTAINING_RECORD(pListEntryDC,
  1411. TESTED_DC, Next);
  1412. PrintMessage(pParams, IDS_DCLIST_DC_INFO,
  1413. pTestedDC->ComputerName);
  1414. if (pTestedDC->Rid)
  1415. {
  1416. PrintMessage(pParams, IDS_DCLIST_RID,
  1417. pTestedDC->Rid);
  1418. }
  1419. if (pTestedDC->Flags & DC_IS_DOWN)
  1420. {
  1421. PrintMessage(pParams, IDS_DCLIST_DC_IS_DOWN);
  1422. if (pTestedDC->Flags & DC_FAILED_PING)
  1423. {
  1424. PrintNewLine(pParams, 1);
  1425. PrintMessage(pParams, IDS_DCLIST_DC_FAILED_PING,
  1426. pTestedDC->ComputerName);
  1427. }
  1428. }
  1429. PrintNewLine(pParams, 1);
  1430. }
  1431. }
  1432. }
  1433. }
  1434. }
  1435. /*!--------------------------------------------------------------------------
  1436. DcListPerInterfacePrint
  1437. -
  1438. Author: KennT
  1439. ---------------------------------------------------------------------------*/
  1440. void DcListPerInterfacePrint( NETDIAG_PARAMS* pParams,
  1441. NETDIAG_RESULT* pResults,
  1442. INTERFACE_RESULT *pInterfaceResults)
  1443. {
  1444. // no per-interface results
  1445. }
  1446. /*!--------------------------------------------------------------------------
  1447. DcListCleanup
  1448. -
  1449. Author: KennT
  1450. ---------------------------------------------------------------------------*/
  1451. void DcListCleanup( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults)
  1452. {
  1453. int i;
  1454. ClearMessage(&pResults->DcList.msgErr);
  1455. MessageListCleanUp(&pResults->DcList.lmsgOutput);
  1456. }