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

1142 lines
31 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. forest.c
  5. Abstract:
  6. Implementation of a variety of TrustedDomain features for supporting forests
  7. Author:
  8. Mac McLain (MacM) Feb 17, 1998
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include <lsapch2.h>
  14. #include <dbp.h>
  15. #include <lmcons.h>
  16. VOID
  17. LsapDsForestFreeTrustBlob(
  18. IN PLSAPDS_FOREST_TRUST_BLOB TrustBlob
  19. )
  20. /*++
  21. Routine Description:
  22. This function will free an individual trust blob. This blob is used in transition from
  23. reading the into from the DS and assembling the outgoing list
  24. Arguments:
  25. TrustBlob - Trust blob to free
  26. Returns:
  27. VOID
  28. --*/
  29. {
  30. LsapFreeLsaHeap( TrustBlob->DomainName.Buffer );
  31. LsapFreeLsaHeap( TrustBlob->FlatName.Buffer );
  32. LsapFreeLsaHeap( TrustBlob->DomainSid );
  33. }
  34. VOID
  35. LsapDsForestFreeTrustBlobList(
  36. IN PLIST_ENTRY TrustList
  37. )
  38. /*++
  39. Routine Description:
  40. This function will free a list of trust blobs
  41. Arguments:
  42. TrustList - Trust list to free
  43. Returns:
  44. VOID
  45. --*/
  46. {
  47. PLSAPDS_FOREST_TRUST_BLOB Current;
  48. PLIST_ENTRY ListEntry, NextEntry;
  49. ListEntry = TrustList->Flink;
  50. //
  51. // Process all of the entries
  52. //
  53. while ( ListEntry != TrustList ) {
  54. Current = CONTAINING_RECORD( ListEntry,
  55. LSAPDS_FOREST_TRUST_BLOB,
  56. Next );
  57. NextEntry = ListEntry->Flink;
  58. RemoveEntryList( ListEntry );
  59. LsapDsForestFreeTrustBlob( Current );
  60. LsapFreeLsaHeap( Current );
  61. ListEntry = NextEntry;
  62. }
  63. }
  64. NTSTATUS
  65. LsapDsForestBuildTrustEntryForAttrBlock(
  66. IN PUNICODE_STRING EnterpriseDnsName,
  67. IN ATTRBLOCK *AttrBlock,
  68. OUT PLSAPDS_FOREST_TRUST_BLOB *TrustInfo
  69. )
  70. /*++
  71. Routine Description:
  72. This function will take the contents of a single ATTRBLOCK returned via the search
  73. info a trust blob. This blob is then used to create the trust tree.
  74. The initialize trust blob should be freed with LsapDsForestFreeTrustBlob
  75. Arguments:
  76. EnterpriseDnsName - Dns domain name of the root of the enterprise. This is what
  77. denotes the trust root
  78. AttrBlock - ATTRBLOCK to return
  79. TrustInfo - Trust info to initialize
  80. Returns:
  81. STATUS_SUCCESS - Success
  82. STATUS_INVALID_PARAMETER - An invalid attribute id was encountered
  83. STATUS_INSUFFICIENT_MEMORY - A memory allocation failed
  84. --*/
  85. {
  86. NTSTATUS Status = STATUS_SUCCESS;
  87. ULONG i, j;
  88. PDSNAME DsName;
  89. PLSAPDS_FOREST_TRUST_BLOB TrustBlob;
  90. TrustBlob = ( PLSAPDS_FOREST_TRUST_BLOB )LsapAllocateLsaHeap(
  91. sizeof( LSAPDS_FOREST_TRUST_BLOB ) );
  92. if ( TrustBlob == NULL ) {
  93. return( STATUS_INSUFFICIENT_RESOURCES );
  94. }
  95. RtlZeroMemory( TrustBlob, sizeof( LSAPDS_FOREST_TRUST_BLOB ) );
  96. for ( i = 0; i < AttrBlock->attrCount && NT_SUCCESS( Status ); i++ ) {
  97. //
  98. // Initialize this so we can tell later on whether or not we have any root trusts or
  99. // a parent
  100. //
  101. DsName = NULL;
  102. switch ( AttrBlock->pAttr[ i ].attrTyp ) {
  103. case ATT_ROOT_TRUST:
  104. TrustBlob->TreeRoot = TRUE;
  105. break;
  106. case ATT_TRUST_PARENT:
  107. DsName = ( PDSNAME )AttrBlock->pAttr[i].AttrVal.pAVal->pVal;
  108. LSAPDS_COPY_GUID_ON_SUCCESS( Status,
  109. &TrustBlob->Parent,
  110. &DsName->Guid );
  111. TrustBlob->ParentTrust = TRUE;
  112. break;
  113. case ATT_OBJECT_GUID:
  114. LSAPDS_COPY_GUID_ON_SUCCESS(
  115. Status,
  116. &TrustBlob->ObjectGuid,
  117. AttrBlock->pAttr[i].AttrVal.pAVal->pVal );
  118. break;
  119. case ATT_DNS_ROOT:
  120. LSAPDS_ALLOC_AND_COPY_STRING_TO_UNICODE_ON_SUCCESS(
  121. Status,
  122. &TrustBlob->DomainName,
  123. AttrBlock->pAttr[i].AttrVal.pAVal->pVal,
  124. AttrBlock->pAttr[i].AttrVal.pAVal->valLen );
  125. break;
  126. case ATT_NETBIOS_NAME:
  127. LSAPDS_ALLOC_AND_COPY_STRING_TO_UNICODE_ON_SUCCESS(
  128. Status,
  129. &TrustBlob->FlatName,
  130. AttrBlock->pAttr[i].AttrVal.pAVal->pVal,
  131. AttrBlock->pAttr[i].AttrVal.pAVal->valLen );
  132. break;
  133. case ATT_NC_NAME:
  134. DsName = ( PDSNAME )AttrBlock->pAttr[i].AttrVal.pAVal->pVal;
  135. if ( DsName->SidLen > 0 ) {
  136. LSAPDS_ALLOC_AND_COPY_SID_ON_SUCCESS( Status,
  137. TrustBlob->DomainSid,
  138. &( DsName->Sid ) );
  139. }
  140. RtlCopyMemory( &TrustBlob->DomainGuid,
  141. &DsName->Guid,
  142. sizeof( GUID ) );
  143. TrustBlob->DomainGuidSet = TRUE;
  144. break;
  145. default:
  146. Status = STATUS_INVALID_PARAMETER;
  147. LsapDsDebugOut(( DEB_ERROR,
  148. "LsapDsForestBuildTrustEntryForAttrBlock: Invalid attribute type %lu\n",
  149. AttrBlock->pAttr[ i ].attrTyp ));
  150. break;
  151. }
  152. }
  153. //
  154. // If we think we have a root object, we'll need to verify it.
  155. //
  156. if ( NT_SUCCESS( Status )) {
  157. if ( RtlEqualUnicodeString( EnterpriseDnsName, &TrustBlob->DomainName, TRUE ) ) {
  158. // The root should not be a child of anything
  159. ASSERT(!TrustBlob->ParentTrust);
  160. TrustBlob->ForestRoot = TRUE;
  161. TrustBlob->TreeRoot = FALSE;
  162. }
  163. }
  164. //
  165. // If something failed, clean up
  166. //
  167. if ( NT_SUCCESS( Status ) ) {
  168. *TrustInfo = TrustBlob;
  169. } else {
  170. LsapDsForestFreeTrustBlob( TrustBlob );
  171. LsapFreeLsaHeap( TrustBlob );
  172. }
  173. return( Status );
  174. }
  175. NTSTATUS
  176. LsapDsForestSearchXRefs(
  177. IN PUNICODE_STRING EnterpriseDnsName,
  178. IN PLIST_ENTRY TrustList,
  179. OUT PAGED_RESULT **ContinuationBlob
  180. )
  181. /*++
  182. Routine Description:
  183. This function will perform a single paged search for domain cross ref objects. The
  184. information returned from this single search is returned in a copied list of trust blobs.
  185. This is necessary to prevent performing multiple searches on the same thread state, thereby
  186. potentially consuming large quantities of memory. A thread state is created and destroyed
  187. for each iteration.
  188. Arguments:
  189. EnterpriseDnsName - Dns domain name of the enterprise
  190. TrustList - Points to the head of a list where the trust blobs will be returned.
  191. The trust blob representing the root of the forest is returned at the head of this list. The remaining entries are unordered.
  192. ContinuationBlob - This is the PAGED_RESULTS continuation blob passed to the search
  193. for multiple passes
  194. Returns:
  195. STATUS_SUCCESS - Success
  196. STATUS_INVALID_PARAMETER - An invalid attribute id was encountered
  197. STATUS_INSUFFICIENT_MEMORY - A memory allocation failed
  198. STATUS_NO_MORE_ENTRIES - All of the entries have been returned.
  199. --*/
  200. {
  201. NTSTATUS Status = STATUS_SUCCESS;
  202. SEARCHARG SearchArg;
  203. FILTER Filters[ 2 ], RootFilter;
  204. ENTINFSEL EntInfSel;
  205. ENTINFLIST *EntInfList;
  206. ULONG ClassId, FlagValue, i;
  207. SEARCHRES *SearchRes = NULL;
  208. PLSAPDS_FOREST_TRUST_BLOB TrustBlob;
  209. BOOLEAN CloseTransaction = FALSE;
  210. LsapDsDebugOut(( DEB_FTRACE, "LsapDsForestSearchXRefs\n" ));
  211. RtlZeroMemory( &SearchArg, sizeof( SEARCHARG ) );
  212. //
  213. // See if we already have a transaction going
  214. //
  215. // If one already exists, we'll use the existing transaction and not
  216. // delete the thread state at the end.
  217. //
  218. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  219. LSAP_DB_DS_OP_TRANSACTION,
  220. NullObject,
  221. &CloseTransaction );
  222. if ( NT_SUCCESS( Status ) ) {
  223. //
  224. // Build the filter. The thing to search on is the flag and the class id.
  225. //
  226. ClassId = CLASS_CROSS_REF;
  227. FlagValue = (FLAG_CR_NTDS_NC | FLAG_CR_NTDS_DOMAIN);
  228. RtlZeroMemory( Filters, sizeof (Filters) );
  229. RtlZeroMemory( &RootFilter, sizeof (RootFilter) );
  230. Filters[ 0 ].pNextFilter = &Filters[ 1 ];
  231. Filters[ 0 ].choice = FILTER_CHOICE_ITEM;
  232. Filters[ 0 ].FilterTypes.Item.choice = FI_CHOICE_EQUALITY;
  233. Filters[ 0 ].FilterTypes.Item.FilTypes.ava.type = ATT_OBJECT_CLASS;
  234. Filters[ 0 ].FilterTypes.Item.FilTypes.ava.Value.valLen = sizeof( ULONG );
  235. Filters[ 0 ].FilterTypes.Item.FilTypes.ava.Value.pVal = ( PUCHAR )&ClassId;
  236. Filters[ 1 ].pNextFilter = NULL;
  237. Filters[ 1 ].choice = FILTER_CHOICE_ITEM;
  238. Filters[ 1 ].FilterTypes.Item.choice = FI_CHOICE_BIT_AND;
  239. Filters[ 1 ].FilterTypes.Item.FilTypes.ava.type = ATT_SYSTEM_FLAGS;
  240. Filters[ 1 ].FilterTypes.Item.FilTypes.ava.Value.valLen = sizeof( ULONG );
  241. Filters[ 1 ].FilterTypes.Item.FilTypes.ava.Value.pVal = ( PUCHAR )&FlagValue;
  242. RootFilter.choice = FILTER_CHOICE_AND;
  243. RootFilter.FilterTypes.And.count = ( USHORT )( sizeof( Filters ) / sizeof( FILTER ) );
  244. RootFilter.FilterTypes.And.pFirstFilter = Filters;
  245. SearchArg.pObject = LsaDsStateInfo.DsPartitionsContainer;
  246. SearchArg.choice = SE_CHOICE_IMMED_CHLDRN;
  247. SearchArg.bOneNC = TRUE;
  248. SearchArg.pFilter = &RootFilter;
  249. SearchArg.searchAliases = FALSE;
  250. SearchArg.pSelection = &EntInfSel;
  251. //
  252. // Build the list of attributes to return
  253. //
  254. EntInfSel.attSel = EN_ATTSET_LIST;
  255. EntInfSel.AttrTypBlock.attrCount = LsapDsForestInfoSearchAttributeCount;
  256. EntInfSel.AttrTypBlock.pAttr = LsapDsForestInfoSearchAttributes;
  257. EntInfSel.infoTypes = EN_INFOTYPES_TYPES_VALS;
  258. //
  259. // Build the Commarg structure
  260. //
  261. LsapDsInitializeStdCommArg( &( SearchArg.CommArg ), 0 );
  262. if ( *ContinuationBlob ) {
  263. RtlCopyMemory( &SearchArg.CommArg.PagedResult,
  264. *ContinuationBlob,
  265. sizeof( PAGED_RESULT ) );
  266. } else {
  267. SearchArg.CommArg.PagedResult.fPresent = TRUE;
  268. }
  269. SearchArg.CommArg.ulSizeLimit = LSAPDS_FOREST_MAX_SEARCH_ITEMS;
  270. LsapDsSetDsaFlags( TRUE );
  271. //
  272. // Do the search
  273. //
  274. DirSearch( &SearchArg, &SearchRes );
  275. LsapDsContinueTransaction();
  276. if ( SearchRes ) {
  277. Status = LsapDsMapDsReturnToStatusEx( &SearchRes->CommRes );
  278. } else {
  279. Status = STATUS_INSUFFICIENT_RESOURCES;
  280. }
  281. //
  282. // Save off the continuation blob
  283. //
  284. if ( NT_SUCCESS( Status ) ) {
  285. if ( *ContinuationBlob ) {
  286. LsapFreeLsaHeap( *ContinuationBlob );
  287. *ContinuationBlob = NULL;
  288. }
  289. if ( SearchRes->PagedResult.fPresent ) {
  290. *ContinuationBlob = LsapAllocateLsaHeap(
  291. sizeof( PAGED_RESULT ) +
  292. SearchRes->PagedResult.pRestart->structLen +
  293. sizeof( RESTART ) );
  294. if ( *ContinuationBlob == NULL ) {
  295. Status = STATUS_INSUFFICIENT_RESOURCES;
  296. } else {
  297. ( *ContinuationBlob )->fPresent = SearchRes->PagedResult.fPresent;
  298. ( *ContinuationBlob )->pRestart = ( PRESTART ) ( ( PBYTE )*ContinuationBlob +
  299. sizeof( PAGED_RESULT ) );
  300. RtlCopyMemory( ( *ContinuationBlob )->pRestart,
  301. SearchRes->PagedResult.pRestart,
  302. SearchRes->PagedResult.pRestart->structLen );
  303. }
  304. }
  305. }
  306. //
  307. // Now, save off all of the information returned from the search
  308. //
  309. if ( NT_SUCCESS( Status ) ) {
  310. EntInfList = &SearchRes->FirstEntInf;
  311. for ( i = 0; i < SearchRes->count && NT_SUCCESS( Status ); i++) {
  312. Status = LsapDsForestBuildTrustEntryForAttrBlock(
  313. EnterpriseDnsName,
  314. &EntInfList->Entinf.AttrBlock,
  315. &TrustBlob );
  316. EntInfList = EntInfList->pNextEntInf;
  317. if ( NT_SUCCESS( Status ) ) {
  318. if ( TrustBlob->ForestRoot ) {
  319. InsertHeadList( TrustList,
  320. &TrustBlob->Next );
  321. } else if ((TrustBlob->ParentTrust )
  322. || (TrustBlob->TreeRoot)) {
  323. InsertTailList( TrustList,
  324. &TrustBlob->Next );
  325. }
  326. else
  327. {
  328. //
  329. // Simply do not return the entry. This
  330. // occurs sometimes at install time when all
  331. // the information has not yet replicated out
  332. //
  333. LsapDsForestFreeTrustBlob( TrustBlob );
  334. LsapFreeLsaHeap( TrustBlob );
  335. }
  336. }
  337. }
  338. }
  339. //
  340. // See if we should indicate that there are no more entries
  341. //
  342. if ( NT_SUCCESS( Status ) &&
  343. ( SearchRes->count == 0 || !SearchRes->PagedResult.fPresent ) ) {
  344. Status = STATUS_NO_MORE_ENTRIES;
  345. }
  346. //
  347. // By destroying the thread state, the allocated memory is freed as well. This is
  348. // required to keep the heap from becoming bloated
  349. //
  350. LsapDsDeleteAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  351. LSAP_DB_DS_OP_TRANSACTION,
  352. NullObject,
  353. CloseTransaction );
  354. }
  355. LsapDsDebugOut(( DEB_FTRACE, "LsapDsForestSearchXRefs: 0x%lx\n", Status ));
  356. return( Status );
  357. }
  358. VOID
  359. LsapDsForestFreeChild(
  360. IN PLSAPR_TREE_TRUST_INFO ChildNode
  361. )
  362. /*++
  363. Routine Description:
  364. Free all buffers pointed to by a Tree Trust Info structure.
  365. Arguments:
  366. ForestTrustInfo - Info to be deleted
  367. Returns:
  368. VOID
  369. --*/
  370. {
  371. ULONG i;
  372. for ( i = 0; i < ChildNode->Children; i++ ) {
  373. LsapDsForestFreeChild( &ChildNode->ChildDomains[ i ] );
  374. }
  375. LsapFreeLsaHeap( ChildNode->ChildDomains );
  376. LsapFreeLsaHeap( ChildNode->DnsDomainName.Buffer );
  377. LsapFreeLsaHeap( ChildNode->FlatName.Buffer );
  378. LsapFreeLsaHeap( ChildNode->DomainSid );
  379. }
  380. VOID
  381. LsaIFreeForestTrustInfo(
  382. IN PLSAPR_FOREST_TRUST_INFO ForestTrustInfo
  383. )
  384. /*++
  385. Routine Description:
  386. This function will free the information obtained via a LsaIQueryForestTrustInfo call
  387. Arguments:
  388. ForestTrustInfo - Info to be deleted
  389. Returns:
  390. VOID
  391. --*/
  392. {
  393. ULONG i, j;
  394. LsapDsDebugOut(( DEB_FTRACE, "LsaIFreeForestTrustInfo\n" ));
  395. if ( ForestTrustInfo == NULL ) {
  396. return;
  397. }
  398. //
  399. // Free all the information in the structure...
  400. //
  401. LsapDsForestFreeChild( &ForestTrustInfo->RootTrust );
  402. //
  403. // Then free the structure itself.
  404. //
  405. LsapFreeLsaHeap( ForestTrustInfo );
  406. LsapDsDebugOut(( DEB_FTRACE, "LsaIFreeForestTrustInfo returned\n" ));
  407. return;
  408. }
  409. NTSTATUS
  410. LsapBuildForestTrustInfoLists(
  411. IN LSAPR_HANDLE PolicyHandle OPTIONAL,
  412. IN PLIST_ENTRY TrustList
  413. )
  414. /*++
  415. Routine Description:
  416. This function returns a linked list of all the cross ref objects on the system.
  417. Arguments:
  418. PolicyHandle - Handle to use for the operation.
  419. If NULL, LsapPolicyHandle will be used.
  420. TrustList - Points to the head of a list where the trust blobs will be returned.
  421. The trust blob representing the root of the forest is returned at the head of this list. The remaining entries are unordered.
  422. Returns:
  423. Misc status codes.
  424. --*/
  425. {
  426. NTSTATUS Status = STATUS_SUCCESS;
  427. PAGED_RESULT *ContinuationBlob = NULL;
  428. PPOLICY_DNS_DOMAIN_INFO PolicyDnsDomainInfo = NULL;
  429. LsapDsDebugOut(( DEB_FTRACE, "LsapBuildForestTrustInfoLists\n" ));
  430. //
  431. // Make sure the DS is installed
  432. //
  433. if ( LsaDsStateInfo.DsPartitionsContainer == NULL ) {
  434. return( STATUS_INVALID_DOMAIN_STATE );
  435. }
  436. //
  437. // Get the current Dns domain information
  438. //
  439. Status = LsapDbQueryInformationPolicy( PolicyHandle ? PolicyHandle : LsapPolicyHandle,
  440. PolicyDnsDomainInformation,
  441. ( PLSAPR_POLICY_INFORMATION * )&PolicyDnsDomainInfo );
  442. if ( NT_SUCCESS( Status ) ) {
  443. //
  444. // A DS transaction is not required, nor is a lock to be held for this routine
  445. //
  446. //
  447. // Build the list of all the trust objects
  448. //
  449. while ( NT_SUCCESS( Status ) ) {
  450. Status = LsapDsForestSearchXRefs( ( PUNICODE_STRING )&PolicyDnsDomainInfo->DnsForestName,
  451. TrustList,
  452. &ContinuationBlob );
  453. if ( Status == STATUS_NO_MORE_ENTRIES ) {
  454. Status = STATUS_SUCCESS;
  455. break;
  456. }
  457. }
  458. if ( Status == STATUS_NO_MORE_ENTRIES ) {
  459. Status = STATUS_SUCCESS;
  460. }
  461. LsaIFree_LSAPR_POLICY_INFORMATION( PolicyDnsDomainInformation,
  462. ( PLSAPR_POLICY_INFORMATION )PolicyDnsDomainInfo );
  463. }
  464. LsapExitFunc( "LsapBuildForestTrustInfoLists", Status );
  465. return( Status );
  466. }
  467. NTSTATUS
  468. LsapDsForestProcessTrustBlob(
  469. IN PLSAPDS_FOREST_TRUST_BLOB ParentTrustBlob,
  470. OUT PLSAPR_TREE_TRUST_INFO ParentNode,
  471. IN PLIST_ENTRY TrustList,
  472. IN PLIST_ENTRY UsedList,
  473. IN PUNICODE_STRING CurrentDnsDomainName,
  474. IN OUT PLSAPR_TREE_TRUST_INFO *ParentReference
  475. )
  476. /*++
  477. Routine Description:
  478. This routine fills in the trust info for all the children of a particular cross ref object.
  479. Arguments:
  480. ParentTrustBlob - Specifies the TrustBlob representing a parent cross ref object
  481. ParentTrustBlob is expected to be on TrustList. Upon return, it will be on UsedList.
  482. ParentNode - Specifies the node to be filled in with the information from ParentTrustBlob.
  483. The Children are filled in, too.
  484. This buffer should be free by calling LsapDsForestFreeChild.
  485. TrustList - Pointer to the head of a linked list of all (remaining) cross ref objects.
  486. UsedList - Pointer to the head of a linked list of all cross ref object that have already been
  487. processed.
  488. Entries in the UsedList have several fields cleared as the pointed to memory is copied to ParentNode.
  489. CurrentDnsDomainName - Dns domain name of the domain this code is running on
  490. ParentReference - Returns the address of the structure that is the parent of
  491. CurrentDnsDomainName
  492. This reference should not be freed. It is simply a pointer to one of the entries returned
  493. in ParentNode.
  494. Returns:
  495. STATUS_SUCCESS - Success
  496. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  497. --*/
  498. {
  499. NTSTATUS Status;
  500. LIST_ENTRY ChildList;
  501. ULONG i, Children = 0;
  502. PLIST_ENTRY NextEntry, ChildEntry;
  503. PLSAPDS_FOREST_TRUST_BLOB Current;
  504. LsapDsDebugOut(( DEB_FTRACE, "LsapDsForestFindChildrenForChildren\n" ));
  505. //
  506. // Initialization.
  507. //
  508. InitializeListHead( &ChildList );
  509. //
  510. // Fill in the ParentNode
  511. //
  512. // Clear it so the caller has a clean deallocation model
  513. RtlZeroMemory( ParentNode, sizeof(*ParentNode) );
  514. // Just copy the pointer to save memory allocation
  515. ParentNode->DnsDomainName = ParentTrustBlob->DomainName;
  516. ParentTrustBlob->DomainName.Buffer = NULL;
  517. ParentNode->FlatName = ParentTrustBlob->FlatName;
  518. ParentTrustBlob->FlatName.Buffer = NULL;
  519. if ( ParentTrustBlob->TreeRoot || ParentTrustBlob->ForestRoot ) {
  520. ParentNode->Flags |= LSAI_FOREST_ROOT_TRUST;
  521. }
  522. if ( ParentTrustBlob->DomainGuidSet ) {
  523. ParentNode->DomainGuid = ParentTrustBlob->DomainGuid;
  524. ParentNode->Flags |= LSAI_FOREST_DOMAIN_GUID_PRESENT;
  525. }
  526. ParentNode->DomainSid = ParentTrustBlob->DomainSid;
  527. ParentTrustBlob->DomainSid = NULL;
  528. //
  529. // Move this entry to the UsedList to prevent us from stumbling across this entry again
  530. //
  531. RemoveEntryList( &ParentTrustBlob->Next );
  532. InsertTailList( UsedList, &ParentTrustBlob->Next );
  533. //
  534. // Build a list of children of this parent
  535. //
  536. NextEntry = TrustList->Flink;
  537. while ( NextEntry != TrustList ) {
  538. Current = CONTAINING_RECORD( NextEntry,
  539. LSAPDS_FOREST_TRUST_BLOB,
  540. Next );
  541. ChildEntry = NextEntry;
  542. NextEntry = NextEntry->Flink;
  543. //
  544. // All nodes that think we are their parent are our children.
  545. // Plus all tree roots are the children of the forest root.
  546. //
  547. if ( RtlCompareMemory( &ParentTrustBlob->ObjectGuid,
  548. &Current->Parent,
  549. sizeof( GUID ) ) == sizeof( GUID ) ||
  550. ( ParentTrustBlob->ForestRoot && Current->TreeRoot ) ) {
  551. Children++;
  552. RemoveEntryList( ChildEntry );
  553. InsertTailList( &ChildList,
  554. ChildEntry );
  555. }
  556. }
  557. //
  558. // Handle the children
  559. //
  560. if ( Children != 0 ) {
  561. //
  562. // Allocate an array large enough for the children
  563. //
  564. ParentNode->ChildDomains = ( PLSAPR_TREE_TRUST_INFO )LsapAllocateLsaHeap(
  565. Children * sizeof( LSAPR_TREE_TRUST_INFO ) );
  566. if ( ParentNode->ChildDomains == NULL ) {
  567. Status = STATUS_INSUFFICIENT_RESOURCES;
  568. goto Cleanup;
  569. }
  570. ParentNode->Children = Children;
  571. RtlZeroMemory( ParentNode->ChildDomains,
  572. Children * sizeof( LSAPR_TREE_TRUST_INFO ) );
  573. //
  574. // Process each child
  575. //
  576. ChildEntry = ChildList.Flink;
  577. for ( i = 0; i < Children; i++ ) {
  578. Current = CONTAINING_RECORD( ChildEntry,
  579. LSAPDS_FOREST_TRUST_BLOB,
  580. Next );
  581. ChildEntry = ChildEntry->Flink;
  582. //
  583. // If the child we're currently processing is for the domain we're running on,
  584. // then the ParentNode is that of the parent of this domain.
  585. //
  586. if ( !*ParentReference &&
  587. RtlEqualUnicodeString( &Current->DomainName,
  588. CurrentDnsDomainName,
  589. TRUE ) ) {
  590. *ParentReference = ParentNode;
  591. }
  592. //
  593. // Process the node
  594. //
  595. Status = LsapDsForestProcessTrustBlob(
  596. Current, // Trust blob to process
  597. &ParentNode->ChildDomains[ i ], // Slot for it
  598. TrustList,
  599. UsedList,
  600. CurrentDnsDomainName,
  601. ParentReference );
  602. if ( !NT_SUCCESS(Status) ) {
  603. goto Cleanup;
  604. }
  605. }
  606. }
  607. Status = STATUS_SUCCESS;
  608. Cleanup:
  609. //
  610. // Put any dangling child entries onto the used list
  611. //
  612. while ( ChildList.Flink != &ChildList ) {
  613. ChildEntry = ChildList.Flink;
  614. RemoveEntryList( ChildEntry );
  615. InsertTailList( UsedList, ChildEntry );
  616. }
  617. LsapDsDebugOut(( DEB_FTRACE, "LsapDsForestFindChildrenForChildren returned 0x%lx\n", Status ));
  618. return( Status );
  619. }
  620. NTSTATUS
  621. LsapDsBuildForestTrustInfo(
  622. OUT PLSAPR_FOREST_TRUST_INFO ForestTrustInfo,
  623. IN PLIST_ENTRY TrustList,
  624. IN PUNICODE_STRING CurrentDnsDomainName
  625. )
  626. /*++
  627. Routine Description:
  628. Convert the TrustList linear list of cross ref objects into a tree shape.
  629. Arguments:
  630. ForestTrustInfo -
  631. Returns:
  632. STATUS_SUCCESS - Success
  633. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  634. --*/
  635. {
  636. NTSTATUS Status;
  637. PLSAPDS_FOREST_TRUST_BLOB Current;
  638. LIST_ENTRY UsedList;
  639. LsapDsDebugOut(( DEB_FTRACE, "LsapDsForestBuildRootTrusts\n" ));
  640. //
  641. // Initialization
  642. //
  643. RtlZeroMemory( ForestTrustInfo, sizeof(*ForestTrustInfo) );
  644. InitializeListHead( &UsedList );
  645. //
  646. // There must be at least one entry
  647. //
  648. if ( TrustList->Flink == TrustList ) {
  649. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  650. goto Cleanup;
  651. }
  652. //
  653. // The first entry on the list is the root of the tree.
  654. //
  655. Current = CONTAINING_RECORD( TrustList->Flink,
  656. LSAPDS_FOREST_TRUST_BLOB,
  657. Next );
  658. //
  659. // Process the entry
  660. //
  661. Status = LsapDsForestProcessTrustBlob(
  662. Current,
  663. &ForestTrustInfo->RootTrust,
  664. TrustList,
  665. &UsedList,
  666. CurrentDnsDomainName,
  667. &ForestTrustInfo->ParentDomainReference );
  668. if ( !NT_SUCCESS(Status) ) {
  669. goto Cleanup;
  670. }
  671. // In theory, Trust list should be empty now
  672. Cleanup:
  673. //
  674. // Merge the used list onto the front of the TrustList
  675. //
  676. if ( !IsListEmpty( &UsedList ) ) {
  677. PLIST_ENTRY TrustFront;
  678. TrustFront = TrustList->Flink;
  679. // Link head of used list onto head of trust list
  680. TrustList->Flink = UsedList.Flink;
  681. UsedList.Flink->Blink = TrustList;
  682. // List previous head of trustlist onto tail of root list
  683. UsedList.Blink->Flink = TrustFront;
  684. TrustFront->Blink = UsedList.Blink;
  685. InitializeListHead( &UsedList );
  686. }
  687. LsapDsDebugOut(( DEB_FTRACE, "LsapDsForestBuildRootTrusts returned 0x%lx\n", Status ));
  688. return( Status );
  689. }
  690. NTSTATUS
  691. NTAPI
  692. LsaIQueryForestTrustInfo(
  693. IN LSAPR_HANDLE PolicyHandle,
  694. OUT PLSAPR_FOREST_TRUST_INFO *ForestTrustInfo
  695. )
  696. /*++
  697. Routine Description:
  698. Will enumerate all of the domains in an organization and return them as
  699. a list.
  700. Arguments:
  701. PolicyHandle - Handle from an LsaOpenPolicy call.
  702. ForestTrustInfo - Where the computed trust info tree is returned. Must be freed with
  703. LsaIFreeForestTrustInfo
  704. Returns:
  705. STATUS_SUCCESS - Success
  706. STATUS_INVALID_DOMAIN_STATE - The Ds is not installed or running at the time of the call
  707. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  708. --*/
  709. {
  710. NTSTATUS Status = STATUS_SUCCESS;
  711. LIST_ENTRY TrustList;
  712. PAGED_RESULT *ContinuationBlob = NULL;
  713. PPOLICY_DNS_DOMAIN_INFO PolicyDnsDomainInfo = NULL;
  714. LsapDsDebugOut(( DEB_FTRACE, "LsaIQueryForestTrustInfo\n" ));
  715. *ForestTrustInfo = NULL;
  716. //
  717. // Make sure the DS is installed
  718. //
  719. if ( LsaDsStateInfo.DsPartitionsContainer == NULL ) {
  720. return( STATUS_INVALID_DOMAIN_STATE );
  721. }
  722. InitializeListHead( &TrustList );
  723. //
  724. // Get the current Dns domain information
  725. //
  726. Status = LsapDbQueryInformationPolicy(
  727. LsapPolicyHandle,
  728. PolicyDnsDomainInformation,
  729. ( PLSAPR_POLICY_INFORMATION * )&PolicyDnsDomainInfo );
  730. if ( NT_SUCCESS( Status ) ) {
  731. //
  732. // A DS transaction is not required, nor is a lock to be held for this routine
  733. //
  734. //
  735. // Build the list of all the trust objects
  736. //
  737. while ( NT_SUCCESS( Status ) ) {
  738. Status = LsapDsForestSearchXRefs( ( PUNICODE_STRING )&PolicyDnsDomainInfo->DnsForestName,
  739. &TrustList,
  740. &ContinuationBlob );
  741. if ( Status == STATUS_NO_MORE_ENTRIES ) {
  742. Status = STATUS_SUCCESS;
  743. break;
  744. }
  745. }
  746. //
  747. // Now, if we have all of the trusts, build the enterprise info
  748. //
  749. if ( NT_SUCCESS( Status ) ) {
  750. *ForestTrustInfo = ( PLSAPR_FOREST_TRUST_INFO )LsapAllocateLsaHeap(
  751. sizeof( LSAPR_FOREST_TRUST_INFO ) );
  752. if ( *ForestTrustInfo == NULL ) {
  753. Status = STATUS_INSUFFICIENT_RESOURCES;
  754. } else {
  755. RtlZeroMemory( *ForestTrustInfo, sizeof( LSAPR_FOREST_TRUST_INFO ) );
  756. //
  757. // Fill in the ForestTrustInfo.
  758. //
  759. Status = LsapDsBuildForestTrustInfo( *ForestTrustInfo,
  760. &TrustList,
  761. &PolicyDnsDomainInfo->DnsDomainName );
  762. }
  763. }
  764. LsaIFree_LSAPR_POLICY_INFORMATION( PolicyDnsDomainInformation,
  765. ( PLSAPR_POLICY_INFORMATION )PolicyDnsDomainInfo );
  766. }
  767. //
  768. // Delete the trust lists
  769. //
  770. LsapDsForestFreeTrustBlobList( &TrustList );
  771. if ( ContinuationBlob != NULL ) {
  772. LsapFreeLsaHeap( ContinuationBlob );
  773. }
  774. if (!NT_SUCCESS(Status))
  775. {
  776. //
  777. // Cleanup on Failure
  778. //
  779. if (NULL!=(*ForestTrustInfo))
  780. {
  781. LsaIFreeForestTrustInfo(*ForestTrustInfo);
  782. *ForestTrustInfo = NULL;
  783. }
  784. }
  785. LsapDsDebugOut(( DEB_FTRACE, "LsaIQueryForestTrustInfo returned 0x%lx\n", Status ));
  786. return( Status );
  787. }