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.

2367 lines
67 KiB

  1. /*++
  2. Microsoft Windows
  3. Copyright (C) Microsoft Corporation, 1998 - 2001
  4. Module Name:
  5. query.c
  6. Abstract:
  7. Handles the various functions for the QUERY command
  8. --*/
  9. #include "pch.h"
  10. #pragma hdrstop
  11. #include <netdom.h>
  12. #define VERIFY_QUERY_ONLY 0xFFFFFFFF
  13. typedef enum _ND5_ACCOUNT_TYPE {
  14. TypeWorkstation,
  15. TypeServer,
  16. TypeDomainController,
  17. TypePDC,
  18. TypeUnknown
  19. } ND5_ACCOUNT_TYPE;
  20. typedef enum _ND5_ACCOUNT_OPERATION {
  21. OperationDisplay,
  22. OperationVerify,
  23. OperationReset
  24. } ND5_ACCOUNT_OPERATION;
  25. typedef struct _ND5_TRANS_TREE_NODE {
  26. PDS_DOMAIN_TRUSTS DomainInfo;
  27. ULONG ListIndex;
  28. ULONG Children;
  29. struct _ND5_TRANS_TREE_NODE *ChildList;
  30. struct _ND5_TRANS_TREE_NODE *Parent;
  31. } ND5_TRANS_TREE_NODE, *PND5_TRANS_TREE_NODE;
  32. VOID
  33. NetDompFreeBuiltTrustInfo(
  34. IN PTRUSTED_DOMAIN_INFORMATION_EX TDInfoEx,
  35. IN ULONG Count
  36. )
  37. {
  38. ULONG i;
  39. for ( i = 0; i < Count; i++ ) {
  40. NetApiBufferFree( TDInfoEx[ i ].Name.Buffer );
  41. }
  42. NetApiBufferFree( TDInfoEx );
  43. }
  44. VOID
  45. NetDompDumpTrustInfo(
  46. IN PWSTR Domain,
  47. IN PTRUSTED_DOMAIN_INFORMATION_EX TrustInfo
  48. )
  49. /*++
  50. Routine Description:
  51. This function will display the specified trusted domain info
  52. Arguments:
  53. Domain - Domain to be dumped
  54. TrustInfo - Trust info the domain
  55. Return Value:
  56. VOID
  57. --*/
  58. {
  59. ULONG Message, Type;
  60. //
  61. // Display the direction & name
  62. //
  63. Type = TrustInfo->TrustDirection & TRUST_DIRECTION_BIDIRECTIONAL;
  64. switch ( Type ) {
  65. case TRUST_DIRECTION_BIDIRECTIONAL:
  66. Message = MSG_TRUST_BOTH_ARROW;
  67. break;
  68. case TRUST_DIRECTION_INBOUND:
  69. Message = MSG_TRUST_IN_ARROW;
  70. break;
  71. case TRUST_DIRECTION_OUTBOUND:
  72. Message = MSG_TRUST_OUT_ARROW;
  73. break;
  74. }
  75. NetDompDisplayMessage( Message,
  76. TrustInfo->Name.Buffer );
  77. //
  78. // Then, the type
  79. //
  80. switch ( TrustInfo->TrustType ) {
  81. case TRUST_TYPE_DOWNLEVEL:
  82. case TRUST_TYPE_UPLEVEL:
  83. Message = MSG_TRUST_TYPE_WINDOWS;
  84. break;
  85. case TRUST_TYPE_MIT:
  86. Message = MSG_TRUST_TYPE_MIT;
  87. break;
  88. default:
  89. Message = MSG_TRUST_TYPE_OTHER;
  90. break;
  91. }
  92. NetDompDisplayMessage( Message );
  93. printf( "\n" );
  94. }
  95. //+----------------------------------------------------------------------------
  96. //
  97. // Function: GetTrustInfo
  98. //
  99. // Synopsis: Reads the trust info from the local TDO for the named domain.
  100. //
  101. //-----------------------------------------------------------------------------
  102. DWORD
  103. GetTrustInfo(PWSTR pwzDomain,
  104. PND5_TRUST_INFO pLocalInfo,
  105. PND5_TRUST_INFO pTrustInfo,
  106. DWORD * pdwVerifyErr)
  107. {
  108. DWORD Win32Err = ERROR_SUCCESS;
  109. NTSTATUS Status = STATUS_SUCCESS;
  110. PTRUSTED_DOMAIN_INFORMATION_EX pTDIEx = NULL;
  111. UNICODE_STRING usDomainName;
  112. LSA_HANDLE hTrust;
  113. *pdwVerifyErr = ERROR_ACCESS_DENIED;
  114. RtlInitUnicodeString(&usDomainName, pwzDomain);
  115. Status = LsaOpenTrustedDomainByName(pLocalInfo->LsaHandle,
  116. &usDomainName,
  117. TRUSTED_READ,
  118. &hTrust);
  119. if (!NT_SUCCESS(Status))
  120. {
  121. *pdwVerifyErr = LsaNtStatusToWinError(Status);
  122. return *pdwVerifyErr;
  123. }
  124. Status = LsaQueryInfoTrustedDomain(hTrust,
  125. TrustedDomainInformationEx,
  126. (PVOID*)&pTDIEx);
  127. if (!NT_SUCCESS(Status))
  128. {
  129. *pdwVerifyErr = LsaNtStatusToWinError(Status);
  130. return *pdwVerifyErr;
  131. }
  132. pTrustInfo->TrustHandle = hTrust;
  133. pTrustInfo->DomainName = &pTDIEx->Name;
  134. pTrustInfo->FlatName = &pTDIEx->FlatName;
  135. pTrustInfo->Sid = pTDIEx->Sid;
  136. pTrustInfo->BlobToFree = pTDIEx;
  137. if (pTDIEx->TrustType >= TRUST_TYPE_MIT)
  138. {
  139. pTrustInfo->Uplevel = FALSE;
  140. pTrustInfo->Flags = NETDOM_TRUST_TYPE_MIT;
  141. *pdwVerifyErr = ERROR_SUCCESS;
  142. }
  143. else
  144. {
  145. PDOMAIN_CONTROLLER_INFO pDcInfo = NULL;
  146. PPOLICY_DNS_DOMAIN_INFO pPolicyDDI = NULL;
  147. OBJECT_ATTRIBUTES OA;
  148. UNICODE_STRING ServerU, DomainNameU;
  149. // Get a DC name for the domain.
  150. //
  151. Win32Err = DsGetDcName(NULL,
  152. pwzDomain,
  153. NULL,
  154. NULL,
  155. DS_DIRECTORY_SERVICE_PREFERRED,
  156. &pDcInfo );
  157. if (ERROR_SUCCESS != Win32Err)
  158. {
  159. pTrustInfo->Flags = NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND;
  160. *pdwVerifyErr = Win32Err;
  161. return ERROR_SUCCESS;
  162. }
  163. // Save off the DC name.
  164. //
  165. Win32Err = NetApiBufferAllocate((wcslen(pDcInfo->DomainControllerName) + 1) * sizeof(WCHAR),
  166. (PVOID*)&(pTrustInfo->Server));
  167. if (ERROR_SUCCESS != Win32Err)
  168. {
  169. NetApiBufferFree(pDcInfo);
  170. return Win32Err;
  171. }
  172. wcscpy(pTrustInfo->Server, pDcInfo->DomainControllerName);
  173. NetApiBufferFree(pDcInfo);
  174. Win32Err = NetpManageIPCConnect(pTrustInfo->Server,
  175. L"",
  176. L"",
  177. NETSETUPP_NULL_SESSION_IPC);
  178. if (ERROR_SUCCESS == Win32Err)
  179. {
  180. pTrustInfo->Connected = TRUE;
  181. }
  182. RtlInitUnicodeString(&ServerU, pTrustInfo->Server);
  183. InitializeObjectAttributes( &OA, NULL, 0, NULL, NULL );
  184. Status = LsaOpenPolicy(&ServerU,
  185. &OA,
  186. POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES,
  187. &(pTrustInfo->LsaHandle));
  188. if (NT_SUCCESS(Status))
  189. {
  190. // Find out if this is an uplevel or downlevel domain.
  191. //
  192. Status = LsaQueryInformationPolicy(pTrustInfo->LsaHandle,
  193. PolicyDnsDomainInformation,
  194. (PVOID *)&pPolicyDDI);
  195. if (NT_SUCCESS(Status))
  196. {
  197. LsaFreeMemory(pPolicyDDI);
  198. pTrustInfo->Uplevel = TRUE;
  199. pTrustInfo->fWasDownlevel = FALSE;
  200. }
  201. else
  202. {
  203. if (RPC_NT_PROCNUM_OUT_OF_RANGE == Status)
  204. {
  205. pTrustInfo->Uplevel = pTrustInfo->fWasDownlevel = FALSE;
  206. Status = STATUS_SUCCESS;
  207. }
  208. }
  209. }
  210. if (ERROR_NO_SUCH_DOMAIN == (*pdwVerifyErr = RtlNtStatusToDosError(Status)) ||
  211. RPC_S_SERVER_UNAVAILABLE == *pdwVerifyErr)
  212. {
  213. pTrustInfo->Flags = NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND;
  214. }
  215. if (*pdwVerifyErr != ERROR_SUCCESS && pTrustInfo->Connected)
  216. {
  217. NetpManageIPCConnect(pTrustInfo->Server,
  218. NULL,
  219. NULL,
  220. NETSETUPP_DISCONNECT_IPC);
  221. pTrustInfo->Connected = FALSE;
  222. }
  223. }
  224. return S_OK;
  225. }
  226. DWORD
  227. NetDompQueryDirectTrust(
  228. IN PWSTR Domain,
  229. IN PND5_TRUST_INFO TrustInfo
  230. )
  231. /*++
  232. Routine Description:
  233. This function will get the trustinfo for the specified domain
  234. Arguments:
  235. Domain - Domain to get the trust info for
  236. TrustInfo - Trust info to be obtained
  237. Return Value:
  238. ERROR_SUCCESS - The function succeeded
  239. --*/
  240. {
  241. DWORD Win32Err = ERROR_SUCCESS;
  242. NTSTATUS Status = STATUS_SUCCESS;
  243. LSA_ENUMERATION_HANDLE EnumerationContext = 0;
  244. PTRUSTED_DOMAIN_INFORMATION_EX TDInfoEx = NULL, TempTDIEx = NULL;
  245. PLSA_TRUST_INFORMATION TDInfo = NULL;
  246. ULONG Count, i, TotalCount = 0, UserCount, j;
  247. BOOL DisplayHeader = TRUE;
  248. LPUSER_INFO_0 UserList = NULL;
  249. ULONG ResumeHandle = 0;
  250. PWSTR Lop, FullServer = NULL;
  251. //
  252. // Handle the uplevel case differently
  253. //
  254. if ( TrustInfo->Uplevel ) {
  255. do {
  256. Status = LsaEnumerateTrustedDomainsEx( TrustInfo->LsaHandle,
  257. &EnumerationContext,
  258. (PVOID*)&TDInfoEx,
  259. 0x1000,
  260. &Count );
  261. if ( NT_SUCCESS( Status ) || Status == STATUS_NO_MORE_ENTRIES ) {
  262. if ( DisplayHeader ) {
  263. NetDompDisplayMessage( MSG_TRUST_DIRECT_HEADER );
  264. DisplayHeader = FALSE;
  265. }
  266. for ( i = 0; i < Count; i++ ) {
  267. NetDompDumpTrustInfo( TrustInfo->DomainName->Buffer,
  268. &TDInfoEx[ i ] );
  269. }
  270. }
  271. LsaFreeMemory( TDInfoEx );
  272. TDInfoEx = NULL;
  273. } while ( Status == STATUS_MORE_ENTRIES );
  274. } else {
  275. //
  276. // We'll have to do this the old fashioned way. That means that we'll enumerate all of
  277. // the trust directly, save them off in a list, and then go through and enumerate all
  278. // of the interdomain trust accounts and merge those into the list.
  279. //
  280. do {
  281. Status = LsaEnumerateTrustedDomains( TrustInfo->LsaHandle,
  282. &EnumerationContext,
  283. (PVOID*)&TDInfo,
  284. 0x1000,
  285. &Count );
  286. if ( NT_SUCCESS( Status ) || Status == STATUS_NO_MORE_ENTRIES ) {
  287. Win32Err = NetApiBufferAllocate( ( Count + TotalCount ) *
  288. sizeof( TRUSTED_DOMAIN_INFORMATION_EX ),
  289. (PVOID*)&TempTDIEx );
  290. if ( Win32Err != ERROR_SUCCESS ) {
  291. Status = STATUS_INSUFFICIENT_RESOURCES;
  292. break;
  293. }
  294. RtlZeroMemory( TempTDIEx, ( Count + TotalCount ) *
  295. sizeof( TRUSTED_DOMAIN_INFORMATION_EX ) );
  296. RtlCopyMemory( TempTDIEx,
  297. TDInfoEx,
  298. TotalCount * sizeof( TRUSTED_DOMAIN_INFORMATION_EX ) );
  299. for ( i = 0; i < Count; i++ ) {
  300. TempTDIEx[ TotalCount + i ].TrustType = TRUST_TYPE_DOWNLEVEL;
  301. TempTDIEx[ TotalCount + i ].TrustDirection = TRUST_DIRECTION_OUTBOUND;
  302. Win32Err = NetApiBufferAllocate( TDInfo[ i ].Name.MaximumLength,
  303. (PVOID*)&( TempTDIEx[ TotalCount + i ].Name.Buffer ) );
  304. if ( Win32Err != ERROR_SUCCESS ) {
  305. Status = STATUS_INSUFFICIENT_RESOURCES;
  306. break;
  307. }
  308. RtlCopyMemory( TempTDIEx[ TotalCount + i ].Name.Buffer,
  309. TDInfo[ i ].Name.Buffer,
  310. TDInfo[ i ].Name.MaximumLength );
  311. TempTDIEx[ TotalCount + i ].Name.Length = TDInfo[ i ].Name.Length;
  312. TempTDIEx[ TotalCount + i ].Name.MaximumLength =
  313. TDInfo[ i ].Name.MaximumLength;
  314. }
  315. if ( NT_SUCCESS( Status ) ) {
  316. NetApiBufferFree( TDInfoEx );
  317. TDInfoEx = TempTDIEx;
  318. TotalCount += Count;
  319. } else {
  320. for ( j = 0; j < i; j++ ) {
  321. NetApiBufferFree( TempTDIEx[ TotalCount + j ].Name.Buffer );
  322. TempTDIEx[ TotalCount + j ].Name.Buffer = NULL;
  323. }
  324. NetApiBufferFree( TempTDIEx );
  325. }
  326. }
  327. } while ( Status == STATUS_MORE_ENTRIES );
  328. //
  329. // Now, let's add in the user accounts
  330. //
  331. if ( NT_SUCCESS( Status ) ) {
  332. if ( TrustInfo->Server && *( TrustInfo->Server ) != L'\\' ) {
  333. Win32Err = NetApiBufferAllocate( ( wcslen( TrustInfo->Server ) + 3 ) * sizeof( WCHAR ),
  334. ( PVOID * )&FullServer );
  335. if ( Win32Err == ERROR_SUCCESS ) {
  336. swprintf( FullServer, L"\\\\%ws", TrustInfo->Server );
  337. }
  338. } else {
  339. FullServer = TrustInfo->Server;
  340. }
  341. if ( Win32Err == ERROR_SUCCESS ) {
  342. do {
  343. Win32Err = NetUserEnum( FullServer,
  344. 0,
  345. FILTER_INTERDOMAIN_TRUST_ACCOUNT,
  346. ( LPBYTE * )&UserList,
  347. MAX_PREFERRED_LENGTH,
  348. &Count,
  349. &UserCount,
  350. &ResumeHandle );
  351. if ( Win32Err == ERROR_SUCCESS || Win32Err == ERROR_MORE_DATA ) {
  352. for ( i = 0; i < Count; i++ ) {
  353. Lop = wcsrchr( UserList[ i ].usri0_name, L'$' );
  354. if ( Lop ) {
  355. *Lop = UNICODE_NULL;
  356. }
  357. for ( j = 0; j < TotalCount; j++ ) {
  358. if ( _wcsicmp( UserList[ i ].usri0_name,
  359. TDInfoEx[ j ].Name.Buffer ) == 0 ) {
  360. TDInfoEx[ j ].TrustDirection |= TRUST_DIRECTION_INBOUND;
  361. break;
  362. }
  363. }
  364. //
  365. // If it wasn't found, add it...
  366. //
  367. if ( j == TotalCount ) {
  368. Win32Err = NetApiBufferAllocate( ( 1 + TotalCount ) *
  369. sizeof( TRUSTED_DOMAIN_INFORMATION_EX ),
  370. (PVOID*)&TempTDIEx );
  371. if ( Win32Err != ERROR_SUCCESS ) {
  372. Status = STATUS_INSUFFICIENT_RESOURCES;
  373. break;
  374. }
  375. RtlZeroMemory( TempTDIEx,
  376. ( 1 + TotalCount ) *
  377. sizeof( TRUSTED_DOMAIN_INFORMATION_EX ) );
  378. RtlCopyMemory( TempTDIEx,
  379. TDInfoEx,
  380. TotalCount * sizeof( TRUSTED_DOMAIN_INFORMATION_EX ) );
  381. TempTDIEx[ TotalCount ].TrustType = TRUST_TYPE_DOWNLEVEL;
  382. TempTDIEx[ TotalCount ].TrustDirection = TRUST_DIRECTION_INBOUND;
  383. Win32Err = NetApiBufferAllocate(
  384. ( wcslen( UserList[ i ].usri0_name ) + 1 ) *
  385. sizeof( WCHAR ) ,
  386. (PVOID*)&( TempTDIEx[ TotalCount ].Name.Buffer ) );
  387. if ( Win32Err != ERROR_SUCCESS ) {
  388. Status = STATUS_INSUFFICIENT_RESOURCES;
  389. break;
  390. }
  391. wcscpy( TempTDIEx[ TotalCount ].Name.Buffer,
  392. UserList[ i ].usri0_name );
  393. RtlInitUnicodeString( &TempTDIEx[ TotalCount ].Name,
  394. TempTDIEx[ TotalCount ].Name.Buffer );
  395. if ( NT_SUCCESS( Status ) ) {
  396. NetApiBufferFree( TDInfoEx );
  397. TDInfoEx = TempTDIEx;
  398. TotalCount++;
  399. } else {
  400. NetApiBufferFree( TempTDIEx );
  401. }
  402. }
  403. if ( Lop ) {
  404. *Lop = L'$';
  405. }
  406. }
  407. NetApiBufferFree( UserList );
  408. }
  409. } while ( Win32Err == ERROR_MORE_DATA );
  410. if( FullServer != TrustInfo->Server )
  411. NetApiBufferFree( FullServer );
  412. }
  413. //
  414. // If everything worked, then dump them all
  415. //
  416. if ( Win32Err == ERROR_SUCCESS ) {
  417. if ( TotalCount > 0 ) {
  418. NetDompDisplayMessage( MSG_TRUST_DIRECT_HEADER );
  419. }
  420. for ( i = 0; i < TotalCount; i++ ) {
  421. NetDompDumpTrustInfo( TrustInfo->DomainName->Buffer,
  422. &TDInfoEx[ i ] );
  423. }
  424. }
  425. NetDompFreeBuiltTrustInfo( TDInfoEx, TotalCount );
  426. } else {
  427. Win32Err = RtlNtStatusToDosError( Status );
  428. }
  429. }
  430. if ( Status == STATUS_NO_MORE_ENTRIES ) {
  431. Status = STATUS_SUCCESS;
  432. }
  433. if ( Win32Err == ERROR_SUCCESS ) {
  434. Win32Err = RtlNtStatusToDosError( Status );
  435. }
  436. return( Win32Err );
  437. }
  438. DWORD
  439. NetDompFindChildrenForNode(
  440. IN PWSTR LocalDomain,
  441. IN ULONG DomainCount,
  442. IN PDS_DOMAIN_TRUSTS DomainList,
  443. IN OUT PND5_TRANS_TREE_NODE TreeNode,
  444. IN OUT PND5_TRANS_TREE_NODE *DomainNode
  445. )
  446. /*++
  447. Routine Description:
  448. This recursive function will find all of the children for a given node in the trust list
  449. Arguments:
  450. LocalDomain - Domain to find the children for
  451. DomainCount - Number of domains in the list
  452. DomainList - List of domains
  453. TreeNode - Tree to insert into
  454. DomainNode - Pointer to the LocalDomain's node, if encountered
  455. Return Value:
  456. ERROR_SUCCESS - The function succeeded
  457. ERROR_INVALID_PARAMETER - No server, workstation or machine was specified
  458. --*/
  459. {
  460. DWORD Win32Err = ERROR_SUCCESS;
  461. ULONG i, Count = 0;
  462. BOOL HandleDirect = FALSE;
  463. //
  464. // See how many
  465. //
  466. for ( i = 0; i < DomainCount; i++ ) {
  467. if ( DomainList[ i ].ParentIndex == TreeNode->ListIndex &&
  468. FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_IN_FOREST ) &&
  469. !FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_TREE_ROOT)) {
  470. Count++;
  471. }
  472. }
  473. //
  474. // If we have the current node, then make sure we get the direct trusts as well
  475. //
  476. if ( ( TreeNode->DomainInfo->DnsDomainName &&
  477. _wcsicmp( LocalDomain, TreeNode->DomainInfo->DnsDomainName ) == 0 ) ||
  478. _wcsicmp( LocalDomain, TreeNode->DomainInfo->NetbiosDomainName ) == 0 ) {
  479. HandleDirect = TRUE;
  480. *DomainNode = TreeNode;
  481. for ( i = 0; i < DomainCount; i++ ) {
  482. if ( FLAG_ON( DomainList[ i ].Flags, (DS_DOMAIN_DIRECT_OUTBOUND | DS_DOMAIN_DIRECT_INBOUND) ) &&
  483. !FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_IN_FOREST ) &&
  484. DomainList[ i ].ParentIndex == 0 ) {
  485. Count++;
  486. }
  487. }
  488. }
  489. //
  490. // Add 'em to the list
  491. //
  492. if ( Count ) {
  493. Win32Err = NetApiBufferAllocate( Count * sizeof( ND5_TRANS_TREE_NODE ),
  494. (PVOID*)&( TreeNode->ChildList ) );
  495. if ( Win32Err == ERROR_SUCCESS ) {
  496. RtlZeroMemory( TreeNode->ChildList, Count * sizeof( ND5_TRANS_TREE_NODE ) );
  497. for ( i = 0; i < DomainCount && Win32Err == ERROR_SUCCESS; i++ ) {
  498. if ( DomainList[ i ].ParentIndex == TreeNode->ListIndex &&
  499. FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_IN_FOREST ) &&
  500. !FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_TREE_ROOT) ) {
  501. TreeNode->ChildList[ TreeNode->Children ].DomainInfo = &DomainList[ i ];
  502. TreeNode->ChildList[ TreeNode->Children ].ListIndex = i;
  503. TreeNode->ChildList[ TreeNode->Children ].Parent = TreeNode;
  504. Win32Err = NetDompFindChildrenForNode( LocalDomain,
  505. DomainCount,
  506. DomainList,
  507. &TreeNode->ChildList[ TreeNode->Children ],
  508. DomainNode );
  509. TreeNode->Children++;
  510. DomainList[ i ].ParentIndex = 0xFFFFFFFF;
  511. }
  512. }
  513. //
  514. // Now, the other local entries
  515. //
  516. if ( Win32Err == ERROR_SUCCESS && HandleDirect ) {
  517. for ( i = 0; i < DomainCount; i++ ) {
  518. if ( FLAG_ON( DomainList[ i ].Flags, (DS_DOMAIN_DIRECT_OUTBOUND | DS_DOMAIN_DIRECT_INBOUND) ) &&
  519. !FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_IN_FOREST ) &&
  520. DomainList[ i ].ParentIndex == 0 ) {
  521. TreeNode->ChildList[ TreeNode->Children ].DomainInfo = &DomainList[ i ];
  522. TreeNode->ChildList[ TreeNode->Children ].ListIndex = i;
  523. TreeNode->Children++;
  524. DomainList[ i ].ParentIndex = 0xFFFFFFFF;
  525. }
  526. }
  527. }
  528. }
  529. }
  530. return( Win32Err );
  531. }
  532. DWORD
  533. NetDompBuildTransTrustTree(
  534. IN PWSTR LocalDomain,
  535. IN ULONG DomainCount,
  536. IN PDS_DOMAIN_TRUSTS DomainList,
  537. OUT PND5_TRANS_TREE_NODE *TreeRoot,
  538. OUT PND5_TRANS_TREE_NODE *CurrentDomainNode
  539. )
  540. /*++
  541. Routine Description:
  542. This function will build the transative trust tree for the given trust list
  543. Arguments:
  544. LocalDomain - Current domain
  545. DomainCount - Number of domains in the list
  546. DomainList - List of domains
  547. TreeRoot - Tree root
  548. CurrentDomainNode - Pointer to the LocalDomain's node
  549. Return Value:
  550. ERROR_SUCCESS - The function succeeded
  551. ERROR_INVALID_PARAMETER - No server, workstation or machine was specified
  552. --*/
  553. {
  554. DWORD Win32Err = ERROR_SUCCESS;
  555. PND5_TRANS_TREE_NODE Root = NULL, Temp = NULL, DomainNode = NULL;
  556. PDS_DOMAIN_TRUSTS TDRoot = NULL;
  557. ULONG i, Index;
  558. //
  559. // First, find the tree root.
  560. //
  561. for ( i = 0; i < DomainCount; i++ ) {
  562. if ( DomainList[ i ].ParentIndex == 0 &&
  563. FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_TREE_ROOT ) ) {
  564. TDRoot = &DomainList[ i ];
  565. Index = i;
  566. break;
  567. }
  568. }
  569. if ( TDRoot == NULL ) {
  570. //
  571. // Find ourselves, and make us the root
  572. //
  573. for ( i = 0; i < DomainCount; i++ ) {
  574. if ( ( DomainList[ i ].DnsDomainName &&
  575. _wcsicmp( LocalDomain, DomainList[ i ].DnsDomainName ) == 0 ) ||
  576. _wcsicmp( LocalDomain, DomainList[ i ].NetbiosDomainName ) == 0 ) {
  577. TDRoot = &DomainList[ i ];
  578. Index = i;
  579. break;
  580. }
  581. }
  582. }
  583. //
  584. // If we still don't have one, bail...
  585. //
  586. if ( TDRoot == NULL) {
  587. Win32Err = ERROR_INVALID_DOMAIN_STATE;
  588. goto BuildTransExit;
  589. }
  590. Win32Err = NetApiBufferAllocate( sizeof( ND5_TRANS_TREE_NODE ), (PVOID*)&Root );
  591. if ( Win32Err != ERROR_SUCCESS ) {
  592. goto BuildTransExit;
  593. }
  594. RtlZeroMemory( Root, sizeof( ND5_TRANS_TREE_NODE ) );
  595. Root->DomainInfo = TDRoot;
  596. Root->ListIndex = Index;
  597. TDRoot->ParentIndex = 0xFFFFFFFF;
  598. Win32Err = NetDompFindChildrenForNode( LocalDomain,
  599. DomainCount,
  600. DomainList,
  601. Root,
  602. &DomainNode );
  603. BuildTransExit:
  604. if ( Win32Err == ERROR_SUCCESS ) {
  605. *TreeRoot = Root;
  606. *CurrentDomainNode = DomainNode;
  607. }
  608. return( Win32Err );
  609. }
  610. DWORD
  611. NetDompGetTrustDirection(
  612. IN PND5_TRUST_INFO TrustingInfo,
  613. IN PND5_TRUST_INFO TrustedInfo,
  614. IN OUT PDWORD Direction
  615. )
  616. /*++
  617. Routine Description:
  618. This function will get the direction of the trust between the 2 specified domains
  619. Arguments:
  620. TrustingInfo - Domain #1
  621. TrustedInfo - Domain #2
  622. Direction - Where the trust direction is returned
  623. Return Value:
  624. ERROR_SUCCESS - The function succeeded
  625. --*/
  626. {
  627. DWORD Win32Err = ERROR_SUCCESS;
  628. NTSTATUS Status;
  629. LSA_HANDLE TrustedDomain;
  630. PTRUSTED_DOMAIN_INFORMATION_EX TDIEx = NULL;
  631. PUSER_INFO_1 UI1 = NULL;
  632. WCHAR AccountName[ UNLEN + 1 ];
  633. if ( TrustingInfo->Uplevel ) {
  634. Status = LsaQueryTrustedDomainInfoByName( TrustingInfo->LsaHandle,
  635. TrustedInfo->DomainName,
  636. TrustedDomainInformationEx,
  637. (PVOID*)&TDIEx );
  638. if (STATUS_OBJECT_NAME_NOT_FOUND == Status && TrustedInfo->Uplevel)
  639. {
  640. // Pre-existing TDOs for domains upgraded from NT4 to NT5 will continue to
  641. // have a flat name.
  642. //
  643. TrustedInfo->fWasDownlevel = TRUE;
  644. Status = LsaQueryTrustedDomainInfoByName( TrustingInfo->LsaHandle,
  645. TrustedInfo->FlatName,
  646. TrustedDomainInformationEx,
  647. (PVOID*)&TDIEx );
  648. }
  649. if ( NT_SUCCESS( Status ) ) {
  650. DBG_VERBOSE(("Trust to domain %ws has direction %d\n", TrustedInfo->DomainName->Buffer,
  651. TDIEx->TrustDirection));
  652. *Direction = TDIEx->TrustDirection;
  653. LsaFreeMemory( TDIEx );
  654. }
  655. Win32Err = RtlNtStatusToDosError( Status );
  656. } else {
  657. *Direction = 0;
  658. Status = LsaOpenTrustedDomain( TrustingInfo->LsaHandle,
  659. TrustedInfo->Sid,
  660. MAXIMUM_ALLOWED,
  661. &TrustedDomain );
  662. if ( Status != STATUS_OBJECT_NAME_NOT_FOUND ) {
  663. *Direction = TRUST_DIRECTION_OUTBOUND;
  664. }
  665. if ( NT_SUCCESS( Status ) ) {
  666. LsaClose( TrustedDomain );
  667. }
  668. if ( TrustedInfo->FlatName->Length > DNLEN * sizeof( WCHAR ) ) {
  669. Win32Err = ERROR_INVALID_DOMAINNAME;
  670. } else {
  671. //
  672. // Build the account name...
  673. //
  674. swprintf( AccountName, L"%ws$", TrustedInfo->FlatName->Buffer );
  675. Win32Err = NetUserGetInfo( TrustingInfo->Server,
  676. AccountName,
  677. 1,
  678. ( LPBYTE * )&UI1 );
  679. if ( Win32Err != ERROR_NO_SUCH_USER ) {
  680. *Direction |= TRUST_DIRECTION_INBOUND;
  681. }
  682. if ( Win32Err == ERROR_SUCCESS ) {
  683. NetApiBufferFree( UI1 );
  684. }
  685. }
  686. }
  687. return( Win32Err );
  688. }
  689. /*++
  690. DWORD
  691. NetDompFindChildNode(
  692. IN PUNICODE_STRING ChildToFind,
  693. IN PND5_TRANS_TREE_NODE Current,
  694. IN PND5_TRANS_TREE_NODE Skip,
  695. IN ULONG Display,
  696. BOOL IncludeParent
  697. )
  698. Routine Description:
  699. This function will find the child of the current node
  700. Arguments:
  701. ChildToFind - Child domain to find
  702. Current - Where we are in the tree
  703. Skip - Node to not process if we are coming from our parent
  704. Display - Resource id of string to display
  705. IncludeParent - If TRUE, work up the tree as well as down
  706. Return Value:
  707. ERROR_SUCCESS - The function succeeded
  708. ERROR_INVALID_PARAMETER - No server, workstation or machine was specified
  709. {
  710. DWORD Win32Err = ERROR_NOT_FOUND;
  711. ULONG i;
  712. UNICODE_STRING CurrentDomain;
  713. BOOL Found = FALSE;
  714. if ( !Current ) {
  715. return( Win32Err );
  716. }
  717. for ( i = 0; i < Current->Children && !Found && Win32Err == ERROR_NOT_FOUND; i++ ) {
  718. RtlInitUnicodeString( &CurrentDomain,
  719. Current->ChildList[ i ].DomainInfo->DnsDomainName ?
  720. Current->ChildList[ i ].DomainInfo->DnsDomainName :
  721. Current->ChildList[ i ].DomainInfo->NetbiosDomainName );
  722. if ( RtlCompareUnicodeString( &CurrentDomain,
  723. ChildToFind,
  724. TRUE ) == 0 ) {
  725. Found = TRUE;
  726. break;
  727. } else {
  728. if ( Skip != &Current->ChildList[ i ] ) {
  729. Win32Err = NetDompFindChildNode( ChildToFind,
  730. &Current->ChildList[ i ],
  731. NULL,
  732. Display,
  733. FALSE );
  734. if ( Win32Err == ERROR_SUCCESS ) {
  735. break;
  736. }
  737. }
  738. }
  739. }
  740. if ( Win32Err == ERROR_NOT_FOUND && IncludeParent ) {
  741. if ( Current->Parent && !Found ) {
  742. RtlInitUnicodeString( &CurrentDomain,
  743. Current->Parent->DomainInfo->DnsDomainName ?
  744. Current->Parent->DomainInfo->DnsDomainName :
  745. Current->Parent->DomainInfo->NetbiosDomainName );
  746. if ( RtlCompareUnicodeString( &CurrentDomain,
  747. ChildToFind,
  748. TRUE ) == 0 ) {
  749. Found = TRUE;
  750. }
  751. }
  752. if ( !Found ) {
  753. Win32Err = NetDompFindChildNode( ChildToFind,
  754. Current->Parent,
  755. Current,
  756. Display,
  757. TRUE );
  758. }
  759. }
  760. if ( Win32Err == ERROR_SUCCESS && Display ) {
  761. NetDompDisplayMessage( Display,
  762. CurrentDomain.Buffer );
  763. }
  764. if ( Found ) {
  765. Win32Err = ERROR_SUCCESS;
  766. }
  767. return( Win32Err );
  768. }
  769. --*/
  770. DWORD
  771. NetDompDisplayTransTrustStatus(
  772. IN PND5_TRUST_INFO TrustInfo,
  773. IN PWSTR DomainName,
  774. //IN PND5_TRANS_TREE_NODE CurrentDomain,
  775. IN DWORD Direction,
  776. IN DWORD TrustStatus
  777. )
  778. /*++
  779. Routine Description:
  780. This function will display the status for a trust
  781. Arguments:
  782. TrustInfo - Trust info to display the status for
  783. DomainName - Name of the domain (if TrustInfo isn't available)
  784. CurrentDomain - Current domain node pointer
  785. Direction - Direction of the trust
  786. TrustStatus - Status code from verifying the trust
  787. Return Value:
  788. ERROR_SUCCESS - The function succeeded
  789. --*/
  790. {
  791. DWORD Win32Err = ERROR_SUCCESS;
  792. ULONG Message, Type;
  793. //
  794. // Display the direction & name
  795. //
  796. Type = Direction & TRUST_DIRECTION_BIDIRECTIONAL;
  797. switch ( Type ) {
  798. case 0:
  799. Message = MSG_TRUST_TRANS_NO_ARROW;
  800. break;
  801. case TRUST_DIRECTION_BIDIRECTIONAL:
  802. Message = MSG_TRUST_TRANS_BOTH_ARROW;
  803. break;
  804. case TRUST_DIRECTION_INBOUND:
  805. Message = MSG_TRUST_TRANS_IN_ARROW;
  806. break;
  807. case TRUST_DIRECTION_OUTBOUND:
  808. Message = MSG_TRUST_TRANS_OUT_ARROW;
  809. break;
  810. }
  811. NetDompDisplayMessage( Message, TrustInfo ? TrustInfo->DomainName->Buffer : DomainName );
  812. //
  813. // Then, the type
  814. //
  815. if (TrustInfo && TrustInfo->Flags & NETDOM_TRUST_TYPE_INDIRECT)
  816. {
  817. Message = MSG_TRUST_TYPE_INDIRECT;
  818. }
  819. else
  820. {
  821. if (TrustInfo && TrustInfo->Flags & NETDOM_TRUST_TYPE_MIT)
  822. {
  823. Message = MSG_TRUST_TYPE_MIT;
  824. }
  825. else
  826. {
  827. Message = MSG_TRUST_TYPE_WINDOWS;
  828. }
  829. }
  830. NetDompDisplayMessage( Message );
  831. //
  832. // Finally, the status.
  833. //
  834. if (TrustInfo && TrustInfo->Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND)
  835. {
  836. TrustStatus = ERROR_NO_SUCH_DOMAIN;
  837. }
  838. switch ( TrustStatus ) {
  839. case ERROR_SUCCESS:
  840. NetDompDisplayMessage( MSG_TRUST_VERIFIED );
  841. break;
  842. case ERROR_NO_SUCH_DOMAIN:
  843. NetDompDisplayMessage( MSG_TRUST_NO_DOMAIN );
  844. break;
  845. case ERROR_ACCESS_DENIED:
  846. NetDompDisplayMessage( MSG_TRUST_ACCESS_DENIED );
  847. break;
  848. case VERIFY_QUERY_ONLY:
  849. printf( "\n" );
  850. break;
  851. default:
  852. NetDompDisplayMessage( MSG_TRUST_BROKEN );
  853. break;
  854. }
  855. /* this doesn't work.
  856. if ( TrustInfo ) {
  857. Win32Err = NetDompFindChildNode( TrustInfo->DomainName,
  858. CurrentDomain,
  859. NULL,
  860. MSG_TRUST_VIA,
  861. TRUE );
  862. } */
  863. return( Win32Err );
  864. }
  865. DWORD
  866. NetDompQueryTrust(
  867. IN PWSTR Domain,
  868. IN PND5_AUTH_INFO AuthInfo,
  869. IN PWSTR pwzServer,
  870. IN BOOL Direct,
  871. IN BOOL Verify
  872. )
  873. /*++
  874. Routine Description:
  875. This function will get the list of trusts for a domain
  876. Arguments:
  877. Domain - Domain to get the trust for
  878. AuthInfo - Username and password to use to connect to the machine
  879. pwzServer - Server specified on command line, if any
  880. Direct - if TRUE, get only the DIRECTLY trusted domains
  881. Verify - If TRUE, verify that the trusts are valid
  882. Return Value:
  883. ERROR_SUCCESS - The function succeeded
  884. ERROR_INVALID_PARAMETER - No server, workstation or machine was specified
  885. --*/
  886. {
  887. DWORD Win32Err = ERROR_SUCCESS, VerifyErr;
  888. ND5_TRUST_INFO TrustInfo, OtherInfo;
  889. ULONG Count = 0, i;
  890. PDS_DOMAIN_TRUSTS rgTrustedDomains = NULL;
  891. ULONG Message, Type, Direction;
  892. //PND5_TRANS_TREE_NODE TreeRoot = NULL, CurrentDomainNode;
  893. PWSTR CurrentDomain;
  894. RtlZeroMemory( &TrustInfo, sizeof( ND5_TRUST_INFO ) );
  895. Win32Err = NetDompTrustGetDomInfo( Domain,
  896. pwzServer,
  897. AuthInfo,
  898. &TrustInfo,
  899. FALSE,
  900. FALSE,
  901. FALSE);
  902. if ( Win32Err == ERROR_SUCCESS ) {
  903. if ( Direct || !TrustInfo.Uplevel ) {
  904. Win32Err = NetDompQueryDirectTrust( Domain,
  905. &TrustInfo );
  906. } else {
  907. Win32Err = DsEnumerateDomainTrusts(TrustInfo.Server,
  908. DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND | DS_DOMAIN_DIRECT_INBOUND,
  909. &rgTrustedDomains,
  910. &Count);
  911. if ( Win32Err == ERROR_SUCCESS ) {
  912. if ( Count ) {
  913. NetDompDisplayMessage((Verify) ? MSG_TRUST_TRANS_HEADER_VERIFY :
  914. MSG_TRUST_TRANS_HEADER);
  915. }
  916. /* this doesn't work.
  917. Win32Err = NetDompBuildTransTrustTree( Domain,
  918. Count,
  919. rgTrustedDomains,
  920. &TreeRoot,
  921. &CurrentDomainNode ); */
  922. if ( Win32Err == ERROR_SUCCESS ) {
  923. for ( i = 0; i < Count; i++ ) {
  924. //
  925. // Make sure we aren't connecting to ourselves...
  926. //
  927. CurrentDomain = rgTrustedDomains[ i ].DnsDomainName ?
  928. rgTrustedDomains[ i ].DnsDomainName :
  929. rgTrustedDomains[ i ].NetbiosDomainName;
  930. if ( !_wcsicmp( CurrentDomain, TrustInfo.DomainName->Buffer ) ) {
  931. continue;
  932. }
  933. RtlZeroMemory(&OtherInfo, sizeof(ND5_TRUST_INFO));
  934. if (rgTrustedDomains[i].Flags & DS_DOMAIN_DIRECT_OUTBOUND ||
  935. rgTrustedDomains[i].Flags & DS_DOMAIN_DIRECT_INBOUND)
  936. {
  937. // There is a direct trust to the domain, therefore a TDO
  938. // exists, so read the domain data locally.
  939. //
  940. Win32Err = GetTrustInfo(CurrentDomain,
  941. &TrustInfo,
  942. &OtherInfo,
  943. &VerifyErr);
  944. if (ERROR_SUCCESS == Win32Err)
  945. {
  946. VerifyErr = NetDompGetTrustDirection(&TrustInfo,
  947. &OtherInfo,
  948. &Direction);
  949. }
  950. else
  951. {
  952. Direction = 0;
  953. }
  954. }
  955. else
  956. {
  957. Win32Err = NetDompTrustGetDomInfo(CurrentDomain,
  958. NULL,
  959. AuthInfo,
  960. &OtherInfo,
  961. FALSE,
  962. FALSE, TRUE);
  963. VerifyErr = Win32Err;
  964. OtherInfo.Flags |= NETDOM_TRUST_TYPE_INDIRECT;
  965. //
  966. // If the trust is indirect, it must be a forest trust.
  967. // Enterprise trusts always have a bi-di path.
  968. //
  969. Direction = TRUST_DIRECTION_BIDIRECTIONAL;
  970. }
  971. if (ERROR_SUCCESS == VerifyErr)
  972. {
  973. if (Verify
  974. && !(NETDOM_TRUST_TYPE_MIT & OtherInfo.Flags)
  975. && (DS_DOMAIN_DIRECT_OUTBOUND & rgTrustedDomains[i].Flags))
  976. {
  977. // Verify only direct, outbound, non-MIT trusts.
  978. // Can't verify incoming without creds to the other
  979. // domain.
  980. //
  981. VerifyErr = NetDompVerifyTrust(&TrustInfo,
  982. &OtherInfo,
  983. FALSE);
  984. }
  985. else
  986. {
  987. VerifyErr = VERIFY_QUERY_ONLY;
  988. }
  989. NetDompDisplayTransTrustStatus( &OtherInfo,
  990. NULL,
  991. //CurrentDomainNode,
  992. Direction,
  993. VerifyErr );
  994. NetDompFreeDomInfo( &OtherInfo );
  995. } else {
  996. if ( !Verify ) {
  997. VerifyErr = VERIFY_QUERY_ONLY;
  998. }
  999. NetDompDisplayTransTrustStatus( NULL,
  1000. rgTrustedDomains[ i ].DnsDomainName ?
  1001. rgTrustedDomains[ i ].DnsDomainName :
  1002. rgTrustedDomains[ i ].NetbiosDomainName,
  1003. //CurrentDomainNode,
  1004. Direction,
  1005. VerifyErr );
  1006. }
  1007. }
  1008. }
  1009. NetApiBufferFree( rgTrustedDomains );
  1010. }
  1011. }
  1012. NetDompFreeDomInfo( &TrustInfo );
  1013. }
  1014. return( Win32Err );
  1015. }
  1016. DWORD
  1017. NetDompQueryDisplayOus(
  1018. IN PWSTR Domain,
  1019. IN PND5_AUTH_INFO AuthInfo
  1020. )
  1021. /*++
  1022. Routine Description:
  1023. This function will list the OUs under which the specified user can create a computer object
  1024. Arguments:
  1025. Domain - Domain to connect to
  1026. AuthInfo - Username and password to connect to the domain with
  1027. Return Value:
  1028. ERROR_SUCCESS - The function succeeded
  1029. --*/
  1030. {
  1031. DWORD Win32Err = ERROR_SUCCESS;
  1032. PWSTR *OuList;
  1033. ULONG OuCount = 0, i;
  1034. //
  1035. // Get the list and display it
  1036. //
  1037. LOG_VERBOSE(( MSG_VERBOSE_DETERMINE_OU ));
  1038. Win32Err = NetGetJoinableOUs( NULL,
  1039. Domain,
  1040. AuthInfo->User,
  1041. AuthInfo->Password,
  1042. &OuCount,
  1043. &OuList );
  1044. if ( Win32Err == ERROR_SUCCESS ) {
  1045. NetDompDisplayMessage( MSG_OU_LIST );
  1046. for ( i = 0; i < OuCount; i++ ) {
  1047. printf( "%ws\n", OuList[ i ] );
  1048. }
  1049. NetApiBufferFree( OuList );
  1050. }
  1051. return( Win32Err );
  1052. }
  1053. DWORD
  1054. NetDompQueryFsmo(
  1055. IN PWSTR Domain,
  1056. IN PND5_AUTH_INFO AuthInfo
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. This function will list the machines holding the various FSMO roles
  1061. Arguments:
  1062. Domain - Domain to connect to
  1063. AuthInfo - Username and password to connect to the domain with
  1064. Return Value:
  1065. ERROR_SUCCESS - The function succeeded
  1066. --*/
  1067. {
  1068. DWORD Win32Err = ERROR_SUCCESS;
  1069. PWSTR User = NULL, Separator = NULL, pwzDomain = NULL, FsmoServer = NULL, ServerPath;
  1070. PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
  1071. HANDLE DsHandle = NULL;
  1072. RPC_AUTH_IDENTITY_HANDLE AuthHandle;
  1073. PDS_NAME_RESULT DsRoles = NULL;
  1074. PLDAP Ldap = NULL;
  1075. ULONG i;
  1076. ULONG DisplayMap[ ] = {
  1077. MSG_FSMO_SCHEMA,
  1078. MSG_FSMO_DOMAIN,
  1079. MSG_FSMO_PDC,
  1080. MSG_FSMO_RID,
  1081. MSG_FSMO_INFRASTRUCTURE
  1082. };
  1083. //
  1084. // Find a domain controller
  1085. //
  1086. LOG_VERBOSE(( MSG_VERBOSE_FIND_DC, Domain ));
  1087. Win32Err = DsGetDcName( NULL,
  1088. Domain,
  1089. NULL,
  1090. NULL,
  1091. DS_DIRECTORY_SERVICE_REQUIRED,
  1092. &DcInfo );
  1093. if ( Win32Err == ERROR_SUCCESS ) {
  1094. if ( AuthInfo->User ) {
  1095. Separator = wcschr( AuthInfo->User, L'\\' );
  1096. if ( Separator ) {
  1097. *Separator = UNICODE_NULL;
  1098. User = Separator + 1;
  1099. if (!*User) {
  1100. return ERROR_INVALID_PARAMETER;
  1101. }
  1102. pwzDomain = AuthInfo->User;
  1103. } else {
  1104. User = AuthInfo->User;
  1105. pwzDomain = Domain;
  1106. }
  1107. }
  1108. Win32Err = DsMakePasswordCredentials( User,
  1109. pwzDomain,
  1110. AuthInfo->Password,
  1111. &AuthHandle );
  1112. if ( Win32Err == ERROR_SUCCESS ) {
  1113. Win32Err = DsBindWithCred( DcInfo->DomainControllerName,
  1114. NULL,
  1115. AuthHandle,
  1116. &DsHandle );
  1117. DsFreePasswordCredentials( AuthHandle );
  1118. }
  1119. //
  1120. // Now, start getting the info
  1121. //
  1122. if ( Win32Err == ERROR_SUCCESS ) {
  1123. Win32Err = DsListRoles( DsHandle,
  1124. &DsRoles );
  1125. if ( Win32Err == ERROR_SUCCESS ) {
  1126. ASSERT( sizeof( DisplayMap ) / sizeof( ULONG ) == DsRoles->cItems );
  1127. for ( i = 0; i < sizeof( DisplayMap ) / sizeof( ULONG ); i++ ) {
  1128. ULONG Type = 0;
  1129. //
  1130. // Skip items that may not exist
  1131. //
  1132. if ( DsRoles->rItems[ i ].status != DS_NAME_NO_ERROR ) {
  1133. continue;
  1134. }
  1135. ServerPath = wcschr( DsRoles->rItems[ i ].pName, L',' );
  1136. if ( ServerPath ) {
  1137. ServerPath++;
  1138. } else {
  1139. ServerPath = DsRoles->rItems[ i ].pName;
  1140. }
  1141. if ( !Ldap ) {
  1142. Win32Err = NetDompLdapBind( DcInfo->DomainControllerName + 2,
  1143. User == AuthInfo->User ? NULL : AuthInfo->User,
  1144. User,
  1145. AuthInfo->Password,
  1146. LDAP_AUTH_SSPI,
  1147. &Ldap );
  1148. }
  1149. if ( Win32Err == ERROR_SUCCESS ) {
  1150. Win32Err = NetDompLdapReadOneAttribute( Ldap,
  1151. ServerPath,
  1152. L"dNSHostName",
  1153. &FsmoServer );
  1154. if ( Win32Err == ERROR_SUCCESS ) {
  1155. NetDompDisplayMessage( DisplayMap[ i ], FsmoServer );
  1156. NetApiBufferFree( FsmoServer );
  1157. }
  1158. }
  1159. }
  1160. }
  1161. }
  1162. }
  1163. if ( DsHandle ) {
  1164. DsUnBind( &DsHandle );
  1165. }
  1166. if ( DsRoles ) {
  1167. DsFreeNameResult( DsRoles );
  1168. }
  1169. if ( Separator ) {
  1170. *Separator = L'\\';
  1171. }
  1172. NetApiBufferFree( DcInfo );
  1173. return( Win32Err );
  1174. }
  1175. DWORD
  1176. NetDompDisplayMachineByType(
  1177. IN PWSTR AccountName,
  1178. IN PND5_AUTH_INFO AuthInfo,
  1179. IN ND5_ACCOUNT_TYPE DesiredType,
  1180. IN ND5_ACCOUNT_TYPE KnownType,
  1181. IN BOOL DisplayOnError
  1182. )
  1183. /*++
  1184. Routine Description:
  1185. This function display machines of the specified type that are joined to the domain
  1186. Arguments:
  1187. AccountName - Name of the machine to get the info from
  1188. AuthInfo - Username and password to connect to the domain with
  1189. DesiredType - Type of machine to get
  1190. KnownType - Whether the machine type is known or not
  1191. DisplayOnError - If TRUE, display a message if an error is encountered
  1192. Return Value:
  1193. ERROR_SUCCESS - The function succeeded
  1194. ERROR_UNSUPPORTED_TYPE - An unknown type was encountered
  1195. --*/
  1196. {
  1197. DWORD Win32Err = ERROR_SUCCESS;
  1198. PSERVER_INFO_101 SrvInfo = NULL;
  1199. PWSTR AccountChar;
  1200. AccountChar = wcsrchr( AccountName, L'$' );
  1201. if ( AccountChar ) {
  1202. *AccountChar = UNICODE_NULL;
  1203. }
  1204. //
  1205. // See if we have to get the type or not
  1206. //
  1207. if ( KnownType == TypeUnknown ) {
  1208. Win32Err = NetpManageIPCConnect( AccountName,
  1209. AuthInfo->User,
  1210. AuthInfo->Password,
  1211. NETSETUPP_CONNECT_IPC );
  1212. if ( Win32Err == ERROR_SUCCESS ) {
  1213. Win32Err = NetServerGetInfo( AccountName,
  1214. 101,
  1215. ( LPBYTE * )&SrvInfo );
  1216. NetpManageIPCConnect( AccountName,
  1217. AuthInfo->User,
  1218. AuthInfo->Password,
  1219. NETSETUPP_DISCONNECT_IPC );
  1220. }
  1221. if ( Win32Err == ERROR_SUCCESS ) {
  1222. if ( FLAG_ON( SrvInfo->sv101_type, SV_TYPE_DOMAIN_BAKCTRL ) ) {
  1223. KnownType = TypeDomainController;
  1224. } else if ( FLAG_ON( SrvInfo->sv101_type, SV_TYPE_DOMAIN_CTRL ) ) {
  1225. if ( DesiredType == TypeDomainController ) {
  1226. KnownType = TypeDomainController;
  1227. } else {
  1228. KnownType = TypePDC;
  1229. }
  1230. } else if ( FLAG_ON( SrvInfo->sv101_type, SV_TYPE_WORKSTATION ) ) {
  1231. KnownType = TypeWorkstation;
  1232. } else {
  1233. Win32Err = ERROR_UNSUPPORTED_TYPE;
  1234. }
  1235. } else {
  1236. LOG_VERBOSE(( MSG_VERBOSE_FAIL_MACH_TYPE, AccountName ));
  1237. ERROR_VERBOSE(( Win32Err ));
  1238. if ( DisplayOnError ) {
  1239. KnownType = DesiredType;
  1240. }
  1241. }
  1242. }
  1243. if ( KnownType == DesiredType && ( Win32Err == ERROR_SUCCESS || DisplayOnError ) ) {
  1244. if ( Win32Err != ERROR_SUCCESS ) {
  1245. NetDompDisplayMessage( MSG_WKSTA_OR_SERVER, AccountName );
  1246. Win32Err = ERROR_SUCCESS;
  1247. } else {
  1248. printf( "%ws\n", AccountName );
  1249. }
  1250. }
  1251. return( Win32Err );
  1252. }
  1253. DWORD
  1254. NetDompQueryMachines(
  1255. IN ND5_ACCOUNT_OPERATION Operation,
  1256. IN PWSTR Domain,
  1257. IN PND5_AUTH_INFO AuthInfo,
  1258. IN PWSTR pwzServer,
  1259. IN ND5_ACCOUNT_TYPE AccountType,
  1260. IN ULONG MessageId
  1261. )
  1262. /*++
  1263. Routine Description:
  1264. This function will list the machines in a domian
  1265. Arguments:
  1266. Operation - Whether to display/verify/reset the machines
  1267. Domain - Domain to connect to
  1268. AuthInfo - Username and password to connect to the domain with
  1269. pwzServer - Optional server name specified on command line, must be NULL for PDC operation.
  1270. AccountType - Type of accounts to display
  1271. MessageId - Resource ID of string to display
  1272. Return Value:
  1273. ERROR_SUCCESS - The function succeeded
  1274. --*/
  1275. {
  1276. DWORD Win32Err = ERROR_SUCCESS, Win32Err2;
  1277. PWSTR pwzUncServer = NULL, Lop, pwzUser = NULL, pwzDomain = NULL;
  1278. BOOL Connected = FALSE, fDsDcInfoAllocated = FALSE, fFreeServer = FALSE;
  1279. ULONG Type = 0;
  1280. PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
  1281. ULONG AccountTypeMap[] = {
  1282. FILTER_WORKSTATION_TRUST_ACCOUNT,
  1283. FILTER_WORKSTATION_TRUST_ACCOUNT,
  1284. FILTER_SERVER_TRUST_ACCOUNT,
  1285. FILTER_SERVER_TRUST_ACCOUNT,
  1286. FILTER_WORKSTATION_TRUST_ACCOUNT
  1287. };
  1288. LPUSER_INFO_0 UserList = NULL;
  1289. ULONG ResumeHandle = 0, Count = 0, TotalCount = 0, i;
  1290. ULONG DsGetDcOptions = DS_DIRECTORY_SERVICE_PREFERRED;
  1291. PDS_DOMAIN_CONTROLLER_INFO_1 pDsDcInfo;
  1292. if ( AccountType == TypeUnknown ) {
  1293. return( ERROR_INVALID_PARAMETER );
  1294. }
  1295. if (!pwzServer)
  1296. {
  1297. if ( AccountType == TypePDC ) {
  1298. DsGetDcOptions |= DS_PDC_REQUIRED;
  1299. }
  1300. LOG_VERBOSE(( MSG_VERBOSE_FIND_DC, Domain ));
  1301. Win32Err = DsGetDcName( NULL,
  1302. Domain,
  1303. NULL,
  1304. NULL,
  1305. DsGetDcOptions,
  1306. &DcInfo );
  1307. if (ERROR_SUCCESS != Win32Err)
  1308. {
  1309. return Win32Err;
  1310. }
  1311. if (AccountType == TypePDC)
  1312. {
  1313. NetDompDisplayMessage( MessageId );
  1314. NetDompDisplayMachineByType( DcInfo->DomainControllerName + 2,
  1315. AuthInfo,
  1316. TypePDC,
  1317. TypePDC,
  1318. TRUE );
  1319. goto QueryMachinesExit;
  1320. }
  1321. pwzUncServer = DcInfo->DomainControllerName;
  1322. }
  1323. else
  1324. {
  1325. // Server supplied on the command line. See if it has the needed backslashes.
  1326. //
  1327. if (L'\\' == *pwzServer)
  1328. {
  1329. if (wcslen(pwzServer) < 3 || L'\\' != pwzServer[1])
  1330. {
  1331. return ERROR_INVALID_PARAMETER;
  1332. }
  1333. pwzUncServer = pwzServer;
  1334. }
  1335. else
  1336. {
  1337. Win32Err = NetApiBufferAllocate((wcslen(pwzServer) + 3) * sizeof(WCHAR),
  1338. (PVOID*)&pwzUncServer);
  1339. if (ERROR_SUCCESS != Win32Err)
  1340. {
  1341. return Win32Err;
  1342. }
  1343. wsprintf(pwzUncServer, L"\\\\%s", pwzServer);
  1344. fFreeServer = TRUE;
  1345. }
  1346. }
  1347. LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, pwzUncServer ));
  1348. Win32Err = NetpManageIPCConnect( pwzUncServer,
  1349. AuthInfo->User,
  1350. AuthInfo->Password,
  1351. NETSETUPP_CONNECT_IPC );
  1352. if ( Win32Err == ERROR_SUCCESS ) {
  1353. Connected = TRUE;
  1354. }
  1355. else {
  1356. goto QueryMachinesExit;
  1357. }
  1358. NetDompDisplayMessage( MessageId );
  1359. //
  1360. // Now, do the enumeration
  1361. //
  1362. if (TypeDomainController == AccountType) {
  1363. HANDLE hDS;
  1364. RPC_AUTH_IDENTITY_HANDLE hID;
  1365. if (AuthInfo->User) {
  1366. pwzUser = wcschr(AuthInfo->User, L'\\');
  1367. if (pwzUser) {
  1368. //
  1369. // backslash found, replace with NULL and point to next char.
  1370. //
  1371. *pwzUser = UNICODE_NULL;
  1372. pwzUser++;
  1373. if (!*pwzUser) {
  1374. return ERROR_INVALID_PARAMETER;
  1375. }
  1376. pwzDomain = AuthInfo->User;
  1377. }
  1378. else {
  1379. pwzUser = AuthInfo->User;
  1380. pwzDomain = Domain;
  1381. }
  1382. }
  1383. Win32Err = DsMakePasswordCredentials( pwzUser,
  1384. pwzDomain,
  1385. AuthInfo->Password,
  1386. &hID);
  1387. if ( Win32Err != ERROR_SUCCESS ) {
  1388. goto QueryMachinesExit;
  1389. }
  1390. Win32Err = DsBindWithCred(pwzUncServer, NULL, hID, &hDS);
  1391. DsFreePasswordCredentials(hID);
  1392. if ( Win32Err == ERROR_SUCCESS ) {
  1393. Win32Err = DsGetDomainControllerInfo(hDS, Domain, 1, &Count, (PVOID*)&pDsDcInfo);
  1394. DsUnBind(&hDS);
  1395. if ( Win32Err != ERROR_SUCCESS ) {
  1396. goto QueryMachinesExit;
  1397. }
  1398. fDsDcInfoAllocated = TRUE;
  1399. for ( i = 0; i < Count; i++ ) {
  1400. switch ( Operation ) {
  1401. case OperationDisplay:
  1402. //
  1403. // Ignore errors from this function
  1404. //
  1405. NetDompDisplayMachineByType( pDsDcInfo[ i ].NetbiosName,
  1406. AuthInfo,
  1407. TypeDomainController,
  1408. TypeDomainController,
  1409. TRUE );
  1410. break;
  1411. case OperationVerify:
  1412. Win32Err2 = NetDompVerifyServerSC( Domain,
  1413. pDsDcInfo[ i ].NetbiosName,
  1414. AuthInfo,
  1415. MSG_QUERY_VERIFY_OK,
  1416. 0 );
  1417. if ( Win32Err2 != ERROR_SUCCESS ) {
  1418. NetDompDisplayMessageAndError( MSG_QUERY_VERIFY_BAD,
  1419. Win32Err2,
  1420. pDsDcInfo[ i ].NetbiosName );
  1421. }
  1422. break;
  1423. case OperationReset:
  1424. Win32Err2 = NetDompResetServerSC( Domain,
  1425. pDsDcInfo[ i ].NetbiosName,
  1426. NULL,
  1427. AuthInfo,
  1428. MSG_QUERY_VERIFY_OK,
  1429. 0 );
  1430. if ( Win32Err2 != ERROR_SUCCESS ) {
  1431. NetDompDisplayMessageAndError( MSG_QUERY_VERIFY_BAD,
  1432. Win32Err2,
  1433. pDsDcInfo[ i ].NetbiosName );
  1434. }
  1435. break;
  1436. default:
  1437. Win32Err2 = ERROR_INVALID_PARAMETER;
  1438. break;
  1439. }
  1440. }
  1441. goto QueryMachinesExit;
  1442. }
  1443. else {
  1444. // DsBind will return EPT_S_NOT_REGISTERED if a downlevel DC is targetted.
  1445. // If so, fall through to the NetUserEnum code.
  1446. //
  1447. if (EPT_S_NOT_REGISTERED != Win32Err) {
  1448. goto QueryMachinesExit;
  1449. }
  1450. }
  1451. }
  1452. do {
  1453. Win32Err = NetUserEnum( pwzUncServer,
  1454. 0,
  1455. AccountTypeMap[ AccountType ],
  1456. ( LPBYTE * )&UserList,
  1457. MAX_PREFERRED_LENGTH,
  1458. &Count,
  1459. &TotalCount,
  1460. &ResumeHandle );
  1461. if ( Win32Err == ERROR_SUCCESS || Win32Err == ERROR_MORE_DATA ) {
  1462. for ( i = 0; i < Count; i++ ) {
  1463. switch ( Operation ) {
  1464. case OperationDisplay:
  1465. //
  1466. // Ignore errors from this function
  1467. //
  1468. NetDompDisplayMachineByType( UserList[ i ].usri0_name,
  1469. AuthInfo,
  1470. AccountType,
  1471. TypeUnknown,
  1472. TRUE );
  1473. break;
  1474. case OperationVerify:
  1475. Lop = wcsrchr( UserList[ i ].usri0_name, L'$' );
  1476. if ( Lop ) {
  1477. *Lop = UNICODE_NULL;
  1478. }
  1479. Win32Err2 = NetDompVerifyServerSC( Domain,
  1480. UserList[ i ].usri0_name,
  1481. AuthInfo,
  1482. MSG_QUERY_VERIFY_OK,
  1483. 0 );
  1484. if ( Win32Err2 != ERROR_SUCCESS ) {
  1485. NetDompDisplayMessageAndError( MSG_QUERY_VERIFY_BAD,
  1486. Win32Err2,
  1487. UserList[ i ].usri0_name );
  1488. }
  1489. if ( Lop ) {
  1490. *Lop = L'$';
  1491. }
  1492. break;
  1493. case OperationReset:
  1494. Lop = wcsrchr( UserList[ i ].usri0_name, L'$' );
  1495. if ( Lop ) {
  1496. *Lop = UNICODE_NULL;
  1497. }
  1498. Win32Err2 = NetDompResetServerSC( Domain,
  1499. UserList[ i ].usri0_name,
  1500. NULL,
  1501. AuthInfo,
  1502. MSG_QUERY_VERIFY_OK,
  1503. 0 );
  1504. if ( Win32Err2 != ERROR_SUCCESS ) {
  1505. NetDompDisplayMessageAndError( MSG_QUERY_VERIFY_BAD,
  1506. Win32Err2,
  1507. UserList[ i ].usri0_name );
  1508. }
  1509. if ( Lop ) {
  1510. *Lop = L'$';
  1511. }
  1512. break;
  1513. default:
  1514. Win32Err2 = ERROR_INVALID_PARAMETER;
  1515. break;
  1516. }
  1517. }
  1518. NetApiBufferFree( UserList );
  1519. }
  1520. } while ( Win32Err == ERROR_MORE_DATA );
  1521. QueryMachinesExit:
  1522. if ( Connected ) {
  1523. LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, pwzUncServer ));
  1524. NetpManageIPCConnect( pwzUncServer,
  1525. NULL,
  1526. NULL,
  1527. NETSETUPP_DISCONNECT_IPC );
  1528. }
  1529. if (fFreeServer)
  1530. {
  1531. NetApiBufferFree(pwzUncServer);
  1532. }
  1533. if (fDsDcInfoAllocated)
  1534. {
  1535. DsFreeDomainControllerInfo(1, Count, pDsDcInfo);
  1536. }
  1537. if (DcInfo)
  1538. {
  1539. NetApiBufferFree(DcInfo);
  1540. }
  1541. return( Win32Err );
  1542. }
  1543. DWORD
  1544. NetDompHandleQuery(ARG_RECORD * rgNetDomArgs)
  1545. /*++
  1546. Routine Description:
  1547. This function will move a machine from one domain to another
  1548. Arguments:
  1549. Args - List of command line arguments
  1550. Return Value:
  1551. ERROR_INVALID_PARAMETER - No object name was supplied
  1552. --*/
  1553. {
  1554. DWORD Win32Err = ERROR_SUCCESS;
  1555. PWSTR Domain = NULL, Server = NULL;
  1556. ND5_AUTH_INFO DomainUser;
  1557. ND5_ACCOUNT_OPERATION Operation = OperationDisplay;
  1558. ULONG DisplayFlag = 0;
  1559. RtlZeroMemory( &DomainUser, sizeof( ND5_AUTH_INFO ) );
  1560. Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
  1561. eQueryPDC,
  1562. eQueryServer,
  1563. eQueryWksta,
  1564. eQueryDC,
  1565. eQueryOU,
  1566. eQueryFSMO,
  1567. eQueryTrust,
  1568. eCommDomain,
  1569. eCommUserNameD,
  1570. eCommPasswordD,
  1571. eCommServer,
  1572. eCommReset,
  1573. eQueryDirect,
  1574. eCommVerbose,
  1575. eCommVerify,
  1576. eArgEnd);
  1577. if ( Win32Err != ERROR_SUCCESS ) {
  1578. DisplayHelp(ePriQuery);
  1579. return Win32Err;
  1580. }
  1581. //
  1582. // Get the server name
  1583. //
  1584. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  1585. eCommServer,
  1586. &Server);
  1587. if ( Win32Err != ERROR_SUCCESS ) {
  1588. goto HandleQueryExit;
  1589. }
  1590. //
  1591. // Ok, make sure that we have a specified domain...
  1592. //
  1593. Win32Err = NetDompGetDomainForOperation(rgNetDomArgs,
  1594. Server,
  1595. TRUE,
  1596. &Domain);
  1597. if ( Win32Err != ERROR_SUCCESS ) {
  1598. goto HandleQueryExit;
  1599. }
  1600. //
  1601. // Get the password and user if it exists
  1602. //
  1603. if ( CmdFlagOn(rgNetDomArgs, eCommUserNameD) ) {
  1604. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  1605. eCommUserNameD,
  1606. Domain,
  1607. &DomainUser);
  1608. if ( Win32Err != ERROR_SUCCESS ) {
  1609. goto HandleQueryExit;
  1610. }
  1611. }
  1612. //
  1613. // Find the query sub command.
  1614. //
  1615. NETDOM_ARG_ENUM eQuery = eArgNull;
  1616. for (int i = eQueryBegin; i <= eQueryEnd; i++)
  1617. {
  1618. if (CmdFlagOn(rgNetDomArgs, static_cast<NETDOM_ARG_ENUM>(i)))
  1619. {
  1620. if (eArgNull != eQuery)
  1621. {
  1622. ASSERT(rgNetDomArgs[i].strArg1);
  1623. NetDompDisplayUnexpectedParameter(rgNetDomArgs[i].strArg1);
  1624. DisplayHelp(ePriQuery);
  1625. Win32Err = ERROR_INVALID_PARAMETER;
  1626. goto HandleQueryExit;
  1627. }
  1628. eQuery = static_cast<NETDOM_ARG_ENUM>(i);
  1629. }
  1630. }
  1631. if (eArgNull == eQuery)
  1632. {
  1633. DisplayHelp(ePriQuery);
  1634. Win32Err = ERROR_INVALID_PARAMETER;
  1635. goto HandleQueryExit;
  1636. }
  1637. if ( CmdFlagOn(rgNetDomArgs, eCommVerify) ) {
  1638. Operation = OperationVerify;
  1639. DisplayFlag = MSG_QUERY_VERIFY;
  1640. }
  1641. if ( CmdFlagOn(rgNetDomArgs, eCommReset) ) {
  1642. if ( Operation == OperationVerify ) {
  1643. Win32Err = ERROR_INVALID_PARAMETER;
  1644. goto HandleQueryExit;
  1645. } else {
  1646. Operation = OperationReset;
  1647. DisplayFlag = MSG_QUERY_RESET;
  1648. }
  1649. }
  1650. switch (eQuery)
  1651. {
  1652. case eQueryOU:
  1653. Win32Err = NetDompQueryDisplayOus( Domain,
  1654. &DomainUser );
  1655. break;
  1656. case eQueryWksta:
  1657. Win32Err = NetDompQueryMachines( Operation,
  1658. Domain,
  1659. &DomainUser,
  1660. Server,
  1661. TypeWorkstation,
  1662. DisplayFlag ? DisplayFlag : MSG_WORKSTATION_LIST );
  1663. break;
  1664. case eQueryServer:
  1665. Win32Err = NetDompQueryMachines( Operation,
  1666. Domain,
  1667. &DomainUser,
  1668. Server,
  1669. TypeServer,
  1670. DisplayFlag ? DisplayFlag : MSG_SERVER_LIST );
  1671. break;
  1672. case eQueryDC:
  1673. Win32Err = NetDompQueryMachines( Operation,
  1674. Domain,
  1675. &DomainUser,
  1676. Server,
  1677. TypeDomainController,
  1678. DisplayFlag ? DisplayFlag : MSG_DC_LIST );
  1679. break;
  1680. case eQueryPDC:
  1681. Win32Err = NetDompQueryMachines( Operation,
  1682. Domain,
  1683. &DomainUser,
  1684. NULL,
  1685. TypePDC,
  1686. MSG_PDC_LIST );
  1687. break;
  1688. case eQueryFSMO:
  1689. Win32Err = NetDompQueryFsmo( Domain,
  1690. &DomainUser );
  1691. break;
  1692. case eQueryTrust:
  1693. if (CmdFlagOn(rgNetDomArgs, eQueryDirect) &&
  1694. CmdFlagOn(rgNetDomArgs, eCommVerify))
  1695. {
  1696. DisplayHelp(ePriQuery);
  1697. Win32Err = ERROR_INVALID_PARAMETER;
  1698. goto HandleQueryExit;
  1699. }
  1700. Win32Err = NetDompQueryTrust( Domain,
  1701. &DomainUser,
  1702. Server,
  1703. CmdFlagOn(rgNetDomArgs, eQueryDirect),
  1704. CmdFlagOn(rgNetDomArgs, eCommVerify));
  1705. break;
  1706. default:
  1707. Win32Err = ERROR_INVALID_PARAMETER;
  1708. break;
  1709. }
  1710. HandleQueryExit:
  1711. NetApiBufferFree( Domain );
  1712. NetApiBufferFree( Server );
  1713. NetDompFreeAuthIdent( &DomainUser );
  1714. if (NO_ERROR != Win32Err)
  1715. {
  1716. NetDompDisplayErrorMessage(Win32Err);
  1717. }
  1718. return( Win32Err );
  1719. }