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.

554 lines
17 KiB

  1. //++
  2. //
  3. // Copyright (C) Microsoft Corporation, 1987 - 1999
  4. //
  5. // Module Name:
  6. //
  7. // trust.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 DomainSidRight( IN PTESTED_DOMAIN TestedDomain,
  27. NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults
  28. );
  29. HRESULT TrustTest( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults)
  30. {
  31. HRESULT hr = S_OK;
  32. PTESTED_DOMAIN Context = pParams->pDomain;
  33. NET_API_STATUS NetStatus;
  34. PNETLOGON_INFO_2 NetlogonInfo2 = NULL;
  35. NET_API_STATUS TrustedNetStatus = 0;
  36. LPWSTR TrustedDomainList = NULL;
  37. PTESTED_DOMAIN TestedDomain = pResults->Global.pMemberDomain;
  38. PLIST_ENTRY ListEntry;
  39. LPBYTE InputDataPtr;
  40. int i;
  41. // validDC is the count of valid Domain Controllers with which secure channel can be set.
  42. int validDC = 0;
  43. InitializeListHead(&pResults->Trust.lmsgOutput);
  44. PrintStatusMessage(pParams, 4, IDS_TRUST_STATUS_MSG);
  45. //
  46. // Only Members and BDCs have trust relationships to their primary domain
  47. //
  48. if (!
  49. (pResults->Global.pPrimaryDomainInfo->MachineRole == DsRole_RoleMemberWorkstation ||
  50. pResults->Global.pPrimaryDomainInfo->MachineRole == DsRole_RoleMemberServer ||
  51. pResults->Global.pPrimaryDomainInfo->MachineRole == DsRole_RoleBackupDomainController )
  52. )
  53. {
  54. PrintStatusMessage(pParams, 0, IDS_GLOBAL_SKIP_NL);
  55. return hr; // not to test standalone
  56. }
  57. pResults->Trust.fPerformed = TRUE;
  58. //
  59. // Check to see that the domain Sid of the primary domain is right.
  60. //
  61. if ( !DomainSidRight( pResults->Global.pMemberDomain, pParams, pResults ) ) {
  62. hr = S_FALSE;
  63. goto L_ERR;
  64. }
  65. //
  66. // Use the secure channel
  67. //
  68. // If some other caller did this in the recent past,
  69. // this doesn't even use the secure channel.
  70. //
  71. // On a BDC, this doesn't use the secure channel.
  72. //
  73. TrustedNetStatus = NetEnumerateTrustedDomains( NULL, &TrustedDomainList );
  74. if ( TrustedNetStatus != NO_ERROR ) {
  75. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
  76. IDS_TRUST_FAILED_LISTDOMAINS,
  77. pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
  78. NetStatusToString(TrustedNetStatus));
  79. }
  80. // Don't complain yet since the real secure channel status is more
  81. // important to the user.
  82. //
  83. // Check the current status of the secure channel.
  84. // (This may still be cached and out of date.)
  85. //
  86. InputDataPtr = (LPBYTE)(pResults->Global.pPrimaryDomainInfo->DomainNameDns ?
  87. pResults->Global.pPrimaryDomainInfo->DomainNameDns :
  88. pResults->Global.pPrimaryDomainInfo->DomainNameFlat);
  89. NetStatus = I_NetLogonControl2(
  90. NULL,
  91. NETLOGON_CONTROL_TC_QUERY,
  92. 2, // Query level
  93. (LPBYTE)&(InputDataPtr),
  94. (LPBYTE *)&NetlogonInfo2 );
  95. // put message to message list
  96. if ( NetStatus != NO_ERROR )
  97. {
  98. //IDS_TRUST_FAILED_SECURECHANNEL " Cannot get secure channel status for domain '%ws' from Netlogon. [%s]"
  99. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
  100. IDS_TRUST_FAILED_SECURECHANNEL,
  101. pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
  102. NetStatusToString(NetStatus));
  103. hr = S_FALSE;
  104. goto L_ERR;
  105. }
  106. if ( NetlogonInfo2->netlog2_tc_connection_status != NO_ERROR )
  107. {
  108. //IDS_TRUST_CHANNEL_BROKEN " [FATAL] Secure channel to domain '%ws' is broken. [%s]\n"
  109. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
  110. IDS_TRUST_CHANNEL_BROKEN,
  111. pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
  112. NetStatusToString(NetlogonInfo2->netlog2_tc_connection_status));
  113. hr = S_FALSE;
  114. goto L_ERR;
  115. }
  116. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Verbose, 0,
  117. IDS_TRUST_SECURECHANNEL_TO,
  118. pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
  119. NetlogonInfo2->netlog2_trusted_dc_name);
  120. // free the data buffer returned earlies
  121. if ( NetlogonInfo2 != NULL ) {
  122. NetApiBufferFree( NetlogonInfo2 );
  123. NetlogonInfo2 = NULL;
  124. }
  125. // test further
  126. switch(pResults->Global.pPrimaryDomainInfo->MachineRole){
  127. //
  128. // On a backup domain controller,
  129. // only setup a secure channel to the PDC.
  130. //
  131. case DsRole_RoleBackupDomainController:
  132. //
  133. // Check the current status of the secure channel.
  134. // (This may be still cached and out of date.)
  135. //
  136. NetlogonInfo2 = NULL;
  137. InputDataPtr = (LPBYTE)(pResults->Global.pPrimaryDomainInfo->DomainNameDns ?
  138. pResults->Global.pPrimaryDomainInfo->DomainNameDns :
  139. pResults->Global.pPrimaryDomainInfo->DomainNameFlat);
  140. // connect to PDC
  141. NetStatus = I_NetLogonControl2(
  142. NULL,
  143. NETLOGON_CONTROL_REDISCOVER,
  144. 2, // Query level
  145. (LPBYTE)&InputDataPtr,
  146. (LPBYTE *)&NetlogonInfo2 );
  147. if (NetStatus == ERROR_ACCESS_DENIED)
  148. {
  149. //IDS_TRUST_NOT_ADMIN " Cannot test secure channel to PDC since you are not an administrator.\n"
  150. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
  151. IDS_TRUST_NOT_ADMIN);
  152. goto L_ERR;
  153. }
  154. if(NetStatus != NO_ERROR)
  155. {
  156. //IDS_TRUST_FAILED_CHANNEL_PDC " [FATAL] Cannot set secure channel for domain '%ws' to PDC. [%s]\n"
  157. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
  158. IDS_TRUST_FAILED_CHANNEL_PDC,
  159. pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
  160. NetStatusToString(NetStatus));
  161. hr = S_FALSE;
  162. goto L_ERR;
  163. }
  164. if ( NetlogonInfo2->netlog2_tc_connection_status != NO_ERROR )
  165. {
  166. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
  167. IDS_TRUST_FAILED_CHANNEL_PDC,
  168. pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
  169. NetStatusToString(NetStatus));
  170. hr = S_FALSE;
  171. goto L_ERR;
  172. }
  173. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_ReallyVerbose, 0,
  174. IDS_TRUST_SECURECHANNEL_TOPDC,
  175. pResults->Global.pPrimaryDomainInfo->DomainNameFlat,
  176. NetlogonInfo2->netlog2_trusted_dc_name);
  177. if ( NetlogonInfo2 != NULL )
  178. {
  179. NetApiBufferFree( NetlogonInfo2 );
  180. NetlogonInfo2 = NULL;
  181. }
  182. break;
  183. // On a workstation or member server,
  184. // try the secure channel to ever DC in the domain.
  185. //
  186. case DsRole_RoleMemberServer:
  187. case DsRole_RoleMemberWorkstation:
  188. if ( TestedDomain->NetbiosDomainName == NULL ) {
  189. //IDS_TRUST_NO_NBT_DOMAIN " [FATAL] Cannot test secure channel since no netbios domain name '%ws' to DC '%ws'."
  190. AddMessageToList( &pResults->Trust.lmsgOutput, Nd_Quiet, IDS_TRUST_NO_NBT_DOMAIN, TestedDomain->PrintableDomainName );
  191. PrintGuruMessage2(" [FATAL] Cannot test secure channel since no netbios domain name '%ws' to DC '%ws'.", TestedDomain->PrintableDomainName );
  192. PrintGuru( 0, NETLOGON_GURU );
  193. hr = S_FALSE;
  194. goto L_ERR;
  195. }
  196. //
  197. // Ensure secure channel can be set with atleast one DC.
  198. //
  199. for ( ListEntry = TestedDomain->TestedDcs.Flink ;
  200. ListEntry != &TestedDomain->TestedDcs ;
  201. ListEntry = ListEntry->Flink )
  202. {
  203. WCHAR RediscoverName[MAX_PATH+1+MAX_PATH+1];
  204. PTESTED_DC TestedDc;
  205. //
  206. // Loop through the list of DCs in this domain
  207. //
  208. TestedDc = CONTAINING_RECORD( ListEntry, TESTED_DC, Next );
  209. if ( TestedDc->Flags & DC_IS_DOWN ) {
  210. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_ReallyVerbose, 0,
  211. IDS_TRUST_NOTESTASITSDOWN,
  212. TestedDc->ComputerName );
  213. continue;
  214. }
  215. //
  216. // Build the name to rediscover
  217. //
  218. wcscpy( RediscoverName, GetSafeStringW(TestedDomain->DnsDomainName ?
  219. TestedDomain->DnsDomainName :
  220. TestedDomain->NetbiosDomainName));
  221. wcscat( RediscoverName, L"\\" );
  222. wcscat( RediscoverName, GetSafeStringW(TestedDc->ComputerName) );
  223. //
  224. // Check the current status of the secure channel.
  225. // (This may be still cached and out of date.)
  226. //
  227. InputDataPtr = (LPBYTE)RediscoverName;
  228. NetStatus = I_NetLogonControl2(
  229. NULL,
  230. NETLOGON_CONTROL_REDISCOVER,
  231. 2, // Query level
  232. (LPBYTE)&InputDataPtr,
  233. (LPBYTE *)&NetlogonInfo2 );
  234. if ( NetStatus != NO_ERROR )
  235. {
  236. if ( ERROR_ACCESS_DENIED == NetStatus )
  237. {
  238. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
  239. IDS_TRUST_TODCS_NOT_ADMIN);
  240. }
  241. else
  242. {
  243. //IDS_TRUST_FAILED_TODCS " Cannot test secure channel for domain '%ws' to DC '%ws'. [%s]\n"
  244. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
  245. IDS_TRUST_FAILED_TODCS,
  246. TestedDomain->PrintableDomainName,
  247. TestedDc->NetbiosDcName,
  248. NetStatusToString(NetStatus));
  249. }
  250. continue;
  251. }
  252. if ( NetlogonInfo2->netlog2_tc_connection_status != NO_ERROR )
  253. {
  254. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
  255. IDS_TRUST_FAILED_CHANNEL_DCS,
  256. TestedDomain->PrintableDomainName,
  257. TestedDc->NetbiosDcName );
  258. continue;
  259. }
  260. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_ReallyVerbose, 0,
  261. IDS_TRUST_CHANNEL_DC,
  262. TestedDomain->PrintableDomainName,
  263. NetlogonInfo2->netlog2_trusted_dc_name );
  264. validDC++;
  265. }
  266. if (validDC == 0)
  267. hr = S_FALSE;
  268. break;
  269. }
  270. L_ERR:
  271. if ( NetlogonInfo2 != NULL ) {
  272. NetApiBufferFree( NetlogonInfo2 );
  273. NetlogonInfo2 = NULL;
  274. }
  275. if ( TrustedDomainList != NULL ) {
  276. NetApiBufferFree( TrustedDomainList );
  277. TrustedDomainList = NULL;
  278. }
  279. PrintStatusMessage(pParams, 0, FHrOK(hr) ? IDS_GLOBAL_PASS_NL : IDS_GLOBAL_FAIL_NL);
  280. pResults->Trust.hr = hr;
  281. return hr;
  282. }
  283. void TrustGlobalPrint(IN NETDIAG_PARAMS *pParams, IN OUT NETDIAG_RESULT *pResults)
  284. {
  285. // print out the test result
  286. if (pParams->fVerbose || !FHrOK(pResults->Trust.hr))
  287. {
  288. PrintNewLine(pParams, 2);
  289. PrintTestTitleResult(pParams, IDS_TRUST_LONG, IDS_TRUST_SHORT, pResults->Trust.fPerformed,
  290. pResults->Trust.hr, 0);
  291. PrintMessageList(pParams, &pResults->Trust.lmsgOutput);
  292. }
  293. }
  294. void TrustPerInterfacePrint(IN NETDIAG_PARAMS *pParams,
  295. IN OUT NETDIAG_RESULT *pResults,
  296. IN INTERFACE_RESULT *pIfResult)
  297. {
  298. // no perinterface information
  299. }
  300. void TrustCleanup(IN NETDIAG_PARAMS *pParams,
  301. IN OUT NETDIAG_RESULT *pResults)
  302. {
  303. MessageListCleanUp(&pResults->Trust.lmsgOutput);
  304. }
  305. BOOL
  306. DomainSidRight(
  307. IN PTESTED_DOMAIN TestedDomain,
  308. NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults
  309. )
  310. /*++
  311. Routine Description:
  312. Determine if the DomainSid field of the TestDomain matches the DomainSid
  313. of the domain.
  314. Arguments:
  315. TestedDomain - Domain to test
  316. Return Value:
  317. TRUE: Test suceeded.
  318. FALSE: Test failed
  319. --*/
  320. {
  321. NET_API_STATUS NetStatus;
  322. NTSTATUS Status;
  323. BOOL RetVal = TRUE;
  324. SAM_HANDLE LocalSamHandle = NULL;
  325. SAM_HANDLE DomainHandle = NULL;
  326. PTESTED_DC pTestedDc;
  327. //
  328. // Initialization
  329. //
  330. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_ReallyVerbose, 0,
  331. IDS_TRUST_ENSURESID,
  332. TestedDomain->PrintableDomainName);
  333. if ( TestedDomain->DomainSid == NULL ) {
  334. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0,
  335. IDS_TRUST_MISSINGSID,
  336. TestedDomain->PrintableDomainName);
  337. RetVal = FALSE;
  338. goto Cleanup;
  339. }
  340. //
  341. // If we don't yet know a DC in the domain,
  342. // find one.
  343. //
  344. if ( TestedDomain->DcInfo == NULL )
  345. {
  346. LPTSTR pszDcType;
  347. if ( TestedDomain->fTriedToFindDcInfo ) {
  348. //IDS_DCLIST_NO_DC " '%ws': Cannot find DC to get DC list from [test skiped].\n"
  349. AddMessageToList( &pResults->Trust.lmsgOutput, Nd_Verbose, IDS_TRUST_NODC, TestedDomain->PrintableDomainName);
  350. goto Cleanup;
  351. }
  352. pszDcType = LoadAndAllocString(IDS_DCTYPE_DC);
  353. NetStatus = DoDsGetDcName( pParams,
  354. pResults,
  355. &pResults->Trust.lmsgOutput,
  356. TestedDomain,
  357. DS_DIRECTORY_SERVICE_PREFERRED,
  358. pszDcType, //"DC",
  359. FALSE,
  360. &TestedDomain->DcInfo );
  361. Free(pszDcType);
  362. TestedDomain->fTriedToFindDcInfo = TRUE;
  363. if ( NetStatus != NO_ERROR ) {
  364. //IDS_TRUST_NODC " '%ws': Cannot find DC to get DC list from [test skiped].\n"
  365. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Verbose, 0,
  366. IDS_TRUST_NODC, TestedDomain->PrintableDomainName);
  367. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Verbose, 4,
  368. IDS_GLOBAL_STATUS, NetStatusToString(NetStatus));
  369. // This isn't fatal.
  370. RetVal = TRUE;
  371. goto Cleanup;
  372. }
  373. }
  374. //
  375. // Get a DC that's UP.
  376. //
  377. pTestedDc = GetUpTestedDc( TestedDomain );
  378. if ( pTestedDc == NULL ) {
  379. AddMessageToList( &pResults->Trust.lmsgOutput, Nd_Verbose,
  380. IDS_TRUST_NODC_UP, TestedDomain->PrintableDomainName);
  381. PrintGuruMessage2(" '%ws': No DCs are up (Cannot run test).\n",
  382. TestedDomain->PrintableDomainName );
  383. PrintGuru( NetStatus, DSGETDC_GURU );
  384. // This isn't fatal.
  385. RetVal = TRUE;
  386. goto Cleanup;
  387. }
  388. //
  389. // Connect to the SAM server
  390. //
  391. Status = NettestSamConnect(
  392. pParams,
  393. pTestedDc->ComputerName,
  394. &LocalSamHandle );
  395. if ( !NT_SUCCESS(Status)) {
  396. if ( Status == STATUS_ACCESS_DENIED ) {
  397. //IDS_TRUST_NO_ACCESS " [WARNING] Don't have access to test your domain sid for domain '%ws'. [Test skipped]\n"
  398. AddMessageToList( &pResults->Trust.lmsgOutput, Nd_Verbose,
  399. IDS_TRUST_NO_ACCESS, TestedDomain->PrintableDomainName );
  400. }
  401. // This isn't fatal.
  402. RetVal = TRUE;
  403. goto Cleanup;
  404. }
  405. //
  406. // Open the domain.
  407. // Ask for no access to avoid access denied.
  408. //
  409. Status = SamOpenDomain( LocalSamHandle,
  410. 0,
  411. pResults->Global.pMemberDomain->DomainSid,
  412. &DomainHandle );
  413. if ( Status == STATUS_NO_SUCH_DOMAIN ) {
  414. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0, IDS_TRUST_WRONGSID, TestedDomain->PrintableDomainName );
  415. RetVal = FALSE;
  416. goto Cleanup;
  417. }
  418. if ( !NT_SUCCESS( Status ) ) {
  419. AddIMessageToList(&pResults->Trust.lmsgOutput, Nd_Quiet, 0, IDS_TRUST_FAILED_SAMOPEN, pTestedDc->ComputerName );
  420. RetVal = FALSE;
  421. goto Cleanup;
  422. }
  423. //
  424. // Cleanup locally used resources
  425. //
  426. Cleanup:
  427. if ( DomainHandle != NULL ) {
  428. (VOID) SamCloseHandle( DomainHandle );
  429. }
  430. if ( LocalSamHandle != NULL ) {
  431. (VOID) SamCloseHandle( LocalSamHandle );
  432. }
  433. return RetVal;
  434. }