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.

2117 lines
55 KiB

  1. /*++
  2. Copyright (c) 1987-2001 Microsoft Corporation
  3. Module Name:
  4. ftnfoctx.c
  5. Abstract:
  6. Utility routines to manipulate the forest trust context
  7. Author:
  8. 27-Jul-00 (cliffv)
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. --*/
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <netdebug.h>
  19. #include <ntlsa.h>
  20. #include <ftnfoctx.h>
  21. #include <align.h> // ROUND_UP_POINTER
  22. #include <rpcutil.h> // MIDL_user_free
  23. #include <stdlib.h> // qsort
  24. VOID
  25. NetpInitFtinfoContext(
  26. OUT PNL_FTINFO_CONTEXT FtinfoContext
  27. )
  28. /*++
  29. Routine Description:
  30. Routine to initialize the Ftinfo context structure.
  31. Arguments:
  32. FtinfoContext - Context to initialize
  33. Return Value:
  34. None
  35. --*/
  36. {
  37. RtlZeroMemory( FtinfoContext, sizeof(*FtinfoContext) );
  38. InitializeListHead( &FtinfoContext->FtinfoList );
  39. }
  40. VOID
  41. NetpMarshalFtinfoEntry (
  42. IN PLSA_FOREST_TRUST_RECORD InFtinfoRecord,
  43. OUT PLSA_FOREST_TRUST_RECORD OutFtinfoRecord,
  44. IN OUT LPBYTE *WherePtr
  45. )
  46. /*++
  47. Routine Description:
  48. Routine to marshalls a single Ftinfo entry
  49. Arguments:
  50. InFtinfoRecord - Template to copy into InFtinfoRecord
  51. OutFtinfoRecord - Entry to fill in
  52. On input, points to a zeroed buffer.
  53. WherePtr - On input, specifies where to marshal to.
  54. On output, points to the first byte past the marshalled data.
  55. Return Value:
  56. TRUE - Success
  57. FALSE - if no memory can be allocated
  58. --*/
  59. {
  60. LPBYTE Where = *WherePtr;
  61. ULONG Size;
  62. ULONG SidSize;
  63. ULONG NameSize;
  64. NetpAssert( Where == ROUND_UP_POINTER( Where, ALIGN_WORST ));
  65. //
  66. // Copy the fixed size data
  67. //
  68. OutFtinfoRecord->ForestTrustType = InFtinfoRecord->ForestTrustType;
  69. OutFtinfoRecord->Flags = InFtinfoRecord->Flags;
  70. OutFtinfoRecord->Time = InFtinfoRecord->Time;
  71. //
  72. // Fill in a domain entry
  73. //
  74. switch( InFtinfoRecord->ForestTrustType ) {
  75. case ForestTrustDomainInfo:
  76. //
  77. // Copy the DWORD aligned data
  78. //
  79. if ( InFtinfoRecord->ForestTrustData.DomainInfo.Sid != NULL ) {
  80. SidSize = RtlLengthSid( InFtinfoRecord->ForestTrustData.DomainInfo.Sid );
  81. OutFtinfoRecord->ForestTrustData.DomainInfo.Sid = (PISID) Where;
  82. RtlCopyMemory( Where, InFtinfoRecord->ForestTrustData.DomainInfo.Sid, SidSize );
  83. Where += SidSize;
  84. }
  85. //
  86. // Copy the WCHAR aligned data
  87. //
  88. NameSize = InFtinfoRecord->ForestTrustData.DomainInfo.DnsName.Length;
  89. if ( NameSize != 0 ) {
  90. OutFtinfoRecord->ForestTrustData.DomainInfo.DnsName.Buffer = (LPWSTR) Where;
  91. OutFtinfoRecord->ForestTrustData.DomainInfo.DnsName.MaximumLength = (USHORT) (NameSize+sizeof(WCHAR));
  92. OutFtinfoRecord->ForestTrustData.DomainInfo.DnsName.Length = (USHORT)NameSize;
  93. RtlCopyMemory( Where, InFtinfoRecord->ForestTrustData.DomainInfo.DnsName.Buffer, NameSize );
  94. Where += NameSize;
  95. *((LPWSTR)Where) = L'\0';
  96. Where += sizeof(WCHAR);
  97. }
  98. NameSize = InFtinfoRecord->ForestTrustData.DomainInfo.NetbiosName.Length;
  99. if ( NameSize != 0 ) {
  100. OutFtinfoRecord->ForestTrustData.DomainInfo.NetbiosName.Buffer = (LPWSTR) Where;
  101. OutFtinfoRecord->ForestTrustData.DomainInfo.NetbiosName.MaximumLength = (USHORT) (NameSize+sizeof(WCHAR));
  102. OutFtinfoRecord->ForestTrustData.DomainInfo.NetbiosName.Length = (USHORT)NameSize;
  103. RtlCopyMemory( Where, InFtinfoRecord->ForestTrustData.DomainInfo.NetbiosName.Buffer, NameSize );
  104. Where += NameSize;
  105. *((LPWSTR)Where) = L'\0';
  106. Where += sizeof(WCHAR);
  107. }
  108. break;
  109. //
  110. // Fill in a TLN entry
  111. //
  112. case ForestTrustTopLevelName:
  113. case ForestTrustTopLevelNameEx:
  114. //
  115. // Copy the WCHAR aligned data
  116. //
  117. NameSize = InFtinfoRecord->ForestTrustData.TopLevelName.Length;
  118. if ( NameSize != 0 ) {
  119. OutFtinfoRecord->ForestTrustData.TopLevelName.Buffer = (LPWSTR) Where;
  120. OutFtinfoRecord->ForestTrustData.TopLevelName.MaximumLength = (USHORT) (NameSize+sizeof(WCHAR));
  121. OutFtinfoRecord->ForestTrustData.TopLevelName.Length = (USHORT)NameSize;
  122. RtlCopyMemory( Where, InFtinfoRecord->ForestTrustData.TopLevelName.Buffer, NameSize );
  123. Where += NameSize;
  124. *((LPWSTR)Where) = L'\0';
  125. Where += sizeof(WCHAR);
  126. }
  127. break;
  128. default:
  129. NetpAssert( FALSE );
  130. }
  131. Where = ROUND_UP_POINTER( Where, ALIGN_WORST );
  132. *WherePtr = Where;
  133. }
  134. VOID
  135. NetpCompareHelper (
  136. IN PUNICODE_STRING Name,
  137. IN OUT PULONG Index,
  138. OUT PUNICODE_STRING CurrentLabel
  139. )
  140. /*++
  141. Routine Description:
  142. This routine is a helper routine for finding the next rightmost label in a string.
  143. Arguments:
  144. Name - The input dns name. The dns name should not have a trailing .
  145. Index - On input, should contain the value returned by the previous call to this routine.
  146. On input for the first call, should be set to Name->Length/sizeof(WCHAR).
  147. On output, zero is returned to indicate that this is the last of the name. The
  148. caller should not call again. Any other value output is a context for the next
  149. call to this routine.
  150. CurrentLabel - Returns a descriptor describing the substring which is the next label.
  151. Return Value:
  152. None.
  153. --*/
  154. {
  155. ULONG PreviousIndex = *Index;
  156. ULONG CurrentIndex = *Index;
  157. ULONG LabelIndex;
  158. NetpAssert( CurrentIndex != 0 );
  159. //
  160. // Find the beginning of the next label
  161. //
  162. while ( CurrentIndex > 0 ) {
  163. CurrentIndex--;
  164. if ( Name->Buffer[CurrentIndex] == L'.' ) {
  165. break;
  166. }
  167. }
  168. if ( CurrentIndex == 0 ) {
  169. LabelIndex = CurrentIndex;
  170. } else {
  171. LabelIndex = CurrentIndex + 1;
  172. }
  173. //
  174. // Return it to the caller
  175. //
  176. CurrentLabel->Buffer = &Name->Buffer[LabelIndex];
  177. CurrentLabel->Length = (USHORT)((PreviousIndex - LabelIndex) * sizeof(WCHAR));
  178. CurrentLabel->MaximumLength = CurrentLabel->Length;
  179. *Index = CurrentIndex;
  180. }
  181. int
  182. NetpCompareDnsNameWithSortOrder(
  183. IN PUNICODE_STRING Name1,
  184. IN PUNICODE_STRING Name2
  185. )
  186. /*++
  187. Routine Description:
  188. Routine to compare two DNS names. The DNS names must not have a trailing "."
  189. Labels are compare right to left to present a pleasent viewing order.
  190. Arguments:
  191. Name1 - First name to compare.
  192. Name2 - Second name to compare.
  193. Return Value:
  194. Signed value that gives the results of the comparison:
  195. Zero - String1 equals String2
  196. < Zero - String1 less than String2
  197. > Zero - String1 greater than String2
  198. --*/
  199. {
  200. ULONG Index1 = Name1->Length/sizeof(WCHAR);
  201. ULONG Index2 = Name2->Length/sizeof(WCHAR);
  202. UNICODE_STRING Label1;
  203. UNICODE_STRING Label2;
  204. LONG Result;
  205. //
  206. // Loop comparing labels
  207. //
  208. while ( Index1 != 0 && Index2 != 0 ) {
  209. //
  210. // Get the next label from each string
  211. //
  212. NetpCompareHelper ( Name1, &Index1, &Label1 );
  213. NetpCompareHelper ( Name2, &Index2, &Label2 );
  214. //
  215. // If the labels are different,
  216. // return that result to the caller.
  217. //
  218. Result = RtlCompareUnicodeString( &Label1, &Label2, TRUE );
  219. if ( Result != 0 ) {
  220. return (int)Result;
  221. }
  222. }
  223. //
  224. // ASSERT: one label is a (proper) substring of the other
  225. //
  226. // If the first name is longer, indicate it is greater than the second
  227. //
  228. return Index1-Index2;
  229. }
  230. int __cdecl NetpCompareFtinfoEntryDns(
  231. const void *String1,
  232. const void *String2
  233. )
  234. /*++
  235. Routine Description:
  236. qsort comparison routine for Dns string in Ftinfo entries
  237. Arguments:
  238. String1: First string to compare
  239. String2: Second string to compare
  240. Return Value:
  241. Signed value that gives the results of the comparison:
  242. Zero - String1 equals String2
  243. < Zero - String1 less than String2
  244. > Zero - String1 greater than String2
  245. --*/
  246. {
  247. PLSA_FOREST_TRUST_RECORD Entry1 = *((PLSA_FOREST_TRUST_RECORD *)String1);
  248. PLSA_FOREST_TRUST_RECORD Entry2 = *((PLSA_FOREST_TRUST_RECORD *)String2);
  249. PUNICODE_STRING Name1;
  250. PUNICODE_STRING Name2;
  251. int Result;
  252. //
  253. // Get the name from the entry
  254. //
  255. switch ( Entry1->ForestTrustType ) {
  256. case ForestTrustTopLevelName:
  257. case ForestTrustTopLevelNameEx:
  258. Name1 = &Entry1->ForestTrustData.TopLevelName;
  259. break;
  260. case ForestTrustDomainInfo:
  261. Name1 = &Entry1->ForestTrustData.DomainInfo.DnsName;
  262. break;
  263. default:
  264. //
  265. // If Entry2 can be recognized,
  266. // then entry 2 is less than this one.
  267. //
  268. switch ( Entry2->ForestTrustType ) {
  269. case ForestTrustTopLevelName:
  270. case ForestTrustTopLevelNameEx:
  271. case ForestTrustDomainInfo:
  272. return 1; // This name is greater than the other
  273. }
  274. //
  275. // Otherwise simply leave them in the same order
  276. //
  277. if ((Entry1 - Entry2) < 0 ) {
  278. return -1;
  279. } else if ((Entry1 - Entry2) > 0 ) {
  280. return 1;
  281. } else {
  282. return 0;
  283. }
  284. }
  285. switch ( Entry2->ForestTrustType ) {
  286. case ForestTrustTopLevelName:
  287. case ForestTrustTopLevelNameEx:
  288. Name2 = &Entry2->ForestTrustData.TopLevelName;
  289. break;
  290. case ForestTrustDomainInfo:
  291. Name2 = &Entry2->ForestTrustData.DomainInfo.DnsName;
  292. break;
  293. default:
  294. //
  295. // Since Entry1 is a recognized type,
  296. // this Entry2 is greater.
  297. //
  298. return -1; // This name is greater than the other
  299. }
  300. //
  301. // If the labels are different,
  302. // return the difference to the caller.
  303. //
  304. Result = NetpCompareDnsNameWithSortOrder( Name1, Name2 );
  305. if ( Result != 0 ) {
  306. return Result;
  307. }
  308. //
  309. // If the labels are the same,
  310. // indicate TLNs are before domain info records.
  311. //
  312. return Entry1->ForestTrustType - Entry2->ForestTrustType;
  313. }
  314. int
  315. NetpCompareSid(
  316. PSID Sid1,
  317. PSID Sid2
  318. )
  319. /*++
  320. Routine description:
  321. SID comparison routine that actually indicates if one sid is greater than another
  322. Arguments:
  323. Sid1 - First Sid
  324. Sid2 - Second Sid
  325. Returns:
  326. Signed value that gives the results of the comparison:
  327. Zero - String1 equals String2
  328. < Zero - String1 less than String2
  329. > Zero - String1 greater than String2
  330. --*/
  331. {
  332. DWORD Size1;
  333. DWORD Size2;
  334. LPBYTE Byte1;
  335. LPBYTE Byte2;
  336. ULONG i;
  337. NetpAssert( Sid1 && RtlValidSid( Sid1 ));
  338. NetpAssert( Sid2 && RtlValidSid( Sid2 ));
  339. //
  340. // The NULL SID is smaller
  341. //
  342. if ( Sid1 == NULL ) {
  343. if ( Sid2 != NULL ) {
  344. return -1;
  345. } else {
  346. return 0;
  347. }
  348. }
  349. if ( Sid2 == NULL ) {
  350. if ( Sid1 != NULL ) {
  351. return 1;
  352. } else {
  353. return 0;
  354. }
  355. }
  356. //
  357. // The longer sid is greater
  358. //
  359. Size1 = RtlLengthSid( Sid1 );
  360. Size2 = RtlLengthSid( Sid2 );
  361. if ( Size1 != Size2 ) {
  362. return Size1 - Size2;
  363. }
  364. //
  365. // Otherwise compare the bytes
  366. //
  367. Byte1 = (LPBYTE)Sid1;
  368. Byte2 = (LPBYTE)Sid2;
  369. for ( i=0; i<Size1; i++ ) {
  370. if ( Byte1[i] != Byte2[i] ) {
  371. return Byte1[i] - Byte2[i];
  372. }
  373. }
  374. return 0;
  375. }
  376. int __cdecl NetpCompareFtinfoEntrySid(
  377. const void *String1,
  378. const void *String2
  379. )
  380. /*++
  381. Routine Description:
  382. qsort comparison routine for Sid string in Ftinfo entries
  383. Arguments:
  384. String1: First string to compare
  385. String2: Second string to compare
  386. Return Value:
  387. Signed value that gives the results of the comparison:
  388. Zero - String1 equals String2
  389. < Zero - String1 less than String2
  390. > Zero - String1 greater than String2
  391. --*/
  392. {
  393. PLSA_FOREST_TRUST_RECORD Entry1 = *((PLSA_FOREST_TRUST_RECORD *)String1);
  394. PLSA_FOREST_TRUST_RECORD Entry2 = *((PLSA_FOREST_TRUST_RECORD *)String2);
  395. PSID Sid1;
  396. PSID Sid2;
  397. int Result;
  398. //
  399. // Get the Sid from the entry
  400. //
  401. switch ( Entry1->ForestTrustType ) {
  402. case ForestTrustDomainInfo:
  403. Sid1 = Entry1->ForestTrustData.DomainInfo.Sid;
  404. break;
  405. default:
  406. //
  407. // If Entry2 can be recognized,
  408. // then entry 2 is less than this one.
  409. //
  410. switch ( Entry2->ForestTrustType ) {
  411. case ForestTrustDomainInfo:
  412. return 1; // This name is greater than the other
  413. }
  414. //
  415. // Otherwise simply leave them in the same order
  416. //
  417. if ((Entry1 - Entry2) < 0 ) {
  418. return -1;
  419. } else if ((Entry1 - Entry2) > 0 ) {
  420. return 1;
  421. } else {
  422. return 0;
  423. }
  424. }
  425. switch ( Entry2->ForestTrustType ) {
  426. case ForestTrustDomainInfo:
  427. Sid2 = Entry2->ForestTrustData.DomainInfo.Sid;
  428. break;
  429. default:
  430. //
  431. // Since Entry1 is a recognized type,
  432. // this Entry2 is greater.
  433. //
  434. return -1; // This name is greater than the other
  435. }
  436. //
  437. // Simply return the different of the sids.
  438. //
  439. return NetpCompareSid( Sid1, Sid2 );
  440. }
  441. int __cdecl NetpCompareFtinfoEntryNetbios(
  442. const void *String1,
  443. const void *String2
  444. )
  445. /*++
  446. Routine Description:
  447. qsort comparison routine for Netbios name in Ftinfo entries
  448. Arguments:
  449. String1: First string to compare
  450. String2: Second string to compare
  451. Return Value:
  452. Signed value that gives the results of the comparison:
  453. Zero - String1 equals String2
  454. < Zero - String1 less than String2
  455. > Zero - String1 greater than String2
  456. --*/
  457. {
  458. PLSA_FOREST_TRUST_RECORD Entry1 = *((PLSA_FOREST_TRUST_RECORD *)String1);
  459. PLSA_FOREST_TRUST_RECORD Entry2 = *((PLSA_FOREST_TRUST_RECORD *)String2);
  460. PUNICODE_STRING Name1;
  461. PUNICODE_STRING Name2;
  462. int Result;
  463. //
  464. // Get the Sid from the entry
  465. //
  466. switch ( Entry1->ForestTrustType ) {
  467. case ForestTrustDomainInfo:
  468. Name1 = &Entry1->ForestTrustData.DomainInfo.NetbiosName;
  469. if ( Name1->Length != 0 && Name1->Buffer != NULL ) {
  470. break;
  471. }
  472. default:
  473. //
  474. // If Entry2 can be recognized,
  475. // then entry 2 is less than this one.
  476. //
  477. switch ( Entry2->ForestTrustType ) {
  478. case ForestTrustDomainInfo:
  479. return 1; // This name is greater than the other
  480. }
  481. //
  482. // Otherwise simply leave them in the same order
  483. //
  484. if ((Entry1 - Entry2) < 0 ) {
  485. return -1;
  486. } else if ((Entry1 - Entry2) > 0 ) {
  487. return 1;
  488. } else {
  489. return 0;
  490. }
  491. }
  492. switch ( Entry2->ForestTrustType ) {
  493. case ForestTrustDomainInfo:
  494. Name2 = &Entry2->ForestTrustData.DomainInfo.NetbiosName;
  495. if ( Name2->Length != 0 && Name2->Buffer != NULL ) {
  496. break;
  497. }
  498. default:
  499. //
  500. // Since Entry1 is a recognized type,
  501. // this Entry2 is greater.
  502. //
  503. return -1; // This name is greater than the other
  504. }
  505. //
  506. // Simply return the difference of the names
  507. //
  508. return RtlCompareUnicodeString( Name1, Name2, TRUE );
  509. }
  510. PLSA_FOREST_TRUST_INFORMATION
  511. NetpCopyFtinfoContext(
  512. IN PNL_FTINFO_CONTEXT FtinfoContext
  513. )
  514. /*++
  515. Routine Description:
  516. Routine to allocate an FTinfo array from an FTinfo context.
  517. Arguments:
  518. FtinfoContext - Context to use
  519. The caller must have previously called NetpInitFtinfoContext
  520. Return Value:
  521. FTinfo array. The caller should free this array using MIDL_user_free.
  522. If NULL, not enough memory was available.
  523. --*/
  524. {
  525. PNL_FTINFO_ENTRY FtinfoEntry;
  526. PLIST_ENTRY ListEntry;
  527. PLSA_FOREST_TRUST_INFORMATION LocalForestTrustInfo;
  528. LPBYTE Where;
  529. ULONG Size;
  530. ULONG i;
  531. PLSA_FOREST_TRUST_RECORD Entries;
  532. //
  533. // Allocate a structure to return to the caller.
  534. //
  535. Size = ROUND_UP_COUNT( sizeof( *LocalForestTrustInfo ), ALIGN_WORST) +
  536. ROUND_UP_COUNT( FtinfoContext->FtinfoCount * sizeof(LSA_FOREST_TRUST_RECORD), ALIGN_WORST) +
  537. ROUND_UP_COUNT( FtinfoContext->FtinfoCount * sizeof(PLSA_FOREST_TRUST_RECORD), ALIGN_WORST) +
  538. FtinfoContext->FtinfoSize;
  539. LocalForestTrustInfo = MIDL_user_allocate( Size );
  540. if ( LocalForestTrustInfo == NULL ) {
  541. return NULL;
  542. }
  543. RtlZeroMemory( LocalForestTrustInfo, Size );
  544. Where = (LPBYTE)(LocalForestTrustInfo+1);
  545. Where = ROUND_UP_POINTER( Where, ALIGN_WORST );
  546. //
  547. // Fill it in
  548. //
  549. LocalForestTrustInfo->RecordCount = FtinfoContext->FtinfoCount;
  550. //
  551. // Grab a huge chunk of ALIGN_WORST
  552. // (We fill it in during the loop below.)
  553. //
  554. Entries = (PLSA_FOREST_TRUST_RECORD) Where;
  555. Where = (LPBYTE)(&Entries[FtinfoContext->FtinfoCount]);
  556. Where = ROUND_UP_POINTER( Where, ALIGN_WORST );
  557. //
  558. // Grab a huge chunk of dword aligned
  559. // (We fill it in during the loop below.)
  560. //
  561. LocalForestTrustInfo->Entries = (PLSA_FOREST_TRUST_RECORD *) Where;
  562. Where = (LPBYTE)(&LocalForestTrustInfo->Entries[FtinfoContext->FtinfoCount]);
  563. Where = ROUND_UP_POINTER( Where, ALIGN_WORST );
  564. //
  565. // Fill in the individual entries
  566. //
  567. i = 0;
  568. for ( ListEntry = FtinfoContext->FtinfoList.Flink ;
  569. ListEntry != &FtinfoContext->FtinfoList ;
  570. ListEntry = ListEntry->Flink) {
  571. FtinfoEntry = CONTAINING_RECORD( ListEntry, NL_FTINFO_ENTRY, Next );
  572. LocalForestTrustInfo->Entries[i] = &Entries[i];
  573. NetpMarshalFtinfoEntry (
  574. &FtinfoEntry->Record,
  575. &Entries[i],
  576. &Where );
  577. i++;
  578. }
  579. NetpAssert( i == FtinfoContext->FtinfoCount );
  580. NetpAssert( Where == ((LPBYTE)LocalForestTrustInfo) + Size );
  581. //
  582. // Sort them into alphabetical order
  583. //
  584. qsort( LocalForestTrustInfo->Entries,
  585. LocalForestTrustInfo->RecordCount,
  586. sizeof(PLSA_FOREST_TRUST_RECORD),
  587. NetpCompareFtinfoEntryDns );
  588. //
  589. // Return the allocated buffer to the caller.
  590. //
  591. return LocalForestTrustInfo;
  592. }
  593. VOID
  594. NetpCleanFtinfoContext(
  595. IN PNL_FTINFO_CONTEXT FtinfoContext
  596. )
  597. /*++
  598. Routine Description:
  599. Routine to cleanup the Ftinfo context structure.
  600. Arguments:
  601. FtinfoContext - Context to clean
  602. The caller must have previously called NetpInitFtinfoContext
  603. Return Value:
  604. None
  605. --*/
  606. {
  607. PLIST_ENTRY ListEntry;
  608. PNL_FTINFO_ENTRY FtinfoEntry;
  609. //
  610. // Loop freeing the entries
  611. //
  612. while ( !IsListEmpty( &FtinfoContext->FtinfoList ) ) {
  613. //
  614. // Delink an entry
  615. //
  616. ListEntry = RemoveHeadList( &FtinfoContext->FtinfoList );
  617. FtinfoEntry = CONTAINING_RECORD( ListEntry, NL_FTINFO_ENTRY, Next );
  618. FtinfoContext->FtinfoCount -= 1;
  619. FtinfoContext->FtinfoSize -= FtinfoEntry->Size;
  620. RtlFreeHeap( RtlProcessHeap(), 0, FtinfoEntry );
  621. }
  622. NetpAssert( FtinfoContext->FtinfoCount == 0 );
  623. NetpAssert( FtinfoContext->FtinfoSize == 0 );
  624. }
  625. PLSA_FOREST_TRUST_RECORD
  626. NetpAllocFtinfoEntry2 (
  627. IN PNL_FTINFO_CONTEXT FtinfoContext,
  628. IN PLSA_FOREST_TRUST_RECORD InFtinfoRecord
  629. )
  630. /*++
  631. Routine Description:
  632. Same as NetpAllocFtinfoEntry except takes a template of an FTinfo entry on input.
  633. Arguments:
  634. FtinfoContext - Context to link the entry onto.
  635. InFtinfoRecord - Template to copy into InFtinfoRecord
  636. Return Value:
  637. Returns the address of the allocated forest trust record.
  638. The caller should not and cannot deallocate this buffer. It has a header and is
  639. linked into the FtinfoContext.
  640. Returns NULL if no memory can be allocated.
  641. --*/
  642. {
  643. PNL_FTINFO_ENTRY FtinfoEntry;
  644. ULONG Size = ROUND_UP_COUNT(sizeof(NL_FTINFO_ENTRY), ALIGN_WORST);
  645. ULONG DataSize = 0;
  646. LPBYTE Where;
  647. //
  648. // Compute the size of the entry.
  649. //
  650. switch( InFtinfoRecord->ForestTrustType ) {
  651. case ForestTrustDomainInfo:
  652. if ( InFtinfoRecord->ForestTrustData.DomainInfo.Sid != NULL ) {
  653. DataSize += RtlLengthSid( InFtinfoRecord->ForestTrustData.DomainInfo.Sid );
  654. }
  655. if ( InFtinfoRecord->ForestTrustData.DomainInfo.DnsName.Length != 0 ) {
  656. DataSize += InFtinfoRecord->ForestTrustData.DomainInfo.DnsName.Length + sizeof(WCHAR);
  657. }
  658. if ( InFtinfoRecord->ForestTrustData.DomainInfo.NetbiosName.Length != 0 ) {
  659. DataSize += InFtinfoRecord->ForestTrustData.DomainInfo.NetbiosName.Length + sizeof(WCHAR);
  660. }
  661. break;
  662. case ForestTrustTopLevelName:
  663. case ForestTrustTopLevelNameEx:
  664. if ( InFtinfoRecord->ForestTrustData.TopLevelName.Length != 0 ) {
  665. DataSize += InFtinfoRecord->ForestTrustData.TopLevelName.Length + sizeof(WCHAR);
  666. }
  667. break;
  668. default:
  669. NetpAssert( FALSE );
  670. return NULL;
  671. }
  672. DataSize = ROUND_UP_COUNT(DataSize, ALIGN_WORST);
  673. //
  674. // Allocate an entry
  675. //
  676. Size += DataSize;
  677. FtinfoEntry = RtlAllocateHeap( RtlProcessHeap(), 0, Size );
  678. if ( FtinfoEntry == NULL ) {
  679. return NULL;
  680. }
  681. RtlZeroMemory( FtinfoEntry, Size );
  682. Where = (LPBYTE)(FtinfoEntry+1);
  683. //
  684. // Fill it in.
  685. //
  686. FtinfoEntry->Size = DataSize;
  687. NetpMarshalFtinfoEntry ( InFtinfoRecord,
  688. &FtinfoEntry->Record,
  689. &Where );
  690. NetpAssert( Where == ((LPBYTE)FtinfoEntry) + Size )
  691. //
  692. // Link it onto the list
  693. //
  694. InsertHeadList( &FtinfoContext->FtinfoList, &FtinfoEntry->Next );
  695. FtinfoContext->FtinfoSize += FtinfoEntry->Size;
  696. FtinfoContext->FtinfoCount += 1;
  697. return &FtinfoEntry->Record;
  698. }
  699. BOOLEAN
  700. NetpAllocFtinfoEntry (
  701. IN PNL_FTINFO_CONTEXT FtinfoContext,
  702. IN LSA_FOREST_TRUST_RECORD_TYPE ForestTrustType,
  703. IN PUNICODE_STRING Name,
  704. IN PSID Sid,
  705. IN PUNICODE_STRING NetbiosName
  706. )
  707. /*++
  708. Routine Description:
  709. Routine to allocate a single Ftinfo entry and link it onto the context.
  710. Arguments:
  711. FtinfoContext - Context to link the entry onto.
  712. ForestTypeType - Specifies the type of record to allocate. This must be
  713. ForestTrustTopLevelName or ForestTrustDomainInfo.
  714. Name - Specifies the name for the record.
  715. Sid - Specifies the SID for the record. (Ignored for ForestTrustTopLevelName.)
  716. NetbiosName - Specifies the netbios name for the record. (Ignored for ForestTrustTopLevelName.)
  717. Return Value:
  718. TRUE - Success
  719. FALSE - if no memory can be allocated
  720. --*/
  721. {
  722. LSA_FOREST_TRUST_RECORD FtinfoRecord = {0};
  723. //
  724. // Initialize the template Ftinfo entry
  725. //
  726. FtinfoRecord.ForestTrustType = ForestTrustType;
  727. switch( ForestTrustType ) {
  728. case ForestTrustDomainInfo:
  729. FtinfoRecord.ForestTrustData.DomainInfo.Sid = Sid;
  730. FtinfoRecord.ForestTrustData.DomainInfo.DnsName = *Name;
  731. FtinfoRecord.ForestTrustData.DomainInfo.NetbiosName = *NetbiosName;
  732. break;
  733. case ForestTrustTopLevelName:
  734. case ForestTrustTopLevelNameEx:
  735. FtinfoRecord.ForestTrustData.TopLevelName = *Name;
  736. break;
  737. default:
  738. NetpAssert( FALSE );
  739. return FALSE;
  740. }
  741. //
  742. // Call the routine that takes a template and does the rest of the job
  743. //
  744. return (NetpAllocFtinfoEntry2( FtinfoContext, &FtinfoRecord ) != NULL);
  745. }
  746. BOOLEAN
  747. NetpIsSubordinate(
  748. IN const UNICODE_STRING * Subordinate,
  749. IN const UNICODE_STRING * Superior,
  750. IN BOOLEAN EqualReturnsTrue
  751. )
  752. /*++
  753. Routine Description:
  754. Determines if Subordinate string is indeed subordinate to Superior
  755. For example, "NY.acme.com" is subordinate to "acme.com", but
  756. "NY.acme.com" is NOT subordinate to "me.com" or "NY.acme.com"
  757. Arguments:
  758. Subordinate name to test for subordinate status
  759. Superior name to test for superior status
  760. EqualReturnsTrue - TRUE if equal names should return TRUE also
  761. Returns:
  762. TRUE is Subordinate is subordinate to Superior
  763. FALSE otherwise
  764. --*/
  765. {
  766. USHORT SubIndex, SupIndex;
  767. UNICODE_STRING Temp;
  768. ASSERT( Subordinate && Subordinate->Buffer );
  769. ASSERT( Superior && Superior->Buffer );
  770. //
  771. // If equal names are to be considered subordinate,
  772. // compare the names for equality.
  773. //
  774. if ( EqualReturnsTrue &&
  775. RtlEqualUnicodeString( Subordinate, Superior, TRUE )) {
  776. return TRUE;
  777. }
  778. //
  779. // A subordinate name must be longer than the superior name
  780. //
  781. if ( Subordinate->Length <= Superior->Length ) {
  782. return FALSE;
  783. }
  784. //
  785. // Subordinate name must be separated from the superior part by a period
  786. //
  787. if ( Subordinate->Buffer[( Subordinate->Length - Superior->Length ) / sizeof( WCHAR ) - 1] != L'.' ) {
  788. return FALSE;
  789. }
  790. //
  791. // Ensure the trailing part of the two names are the same.
  792. //
  793. Temp = *Subordinate;
  794. Temp.Buffer += ( Subordinate->Length - Superior->Length ) / sizeof( WCHAR );
  795. Temp.Length = Superior->Length;
  796. Temp.MaximumLength = Temp.Length;
  797. if ( !RtlEqualUnicodeString( &Temp, Superior, TRUE )) {
  798. return FALSE;
  799. }
  800. return TRUE;
  801. }
  802. BOOLEAN
  803. NetpAddTlnFtinfoEntry (
  804. IN PNL_FTINFO_CONTEXT FtinfoContext,
  805. IN PUNICODE_STRING Name
  806. )
  807. /*++
  808. Routine Description:
  809. Routine to add a TLN Ftinfo entry to the list.
  810. If there is already a TLN that is equal to or superior to this one, this TLN is
  811. ignored. (e.g., a TLN of a.acme.com is ignored of acme.com already exists in the list.)
  812. If there is already a TLN that is inferior to this one, the inferior TLN is
  813. removed and this one is added. (e.g., a TLN of acme.com causes an existing TLN of
  814. a.acme.com to be replaced by the new entry.)
  815. Arguments:
  816. FtinfoContext - Context to link the entry onto.
  817. Name - Specifies the name for the record.
  818. Return Value:
  819. TRUE - Success
  820. FALSE - if no memory can be allocated
  821. --*/
  822. {
  823. PNL_FTINFO_ENTRY FtinfoEntry;
  824. PLIST_ENTRY ListEntry;
  825. //
  826. // Loop through the list of existing entries
  827. //
  828. for ( ListEntry = FtinfoContext->FtinfoList.Flink ;
  829. ListEntry != &FtinfoContext->FtinfoList ;
  830. ) {
  831. FtinfoEntry = CONTAINING_RECORD( ListEntry, NL_FTINFO_ENTRY, Next );
  832. ListEntry = ListEntry->Flink;
  833. //
  834. // Ignore entries that aren't TLNs.
  835. //
  836. if ( FtinfoEntry->Record.ForestTrustType != ForestTrustTopLevelName ) {
  837. continue;
  838. }
  839. //
  840. // If the new name is subordinate (or equal to) to one already in the list,
  841. // ignore the new name.
  842. //
  843. if ( NetpIsSubordinate( Name,
  844. &FtinfoEntry->Record.ForestTrustData.TopLevelName,
  845. TRUE ) ) {
  846. return TRUE;
  847. }
  848. //
  849. // If the existing name is subordinate to the new name,
  850. // remove the existing name.
  851. //
  852. if ( NetpIsSubordinate( &FtinfoEntry->Record.ForestTrustData.TopLevelName,
  853. Name,
  854. FALSE ) ) {
  855. RemoveEntryList( &FtinfoEntry->Next );
  856. FtinfoContext->FtinfoCount -= 1;
  857. FtinfoContext->FtinfoSize -= FtinfoEntry->Size;
  858. RtlFreeHeap( RtlProcessHeap(), 0, FtinfoEntry );
  859. // continue looping since there may be more names to remove
  860. }
  861. }
  862. //
  863. // Add the new entry to the list
  864. //
  865. return NetpAllocFtinfoEntry( FtinfoContext,
  866. ForestTrustTopLevelName,
  867. Name,
  868. NULL, // No sid
  869. NULL ); // No Netbios name
  870. }
  871. VOID
  872. NetpMergeFtinfoHelper(
  873. IN PLSA_FOREST_TRUST_INFORMATION NewForestTrustInfo,
  874. IN PLSA_FOREST_TRUST_INFORMATION OldForestTrustInfo,
  875. IN OUT PULONG NewIndex,
  876. IN OUT PULONG OldIndex,
  877. OUT PLSA_FOREST_TRUST_RECORD *NewEntry,
  878. OUT PLSA_FOREST_TRUST_RECORD *OldEntry,
  879. OUT PULONG OldFlags,
  880. IN int (__cdecl *Routine) (const void *, const void *)
  881. )
  882. /*++
  883. Routine Description:
  884. This routine walks a pair of FTinfo arrays in sorted order and returns the next
  885. entry. If both entries are the same in the sort order, this routine returns an entry
  886. from both arrays
  887. Arguments:
  888. NewForestTrustInfo - Pointer to the first array
  889. OldForestTrustInfo - Pointer to the second array
  890. NewIndex - Current index into the first sorted array
  891. OldIndex - Current index into the second sorted array
  892. Before calling this routine the first time, the caller should set these parameters to zero.
  893. Both indices zero triggers this routine to qsort the arrays.
  894. The caller should *not* call this routine if both NewIndex and OldIndex are greater
  895. than the corresponding record count.
  896. NewEntry - Returns a pointer to an entry to be processed from the first sorted array.
  897. OldEntry - Returns a pointer to an entry to be processed from the second sorted array.
  898. Returns NULL if no entry is to be processed from the corresponding array.
  899. OldFlags - Returns the Flags field that corresponds to OldEntry.
  900. If there are duplicates of OldEntry, those duplicates are silently ignored by
  901. this routine. This field returns the logical OR of the Flags field of those entries.
  902. Routine - Comparison routine to passed to qsort to sort the FTinfo arrays.
  903. Return Value:
  904. None.
  905. --*/
  906. {
  907. int RetVal;
  908. //
  909. // Sort the arrays
  910. //
  911. if ( *NewIndex == 0 && *OldIndex == 0 ) {
  912. qsort( NewForestTrustInfo->Entries,
  913. NewForestTrustInfo->RecordCount,
  914. sizeof(PLSA_FOREST_TRUST_RECORD),
  915. Routine );
  916. qsort( OldForestTrustInfo->Entries,
  917. OldForestTrustInfo->RecordCount,
  918. sizeof(PLSA_FOREST_TRUST_RECORD),
  919. Routine );
  920. }
  921. //
  922. // Compare the first entry at the front of each list to determine which list
  923. // to consume an entry from.
  924. //
  925. *NewEntry = NULL;
  926. *OldEntry = NULL;
  927. *OldFlags = 0;
  928. if ( *NewIndex < NewForestTrustInfo->RecordCount ) {
  929. //
  930. // If neither list is empty,
  931. // compare the entries to determine which is next.
  932. //
  933. if ( *OldIndex < OldForestTrustInfo->RecordCount ) {
  934. RetVal = (*Routine)(
  935. &NewForestTrustInfo->Entries[*NewIndex],
  936. &OldForestTrustInfo->Entries[*OldIndex] );
  937. //
  938. // If the new entry is less than or equal to the old entry,
  939. // consume the new entry.
  940. //
  941. if ( RetVal <= 0 ) {
  942. *NewEntry = NewForestTrustInfo->Entries[*NewIndex];
  943. (*NewIndex) ++;
  944. }
  945. //
  946. // If the old entry is less than or equal to the new entry,
  947. // consume the old entry.
  948. //
  949. if ( RetVal >= 0 ) {
  950. *OldEntry = OldForestTrustInfo->Entries[*OldIndex];
  951. (*OldIndex) ++;
  952. }
  953. //
  954. // If the old list is empty and the new list isn't,
  955. // consume an entry from the new list.
  956. //
  957. } else {
  958. *NewEntry = NewForestTrustInfo->Entries[*NewIndex];
  959. (*NewIndex) ++;
  960. }
  961. } else {
  962. //
  963. // If the new list is empty and the old list isn't,
  964. // consume an entry from the old list.
  965. //
  966. if ( *OldIndex < OldForestTrustInfo->RecordCount ) {
  967. *OldEntry = OldForestTrustInfo->Entries[*OldIndex];
  968. (*OldIndex) ++;
  969. }
  970. }
  971. //
  972. // If we're returning an "OldEntry",
  973. // weed out all duplicates of that OldEntry.
  974. //
  975. if ( *OldEntry != NULL ) {
  976. *OldFlags |= (*OldEntry)->Flags;
  977. while ( *OldIndex < OldForestTrustInfo->RecordCount ) {
  978. //
  979. // Stop as soon as we hit an entry that isn't a duplicate.
  980. //
  981. RetVal = (*Routine)(
  982. OldEntry,
  983. &OldForestTrustInfo->Entries[*OldIndex] );
  984. if ( RetVal != 0 ) {
  985. break;
  986. }
  987. *OldFlags |= (*OldEntry)->Flags;
  988. }
  989. }
  990. }
  991. NTSTATUS
  992. NetpMergeFtinfo(
  993. IN PUNICODE_STRING TrustedDomainName,
  994. IN PLSA_FOREST_TRUST_INFORMATION InNewForestTrustInfo,
  995. IN PLSA_FOREST_TRUST_INFORMATION InOldForestTrustInfo OPTIONAL,
  996. OUT PLSA_FOREST_TRUST_INFORMATION *MergedForestTrustInfo
  997. )
  998. /*++
  999. Routine Description:
  1000. This function merges the changes from a new FTinfo into an old FTinfo and
  1001. produces the resultant FTinfo.
  1002. The merged FTinfo records are a combinition of the new and old records.
  1003. Here's where the merged records come from:
  1004. * The TLN exclusion records are copied from the TDO intact.
  1005. * The TLN record from the trusted domain that maps to the dns domain name of the
  1006. TDO is copied enabled. This reflects the LSA requirement that such a TLN not
  1007. be disabled. For instance, if the TDO is for a.acme.com and there is a TLN for
  1008. a.acme.com that TLN will be enabled. Also, if the TDO is for a.acme.com and
  1009. there is a TLN for acme.com, that TLN will be enabled.
  1010. * All other TLN records from the trusted domain are copied disabled with the
  1011. following exceptions. If there is an enabled TLN on the TDO, all TLNs from the
  1012. trusted domain that equal (or are subordinate to) the TDO TLN are marked as
  1013. disabled. This follows the philosophy that new TLNs are imported as enabled.
  1014. For instance, if the TDO had an enabled TLN for a.acme.com that TLN will still
  1015. be enabled after the automatic update. If the TDO had an enabled TLN for
  1016. acme.com and the trusted forest now has a TLN for a.acme.com, the resultant
  1017. FTinfo will have an enabled TLN for a.acme.com.
  1018. * The domain records from the trusted domain are copied enabled with the
  1019. following exceptions. If there is a disabled domain record on the TDO whose
  1020. dns domain name, or domain sid exactly matches the domain record, then the domain
  1021. remains disabled. If there is a domain record on the TDO whose netbios name is
  1022. disabled and whose netbios name exactly matches the netbios name on a domain
  1023. record, then the netbios name is disabled.
  1024. Arguments:
  1025. TrustedDomainName - Trusted domain that is to be updated.
  1026. NewForestTrustInfo - Specified the new array of FTinfo records as returned from the
  1027. TrustedDomainName.
  1028. The Flags field and Time field of the TLN entries are ignored.
  1029. OldForestTrustInfo - Specified the array of FTinfo records as returned from the
  1030. TDO. This field may be NULL if there is no existing records.
  1031. MergedForestTrustInfo - Returns the resulant FTinfo records.
  1032. The caller should free this buffer using MIDL_user_free.
  1033. Return Value:
  1034. STATUS_SUCCESS: Success.
  1035. STATUS_INVALID_PARAMETER: One of the following happened:
  1036. * There was no New TLN that TrustedDomainName is subordinate to.
  1037. --*/
  1038. {
  1039. NTSTATUS Status;
  1040. LSA_FOREST_TRUST_INFORMATION OldForestTrustInfo;
  1041. LSA_FOREST_TRUST_INFORMATION NewForestTrustInfo;
  1042. LSA_FOREST_TRUST_INFORMATION NetbiosForestTrustInfo;
  1043. NL_FTINFO_CONTEXT FtinfoContext;
  1044. ULONG NewIndex;
  1045. ULONG OldIndex;
  1046. ULONG OldFlags;
  1047. PLSA_FOREST_TRUST_RECORD NewEntry;
  1048. PLSA_FOREST_TRUST_RECORD PreviousNewEntry;
  1049. PLSA_FOREST_TRUST_RECORD OldEntry;
  1050. BOOLEAN DomainTlnFound = FALSE;
  1051. PLSA_FOREST_TRUST_RECORD OldTlnPrefix;
  1052. //
  1053. // Initialization
  1054. //
  1055. *MergedForestTrustInfo = NULL;
  1056. NetpInitFtinfoContext( &FtinfoContext );
  1057. RtlZeroMemory( &OldForestTrustInfo, sizeof(OldForestTrustInfo) );
  1058. RtlZeroMemory( &NewForestTrustInfo, sizeof(NewForestTrustInfo) );
  1059. RtlZeroMemory( &NetbiosForestTrustInfo, sizeof(NetbiosForestTrustInfo) );
  1060. //
  1061. // Make a copy of the data that'll be qsorted so that we don't modify the caller's buffer.
  1062. //
  1063. if ( InOldForestTrustInfo != NULL ) {
  1064. OldForestTrustInfo.RecordCount = InOldForestTrustInfo->RecordCount;
  1065. OldForestTrustInfo.Entries = RtlAllocateHeap( RtlProcessHeap(), 0, OldForestTrustInfo.RecordCount * sizeof(PLSA_FOREST_TRUST_RECORD) );
  1066. if ( OldForestTrustInfo.Entries == NULL ) {
  1067. Status = STATUS_NO_MEMORY;
  1068. goto Cleanup;
  1069. }
  1070. RtlCopyMemory( OldForestTrustInfo.Entries,
  1071. InOldForestTrustInfo->Entries,
  1072. OldForestTrustInfo.RecordCount * sizeof(PLSA_FOREST_TRUST_RECORD) );
  1073. }
  1074. NewForestTrustInfo.RecordCount = InNewForestTrustInfo->RecordCount;
  1075. NewForestTrustInfo.Entries = RtlAllocateHeap( RtlProcessHeap(), 0, NewForestTrustInfo.RecordCount * sizeof(PLSA_FOREST_TRUST_RECORD) );
  1076. if ( NewForestTrustInfo.Entries == NULL ) {
  1077. Status = STATUS_NO_MEMORY;
  1078. goto Cleanup;
  1079. }
  1080. RtlCopyMemory( NewForestTrustInfo.Entries,
  1081. InNewForestTrustInfo->Entries,
  1082. NewForestTrustInfo.RecordCount * sizeof(PLSA_FOREST_TRUST_RECORD) );
  1083. //
  1084. // Allocate a temporary Ftinfo array containing all of the domain entries.
  1085. // Allocate it a worst case size.
  1086. //
  1087. NetbiosForestTrustInfo.Entries = RtlAllocateHeap(
  1088. RtlProcessHeap(),
  1089. 0,
  1090. (OldForestTrustInfo.RecordCount+NewForestTrustInfo.RecordCount) * sizeof(PLSA_FOREST_TRUST_RECORD) );
  1091. if ( NetbiosForestTrustInfo.Entries == NULL ) {
  1092. Status = STATUS_NO_MEMORY;
  1093. goto Cleanup;
  1094. }
  1095. //
  1096. // Loop through each list in DNS canonical order processing the least entry.
  1097. //
  1098. // This loop handles TLN and TLNEX entries only
  1099. //
  1100. NewIndex = 0;
  1101. OldIndex = 0;
  1102. OldTlnPrefix = NULL;
  1103. PreviousNewEntry = NULL;
  1104. while ( NewIndex < NewForestTrustInfo.RecordCount ||
  1105. OldIndex < OldForestTrustInfo.RecordCount ) {
  1106. //
  1107. // Grab the next entry from each of the sorted arrays
  1108. //
  1109. NetpMergeFtinfoHelper( &NewForestTrustInfo,
  1110. &OldForestTrustInfo,
  1111. &NewIndex,
  1112. &OldIndex,
  1113. &NewEntry,
  1114. &OldEntry,
  1115. &OldFlags,
  1116. NetpCompareFtinfoEntryDns );
  1117. //
  1118. // Process the old entry
  1119. //
  1120. if ( OldEntry != NULL ) {
  1121. //
  1122. // Remember to most recent TLN record from the old array.
  1123. //
  1124. if ( OldEntry->ForestTrustType == ForestTrustTopLevelName ) {
  1125. OldTlnPrefix = OldEntry;
  1126. //
  1127. // TLN exclusion records are taken from the old entries
  1128. //
  1129. } else if ( OldEntry->ForestTrustType == ForestTrustTopLevelNameEx ) {
  1130. if ( NetpAllocFtinfoEntry2( &FtinfoContext, OldEntry ) == NULL ) {
  1131. Status = STATUS_NO_MEMORY;
  1132. goto Cleanup;
  1133. }
  1134. }
  1135. }
  1136. //
  1137. // Process the new entry
  1138. //
  1139. if ( NewEntry != NULL ) {
  1140. //
  1141. // Handle TLN entries
  1142. //
  1143. if ( NewEntry->ForestTrustType == ForestTrustTopLevelName ) {
  1144. BOOLEAN SetTlnNewFlag;
  1145. LSA_FOREST_TRUST_RECORD NewEntryCopy;
  1146. //
  1147. // Make a copy of the new entry.
  1148. //
  1149. // We modify the entry to get the time and flags right. We don't want
  1150. // to modify the callers buffer.
  1151. //
  1152. NewEntryCopy = *NewEntry;
  1153. //
  1154. // Ignore duplicate new entries
  1155. //
  1156. // If the name of this new entry is subordinate to the previous new entry,
  1157. // then this TLN can be quietly dropped.
  1158. //
  1159. // This is the case where the trusted domain sent us a TLN for both
  1160. // acme.com and a.acme.com. The second entry is a duplicate.
  1161. //
  1162. if ( PreviousNewEntry != NULL &&
  1163. PreviousNewEntry->ForestTrustType == ForestTrustTopLevelName ) {
  1164. if ( NetpIsSubordinate( &NewEntry->ForestTrustData.TopLevelName,
  1165. &PreviousNewEntry->ForestTrustData.TopLevelName,
  1166. TRUE ) ) {
  1167. continue;
  1168. }
  1169. }
  1170. //
  1171. // By default any TLN from the new list should be marked as new.
  1172. //
  1173. SetTlnNewFlag = TRUE;
  1174. //
  1175. // Set the flags and timestamp on the new entry.
  1176. //
  1177. // If we're processing an entry from both lists,
  1178. // grab the flags and timestamp from the old entry.
  1179. //
  1180. if ( OldEntry != NULL ) {
  1181. NewEntryCopy.Flags = OldFlags;
  1182. NewEntryCopy.Time = OldEntry->Time;
  1183. // This entry isn't 'new'.
  1184. SetTlnNewFlag = FALSE;
  1185. //
  1186. // Otherwise indicate that we have no information
  1187. //
  1188. } else {
  1189. NewEntryCopy.Flags = 0;
  1190. NewEntryCopy.Time.QuadPart = 0;
  1191. }
  1192. //
  1193. // If this new entry is subordinate to the most recent old TLN record,
  1194. // use the flag bits from that most recent old TLN record.
  1195. //
  1196. if ( OldTlnPrefix != NULL &&
  1197. NetpIsSubordinate( &NewEntryCopy.ForestTrustData.TopLevelName,
  1198. &OldTlnPrefix->ForestTrustData.TopLevelName,
  1199. FALSE ) ) {
  1200. //
  1201. // If the old TLN was disabled by the admin,
  1202. // so should the new entry.
  1203. //
  1204. if ( OldTlnPrefix->Flags & LSA_TLN_DISABLED_ADMIN ) {
  1205. NewEntryCopy.Flags |= LSA_TLN_DISABLED_ADMIN;
  1206. SetTlnNewFlag = FALSE;
  1207. //
  1208. // If the old TLN was enabled,
  1209. // so should the new entry.
  1210. //
  1211. } else if ( (OldTlnPrefix->Flags & LSA_FTRECORD_DISABLED_REASONS) == 0 ) {
  1212. SetTlnNewFlag = FALSE;
  1213. }
  1214. }
  1215. //
  1216. // If the name of the forest is subordinate of or equal to the TLN name,
  1217. // enable the entry.
  1218. //
  1219. if ( NetpIsSubordinate( TrustedDomainName,
  1220. &NewEntryCopy.ForestTrustData.TopLevelName,
  1221. TRUE )) {
  1222. SetTlnNewFlag = FALSE;
  1223. DomainTlnFound = TRUE;
  1224. }
  1225. //
  1226. // If this is a new TLN,
  1227. // mark it as such.
  1228. //
  1229. if ( SetTlnNewFlag ) {
  1230. NewEntryCopy.Flags |= LSA_TLN_DISABLED_NEW;
  1231. }
  1232. //
  1233. // Merge the new entry into the list
  1234. //
  1235. if ( NetpAllocFtinfoEntry2( &FtinfoContext, &NewEntryCopy ) == NULL ) {
  1236. Status = STATUS_NO_MEMORY;
  1237. goto Cleanup;
  1238. }
  1239. //
  1240. // Remember this previous entry for the next iteration.
  1241. //
  1242. PreviousNewEntry = NewEntry;
  1243. }
  1244. }
  1245. }
  1246. //
  1247. // Loop through each list in SID canonical order processing the least entry.
  1248. //
  1249. // This loop handles DOMAIN entries only
  1250. //
  1251. // This is in a separate loop since we want to process domain entries in SID order
  1252. // to ensure the correct disabled bits are merged from the old list even though the
  1253. // DNS domain name changes.
  1254. //
  1255. NewIndex = 0;
  1256. OldIndex = 0;
  1257. PreviousNewEntry = NULL;
  1258. while ( NewIndex < NewForestTrustInfo.RecordCount ||
  1259. OldIndex < OldForestTrustInfo.RecordCount ) {
  1260. //
  1261. // Grab the next entry from each of the sorted arrays
  1262. //
  1263. NetpMergeFtinfoHelper( &NewForestTrustInfo,
  1264. &OldForestTrustInfo,
  1265. &NewIndex,
  1266. &OldIndex,
  1267. &NewEntry,
  1268. &OldEntry,
  1269. &OldFlags,
  1270. NetpCompareFtinfoEntrySid );
  1271. //
  1272. // Ignore the netbios bits for now (We'll get them on the next pass through the data.)
  1273. //
  1274. OldFlags &= ~(LSA_NB_DISABLED_ADMIN|LSA_NB_DISABLED_CONFLICT);
  1275. //
  1276. // Process the old entry
  1277. //
  1278. if ( OldEntry != NULL ) {
  1279. //
  1280. // Don't let the lack of a new entry allow an admin disabled entry to be deleted.
  1281. //
  1282. if ( OldEntry->ForestTrustType == ForestTrustDomainInfo &&
  1283. (OldFlags & LSA_SID_DISABLED_ADMIN) != 0 &&
  1284. NewEntry == NULL ) {
  1285. //
  1286. // Make a copy of the entry to ensure we don't modify the caller's buffer
  1287. //
  1288. LSA_FOREST_TRUST_RECORD OldEntryCopy;
  1289. OldEntryCopy = *OldEntry;
  1290. OldEntryCopy.Flags = OldFlags;
  1291. //
  1292. // Allocate entry.
  1293. //
  1294. // Remember the address of the entry for the netbios pass.
  1295. //
  1296. NetbiosForestTrustInfo.Entries[NetbiosForestTrustInfo.RecordCount] =
  1297. NetpAllocFtinfoEntry2( &FtinfoContext, &OldEntryCopy );
  1298. if ( NetbiosForestTrustInfo.Entries[NetbiosForestTrustInfo.RecordCount] == NULL ) {
  1299. Status = STATUS_NO_MEMORY;
  1300. goto Cleanup;
  1301. }
  1302. NetbiosForestTrustInfo.RecordCount++;
  1303. }
  1304. }
  1305. //
  1306. // Process the new entry
  1307. //
  1308. if ( NewEntry != NULL ) {
  1309. //
  1310. // Handle domain entries
  1311. //
  1312. if ( NewEntry->ForestTrustType == ForestTrustDomainInfo ) {
  1313. LSA_FOREST_TRUST_RECORD NewEntryCopy;
  1314. //
  1315. // Make a copy of the new entry.
  1316. //
  1317. // We modify the entry to get the time and flags right. We don't want
  1318. // to modify the callers buffer.
  1319. //
  1320. NewEntryCopy = *NewEntry;
  1321. //
  1322. // Ignore duplicate new entries
  1323. //
  1324. // If the name of this new entry is subordinate to the previous new entry,
  1325. // then this entry can be quietly dropped.
  1326. //
  1327. // We arbitrarily drop the second entry even though the other fields of the
  1328. // triple might be different.
  1329. //
  1330. if ( PreviousNewEntry != NULL &&
  1331. PreviousNewEntry->ForestTrustType == ForestTrustDomainInfo ) {
  1332. if ( RtlEqualSid( NewEntryCopy.ForestTrustData.DomainInfo.Sid,
  1333. PreviousNewEntry->ForestTrustData.DomainInfo.Sid ) ) {
  1334. continue;
  1335. }
  1336. }
  1337. //
  1338. // Set the flags and timestamp on the new entry.
  1339. //
  1340. // If we're processing an entry from both lists,
  1341. // grab the flags and timestamp from the old entry.
  1342. //
  1343. if ( OldEntry != NULL ) {
  1344. NewEntryCopy.Flags = OldFlags;
  1345. NewEntryCopy.Time = OldEntry->Time;
  1346. //
  1347. // Otherwise indicate that we have no information
  1348. //
  1349. } else {
  1350. NewEntryCopy.Flags = 0;
  1351. NewEntryCopy.Time.QuadPart = 0;
  1352. }
  1353. //
  1354. // Merge the new entry into the list
  1355. //
  1356. // Remember the address of the entry for the netbios pass.
  1357. //
  1358. NetbiosForestTrustInfo.Entries[NetbiosForestTrustInfo.RecordCount] =
  1359. NetpAllocFtinfoEntry2( &FtinfoContext, &NewEntryCopy );
  1360. if ( NetbiosForestTrustInfo.Entries[NetbiosForestTrustInfo.RecordCount] == NULL ) {
  1361. Status = STATUS_NO_MEMORY;
  1362. goto Cleanup;
  1363. }
  1364. NetbiosForestTrustInfo.RecordCount++;
  1365. //
  1366. // Ensure there is a TLN for this domain entry
  1367. //
  1368. if ( !NetpAddTlnFtinfoEntry ( &FtinfoContext,
  1369. &NewEntryCopy.ForestTrustData.DomainInfo.DnsName ) ) {
  1370. Status = STATUS_NO_MEMORY;
  1371. goto Cleanup;
  1372. }
  1373. //
  1374. // Remember this previous entry for the next iteration.
  1375. //
  1376. PreviousNewEntry = NewEntry;
  1377. }
  1378. }
  1379. }
  1380. //
  1381. // Loop through each list in Netbios canonical order processing the least entry.
  1382. //
  1383. // This loop handle the Netbios name in the domain entries.
  1384. //
  1385. // This is in a separate loop since we want to process domain entries in Netbios order
  1386. // to ensure the correct disabled bits are merged from the old list even though the
  1387. // DNS domain name or domain sid changes.
  1388. //
  1389. // This iteration is fundamentally different than the previous two. This iteration
  1390. // uses NetbiosForestTrustInfo as the 'new' array. It is a psuedo ftinfo array that
  1391. // is built as the list of all the domain entries that have been copied into FtinfoContext.
  1392. // So, this iteration simply has to find that pre-existing entry and set the flags
  1393. // appropriately.
  1394. //
  1395. NewIndex = 0;
  1396. OldIndex = 0;
  1397. PreviousNewEntry = NULL;
  1398. while ( NewIndex < NetbiosForestTrustInfo.RecordCount ||
  1399. OldIndex < OldForestTrustInfo.RecordCount ) {
  1400. //
  1401. // Grab the next entry from each of the sorted arrays
  1402. //
  1403. NetpMergeFtinfoHelper( &NetbiosForestTrustInfo,
  1404. &OldForestTrustInfo,
  1405. &NewIndex,
  1406. &OldIndex,
  1407. &NewEntry,
  1408. &OldEntry,
  1409. &OldFlags,
  1410. NetpCompareFtinfoEntryNetbios );
  1411. //
  1412. // Ignore everything except the netbios bits.
  1413. //
  1414. // Everything else was processed on the previous iteration.
  1415. //
  1416. OldFlags &= (LSA_NB_DISABLED_ADMIN|LSA_NB_DISABLED_CONFLICT);
  1417. //
  1418. // This loop preserves the netbios disabled bits.
  1419. // If there is no old entry, there's nothing to preserve.
  1420. //
  1421. if ( OldEntry == NULL ) {
  1422. continue;
  1423. }
  1424. //
  1425. // If there is no new entry,
  1426. // ensure the *admin* disabled bit it preserved anyway.
  1427. //
  1428. if ( NewEntry == NULL ) {
  1429. //
  1430. // Don't let the lack of a new entry allow an admin disabled entry to be deleted.
  1431. //
  1432. // Note that the newly added entry might have a duplicate DNS name or SID.
  1433. //
  1434. if ( OldEntry->ForestTrustType == ForestTrustDomainInfo &&
  1435. (OldFlags & LSA_NB_DISABLED_ADMIN) != 0 ) {
  1436. //
  1437. // Make a copy of the entry to ensure we don't modify the caller's buffer
  1438. //
  1439. LSA_FOREST_TRUST_RECORD OldEntryCopy;
  1440. OldEntryCopy = *OldEntry;
  1441. OldEntryCopy.Flags = OldFlags;
  1442. if ( !NetpAllocFtinfoEntry2( &FtinfoContext, &OldEntryCopy ) ) {
  1443. Status = STATUS_NO_MEMORY;
  1444. goto Cleanup;
  1445. }
  1446. }
  1447. //
  1448. // Copy any netbios disabled bits to the existing new entry.
  1449. //
  1450. } else {
  1451. //
  1452. // The NetbiosForestTrustInfo array only has domain entries.
  1453. // And the entries are equal so both must be domain entries.
  1454. //
  1455. NetpAssert( NewEntry->ForestTrustType == ForestTrustDomainInfo );
  1456. NetpAssert( OldEntry->ForestTrustType == ForestTrustDomainInfo );
  1457. NewEntry->Flags |= OldFlags;
  1458. }
  1459. }
  1460. //
  1461. // Ensure there is a TLN that DomainName is subordinate to
  1462. //
  1463. if ( !DomainTlnFound ) {
  1464. Status = STATUS_INVALID_PARAMETER;
  1465. goto Cleanup;
  1466. }
  1467. //
  1468. // Return the collected entries to the caller.
  1469. //
  1470. *MergedForestTrustInfo = NetpCopyFtinfoContext( &FtinfoContext );
  1471. if ( *MergedForestTrustInfo == NULL ) {
  1472. Status = STATUS_NO_MEMORY;
  1473. goto Cleanup;
  1474. }
  1475. Status = STATUS_SUCCESS;
  1476. Cleanup:
  1477. //
  1478. // Clean FtInfoContext
  1479. //
  1480. NetpCleanFtinfoContext( &FtinfoContext );
  1481. if ( OldForestTrustInfo.Entries != NULL ) {
  1482. RtlFreeHeap( RtlProcessHeap(), 0, OldForestTrustInfo.Entries );
  1483. }
  1484. if ( NewForestTrustInfo.Entries != NULL ) {
  1485. RtlFreeHeap( RtlProcessHeap(), 0, NewForestTrustInfo.Entries );
  1486. }
  1487. if ( NetbiosForestTrustInfo.Entries != NULL ) {
  1488. RtlFreeHeap( RtlProcessHeap(), 0, NetbiosForestTrustInfo.Entries );
  1489. }
  1490. return Status;
  1491. }