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.

11396 lines
318 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. dbftrust.cxx
  5. Abstract:
  6. LSA Forest Trust Manager - Routines for managing forest trust information
  7. These routines manipulate information associated with the forest trust
  8. attribute of trusted domain objects
  9. --*/
  10. extern "C" {
  11. #include <lsapch2.h>
  12. #include "dbp.h"
  13. #include <ntdsapip.h>
  14. }
  15. #include <smbgtpt.h>
  16. #include <wmistr.h>
  17. #include <evntrace.h>
  18. #include <lsawmi.h>
  19. #include "dbftrust.h"
  20. #include <dnsapi.h>
  21. #include <ftnfoctx.h>
  22. #include <malloc.h>
  23. #include <alloca.h>
  24. //
  25. // Blob version # (in case we want to overhaul the format entirely at a later time
  26. //
  27. #define LSAP_FOREST_TRUST_BLOB_VERSION_1 (( ULONG ) 1)
  28. #define LSAP_FOREST_TRUST_BLOB_VERSION LSAP_FOREST_TRUST_BLOB_VERSION_1
  29. //
  30. // To prevent forest trust blobs of large size, number of records must be
  31. // smaller than MAX_RECORDS_IN_FOREST_TRUST_INFO
  32. //
  33. #define MAX_RECORDS_IN_FOREST_TRUST_INFO 4000
  34. //
  35. // Forest trust cache debug-only statistics
  36. //
  37. #if DBG
  38. DWORD FTCache::sm_TdoEntries = 0;
  39. DWORD FTCache::sm_TlnEntries = 0;
  40. DWORD FTCache::sm_DomainInfoEntries = 0;
  41. DWORD FTCache::sm_BinaryEntries = 0;
  42. DWORD FTCache::sm_TlnKeys = 0;
  43. DWORD FTCache::sm_SidKeys = 0;
  44. DWORD FTCache::sm_DnsNameKeys = 0;
  45. DWORD FTCache::sm_NetbiosNameKeys = 0;
  46. #endif
  47. //
  48. // DS notification handles
  49. //
  50. DWORD XrefNotificationHandle = NULL;
  51. DWORD UpnSuffixNotificationHandle = NULL;
  52. ///////////////////////////////////////////////////////////////////////////////
  53. //
  54. // Helper routines
  55. //
  56. ///////////////////////////////////////////////////////////////////////////////
  57. template<class T>
  58. BOOLEAN
  59. XOR( const T& t1, const T& t2 )
  60. {
  61. return ( !t1 != !t2 );
  62. }
  63. USHORT
  64. DnsNameComponents(
  65. IN const UNICODE_STRING * const Name
  66. )
  67. /*++
  68. Routine Description:
  69. Counts the number of components of a DNS name
  70. Arguments:
  71. Name something of the form "NY.acme.com"
  72. Returns:
  73. Number of components (at least 1)
  74. --*/
  75. {
  76. USHORT Result = 1;
  77. USHORT Index;
  78. ASSERT( Name );
  79. ASSERT( Name->Length > 0 );
  80. ASSERT( Name->Buffer != NULL );
  81. for ( Index = 0 ; Index <= Name->Length ; Index += sizeof( WCHAR )) {
  82. if ( Name->Buffer[Index / sizeof( WCHAR )] == L'.' ) {
  83. Result += 1;
  84. }
  85. }
  86. return Result;
  87. }
  88. void
  89. NextDnsComponent(
  90. IN UNICODE_STRING * Name
  91. )
  92. /*++
  93. Routine Description:
  94. Changes the given name to point to the next component of a DNS name.
  95. The Buffer component of the name must NOT be dynamically allocated,
  96. since this code will change the Buffer pointer.
  97. The name must have at least two components, else an assert will fire.
  98. Arguments:
  99. Name name to modify
  100. Returns:
  101. Modifies the Name parameter passed in; asserts if input invalid
  102. --*/
  103. {
  104. USHORT Index;
  105. BOOLEAN Found = FALSE;
  106. ASSERT( Name );
  107. ASSERT( Name->Length > 0 );
  108. ASSERT( Name->Buffer != NULL );
  109. for ( Index = 0 ; Index < Name->Length ; Index += sizeof( WCHAR )) {
  110. if ( Name->Buffer[Index / sizeof( WCHAR )] == L'.' ) {
  111. Found = TRUE;
  112. Index += sizeof( WCHAR );
  113. break;
  114. }
  115. }
  116. //
  117. // Somebody else should take care of passing valid data to this routine
  118. //
  119. ASSERT( !Found || Index < Name->Length );
  120. Name->Buffer += Index / sizeof( WCHAR );
  121. Name->Length -= Index;
  122. Name->MaximumLength -= Index;
  123. ASSERT( Found || Name->Length == 0 );
  124. return;
  125. }
  126. BOOLEAN
  127. IsSubordinate(
  128. IN const UNICODE_STRING * Subordinate,
  129. IN const UNICODE_STRING * Superior
  130. )
  131. /*++
  132. Routine Description:
  133. Determines if Subordinate string is indeed subordinate to Superior
  134. For example, "NY.acme.com" is subordinate to "acme.com", but
  135. "NY.acme.com" is NOT subordinate to "me.com" or "NY.acme.com"
  136. Arguments:
  137. Subordinate name to test for subordinate status
  138. Superior name to test for superior status
  139. Returns:
  140. TRUE is Subordinate is subordinate to Superior
  141. FALSE otherwise
  142. --*/
  143. {
  144. USHORT SubIndex, SupIndex;
  145. UNICODE_STRING Temp;
  146. ASSERT( Subordinate && Subordinate->Buffer );
  147. ASSERT( Superior && Superior->Buffer );
  148. ASSERT( LsapValidateLsaUnicodeString( Subordinate ));
  149. ASSERT( LsapValidateLsaUnicodeString( Superior ));
  150. //
  151. // A subordinate name must be longer than the superior name
  152. //
  153. if ( Subordinate->Length <= Superior->Length ) {
  154. return FALSE;
  155. }
  156. //
  157. // Subordinate name must be separated from the superior part by a period
  158. //
  159. if ( Subordinate->Buffer[( Subordinate->Length - Superior->Length ) / sizeof( WCHAR ) - 1] != L'.' ) {
  160. return FALSE;
  161. }
  162. //
  163. // The last part of two names must match exactly (but not case sensitively)
  164. //
  165. Temp = *Subordinate;
  166. Temp.Buffer += ( Subordinate->Length - Superior->Length ) / sizeof( WCHAR );
  167. Temp.Length = Superior->Length;
  168. Temp.MaximumLength = Temp.Length;
  169. if ( !RtlEqualUnicodeString( &Temp, Superior, TRUE )) {
  170. return FALSE;
  171. }
  172. return TRUE;
  173. }
  174. ///////////////////////////////////////////////////////////////////////////////
  175. //
  176. // Memory management code
  177. //
  178. ///////////////////////////////////////////////////////////////////////////////
  179. #define FtcAllocate( size ) MIDL_user_allocate( size )
  180. #define FtcFree( buffer ) MIDL_user_free( buffer )
  181. PVOID
  182. FtcReallocate(
  183. IN OPTIONAL void * OldPointer,
  184. IN size_t OldByteCount,
  185. IN size_t NewByteCount
  186. )
  187. {
  188. void * Result = MIDL_user_allocate( NewByteCount );
  189. if ( Result == NULL ) {
  190. return NULL;
  191. }
  192. if ( OldPointer != NULL ) {
  193. RtlCopyMemory( Result, OldPointer, OldByteCount );
  194. MIDL_user_free( OldPointer );
  195. }
  196. return Result;
  197. }
  198. BOOLEAN
  199. FtcCopySid(
  200. IN PSID * Destination,
  201. IN PSID Source
  202. )
  203. /*++
  204. Routine Description:
  205. Allocates and fills in a copy of a given SID
  206. Arguments:
  207. Destination address of destination SID
  208. Source source SID
  209. Returns:
  210. FALSE if operation failed (out of memory)
  211. TRUE otherwise
  212. --*/
  213. {
  214. ULONG SidLength;
  215. ASSERT( Destination );
  216. if ( Source == NULL ) {
  217. *Destination = NULL;
  218. return TRUE;
  219. }
  220. SidLength = RtlLengthSid( Source );
  221. *Destination = FtcAllocate( SidLength );
  222. if ( *Destination == NULL ) {
  223. return FALSE;
  224. }
  225. RtlCopySid(
  226. SidLength,
  227. *Destination,
  228. Source
  229. );
  230. return TRUE;
  231. }
  232. BOOLEAN
  233. FtcCopyUnicodeString(
  234. IN UNICODE_STRING * Destination,
  235. IN UNICODE_STRING * Source,
  236. IN PWSTR Buffer = NULL
  237. )
  238. /*++
  239. Routine Description:
  240. Copies the contents of one Unicode string to another
  241. Arguments:
  242. Destination destination string
  243. Source source string
  244. Buffer (optional) address of the buffer for destination data
  245. Returns:
  246. FALSE if operation failed (out of memory)
  247. TRUE otherwise
  248. --*/
  249. {
  250. ASSERT( Destination );
  251. ASSERT( Source && LsapValidateLsaUnicodeString( Source ));
  252. if ( Buffer != NULL && Source->Length > 0 ) {
  253. Destination->Buffer = Buffer;
  254. } else if ( Source->Length > 0 ) {
  255. Destination->Buffer = ( PWSTR )FtcAllocate( Source->Length + sizeof( WCHAR ));
  256. if ( Destination->Buffer == NULL ) {
  257. return FALSE;
  258. }
  259. } else {
  260. Destination->Buffer = NULL;
  261. }
  262. Destination->MaximumLength = Source->Length + sizeof( WCHAR );
  263. RtlCopyUnicodeString(
  264. Destination,
  265. Source
  266. );
  267. return TRUE;
  268. }
  269. void
  270. LsapFreeForestTrustInfo(
  271. IN LSA_FOREST_TRUST_INFORMATION * ForestTrustInfo
  272. )
  273. /*++
  274. Routine Description:
  275. Deallocates memory taken up by the ForestTrustInfo structure
  276. Arguments:
  277. ForestTrustInfo structure to free
  278. Returns:
  279. Nothing
  280. --*/
  281. {
  282. ULONG i;
  283. if ( ForestTrustInfo == NULL ) {
  284. return;
  285. }
  286. i = ForestTrustInfo->RecordCount;
  287. while ( i > 0 ) {
  288. LSA_FOREST_TRUST_RECORD * Record = ForestTrustInfo->Entries[--i];
  289. if ( Record == NULL ) {
  290. continue;
  291. }
  292. switch ( Record->ForestTrustType ) {
  293. case ForestTrustTopLevelName:
  294. case ForestTrustTopLevelNameEx:
  295. FtcFree( Record->ForestTrustData.TopLevelName.Buffer );
  296. break;
  297. case ForestTrustDomainInfo:
  298. FtcFree( Record->ForestTrustData.DomainInfo.Sid );
  299. FtcFree( Record->ForestTrustData.DomainInfo.DnsName.Buffer );
  300. FtcFree( Record->ForestTrustData.DomainInfo.NetbiosName.Buffer );
  301. break;
  302. default:
  303. FtcFree( Record->ForestTrustData.Data.Buffer );
  304. break;
  305. }
  306. FtcFree( Record );
  307. }
  308. FtcFree( ForestTrustInfo->Entries );
  309. ForestTrustInfo->RecordCount = 0;
  310. ForestTrustInfo->Entries = NULL;
  311. return;
  312. }
  313. void
  314. LsapFreeCollisionInfo(
  315. IN OUT PLSA_FOREST_TRUST_COLLISION_INFORMATION * CollisionInfo
  316. )
  317. /*++
  318. Routine Description:
  319. Deallocates memory taken up by the CollisionInfo structure
  320. Arguments:
  321. CollisionInfo structure to free
  322. Returns:
  323. Nothing
  324. --*/
  325. {
  326. ASSERT( CollisionInfo );
  327. if ( *CollisionInfo == NULL ) {
  328. return;
  329. }
  330. ULONG i = (*CollisionInfo)->RecordCount;
  331. while ( i > 0 ) {
  332. LSA_FOREST_TRUST_COLLISION_RECORD * Record = (*CollisionInfo)->Entries[--i];
  333. if ( Record == NULL ) {
  334. continue;
  335. }
  336. switch ( Record->Type ) {
  337. case CollisionTdo:
  338. FtcFree( Record->Name.Buffer );
  339. break;
  340. default:
  341. ASSERT( FALSE ); // NYI
  342. }
  343. FtcFree( Record );
  344. }
  345. FtcFree( (*CollisionInfo)->Entries );
  346. FtcFree( *CollisionInfo );
  347. *CollisionInfo = NULL;
  348. return;
  349. }
  350. PVOID
  351. NTAPI
  352. FtcAllocateRoutine(
  353. struct _RTL_AVL_TABLE * Table,
  354. CLONG ByteSize
  355. )
  356. {
  357. UNREFERENCED_PARAMETER( Table );
  358. return RtlAllocateHeap( RtlProcessHeap(), 0, ByteSize );
  359. }
  360. void
  361. NTAPI
  362. FtcFreeRoutine(
  363. struct _RTL_AVL_TABLE * Table,
  364. PVOID Buffer
  365. )
  366. {
  367. UNREFERENCED_PARAMETER( Table );
  368. RtlFreeHeap( RtlProcessHeap(), 0, Buffer );
  369. }
  370. ///////////////////////////////////////////////////////////////////////////////
  371. //
  372. // Comparison and matching routines
  373. //
  374. ///////////////////////////////////////////////////////////////////////////////
  375. template<class T>
  376. inline
  377. RTL_GENERIC_COMPARE_RESULTS
  378. FtcGenericCompare(
  379. IN const T& a,
  380. IN const T& b
  381. )
  382. /*++
  383. Routine Description:
  384. Compares two values and returns one of
  385. GenericEqual
  386. GenericGreaterThan
  387. GenericLessThan
  388. Arguments:
  389. a, b numbers to compare
  390. --*/
  391. {
  392. if ( a < b ) {
  393. return GenericLessThan;
  394. } else if ( a > b ) {
  395. return GenericGreaterThan;
  396. } else {
  397. return GenericEqual;
  398. }
  399. }
  400. inline
  401. RTL_GENERIC_COMPARE_RESULTS
  402. FtcGenericCompareMemory(
  403. IN BYTE * Buffer1,
  404. IN BYTE * Buffer2,
  405. IN ULONG Length
  406. )
  407. /*++
  408. Routine Description:
  409. Compares two buffers and returns one of
  410. GenericEqual
  411. GenericGreaterThan
  412. GenericLessThan
  413. Arguments:
  414. Buffer1, Buffer2 buffers to compare
  415. Length length of buffers
  416. --*/
  417. {
  418. RTL_GENERIC_COMPARE_RESULTS Result = GenericEqual;
  419. for ( ULONG i = 0 ; i < Length ; i++ ) {
  420. const BYTE& b1 = Buffer1[i];
  421. const BYTE& b2 = Buffer2[i];
  422. if ( b1 == b2 ) {
  423. continue;
  424. } else if ( b1 < b2 ) {
  425. Result = GenericLessThan;
  426. } else {
  427. Result = GenericGreaterThan;
  428. }
  429. break;
  430. }
  431. return Result;
  432. }
  433. RTL_GENERIC_COMPARE_RESULTS
  434. NTAPI
  435. SidCompareRoutine(
  436. struct _RTL_AVL_TABLE * Table,
  437. PVOID FirstStruct,
  438. PVOID SecondStruct
  439. )
  440. /*++
  441. Routine description:
  442. SID comparison callback for AVL tree management
  443. Arguments:
  444. Table table for which this comparison takes place (ignored)
  445. FirstStruct, SecondStruct points to SID*'s to compare
  446. Returns:
  447. equal/greater-than/less-than
  448. NOTE:
  449. 1. the code relies on the fact that SID* is the first entry inside the
  450. SID_KEY structure. this way, a pointer to a SID* can be passed
  451. to AVL management routines (Lookup/Insert/Delete)
  452. 2. this is the same code as RtlEqualSid, except it returns
  453. RTL_GENERIC_COMPARE_RESULTS
  454. --*/
  455. {
  456. SID *Sid1, *Sid2;
  457. RTL_GENERIC_COMPARE_RESULTS Result;
  458. PSID_IDENTIFIER_AUTHORITY Authority1, Authority2;
  459. DWORD DomainSubAuthCount1, DomainSubAuthCount2;
  460. ULONG i;
  461. UNREFERENCED_PARAMETER( Table );
  462. ASSERT( FirstStruct );
  463. ASSERT( SecondStruct );
  464. Sid1 = *( PISID * )FirstStruct;
  465. Sid2 = *( PISID * )SecondStruct;
  466. ASSERT( Sid1 && RtlValidSid( Sid1 ));
  467. ASSERT( Sid2 && RtlValidSid( Sid2 ));
  468. if ( GenericEqual != ( Result = FtcGenericCompare<UCHAR>(
  469. Sid1->Revision,
  470. Sid2->Revision ))) {
  471. return Result;
  472. } else if ( GenericEqual != ( Result = FtcGenericCompare<UCHAR>(
  473. *RtlSubAuthorityCountSid( Sid1 ),
  474. *RtlSubAuthorityCountSid( Sid2 )))) {
  475. return Result;
  476. } else {
  477. return FtcGenericCompareMemory(
  478. ( BYTE * )Sid1,
  479. ( BYTE * )Sid2,
  480. RtlLengthSid( Sid1 )
  481. );
  482. }
  483. }
  484. RTL_GENERIC_COMPARE_RESULTS
  485. NTAPI
  486. UnicodeStringCompareRoutine(
  487. struct _RTL_AVL_TABLE * Table,
  488. PVOID FirstStruct,
  489. PVOID SecondStruct
  490. )
  491. /*++
  492. Routine Description:
  493. Unicode string comparison routine for AVL tables
  494. Arguments:
  495. Table Table used in comparison (ignored)
  496. FirstStruct Pointer to first unicode string
  497. SecondStruct Pointer to second unicode string
  498. Returns:
  499. equal/greater-than/less-than
  500. --*/
  501. {
  502. INT Result;
  503. UNICODE_STRING *String1, *String2;
  504. UNREFERENCED_PARAMETER( Table );
  505. ASSERT( FirstStruct );
  506. ASSERT( SecondStruct );
  507. String1 = ( UNICODE_STRING * )FirstStruct;
  508. String2 = ( UNICODE_STRING * )SecondStruct;
  509. Result = RtlCompareUnicodeString(
  510. String1,
  511. String2,
  512. TRUE
  513. );
  514. if ( Result < 0 ) {
  515. return GenericLessThan;
  516. } else if ( Result > 0 ) {
  517. return GenericGreaterThan;
  518. } else {
  519. return GenericEqual;
  520. }
  521. }
  522. ///////////////////////////////////////////////////////////////////////////////
  523. //
  524. // Global forest trust cache object
  525. //
  526. ///////////////////////////////////////////////////////////////////////////////
  527. FTCache * g_FTCache = NULL;
  528. ///////////////////////////////////////////////////////////////////////////////
  529. //
  530. // Validation code
  531. //
  532. ///////////////////////////////////////////////////////////////////////////////
  533. BOOLEAN
  534. LsapValidateForestTrustInfo(
  535. IN LSA_FOREST_TRUST_INFORMATION * ForestTrustInfo
  536. )
  537. /*++
  538. Routine Description:
  539. Runs a validation algorithm on the ForestTrustInfo structure passed in.
  540. Strips trailing periods from names where appropriate.
  541. Arguments:
  542. ForestTrustInfo data to validate
  543. Returns:
  544. TRUE if ForestTrustInfo checks out, FALSE otherwise
  545. --*/
  546. {
  547. ULONG i;
  548. if ( ForestTrustInfo == NULL ) {
  549. return TRUE;
  550. }
  551. if ( ForestTrustInfo->RecordCount > 0 &&
  552. ForestTrustInfo->Entries == NULL ) {
  553. LsapDsDebugOut(( DEB_FTINFO, "LsapValidateForestTrustInfo: ForestTrustInfo->Entries is NULL (%s:%d)\n", __FILE__, __LINE__ ));
  554. return FALSE;
  555. }
  556. for ( i = 0 ; i < ForestTrustInfo->RecordCount ; i++ ) {
  557. LSA_FOREST_TRUST_RECORD * Record;
  558. Record = ForestTrustInfo->Entries[i];
  559. if ( Record == NULL ) {
  560. LsapDsDebugOut(( DEB_FTINFO, "LsapValidateForestTrustInfo: Record %d is invalid (%s:%d)\n", i, __FILE__, __LINE__ ));
  561. return FALSE;
  562. }
  563. switch ( Record->ForestTrustType ) {
  564. case ForestTrustTopLevelName:
  565. case ForestTrustTopLevelNameEx: {
  566. BOOLEAN Valid;
  567. if ( !LsapValidateLsaUnicodeString( &Record->ForestTrustData.TopLevelName )) {
  568. LsapDsDebugOut(( DEB_FTINFO, "LsapValidateForestTrustInfo: Record %d is invalid (%s:%d)\n", i, __FILE__, __LINE__ ));
  569. return FALSE;
  570. }
  571. //
  572. // DNS names have additional tests applied to them
  573. //
  574. LsapValidateDnsName(( UNICODE_STRING * )&Record->ForestTrustData.TopLevelName, &Valid );
  575. if ( !Valid ) {
  576. LsapDsDebugOut(( DEB_FTINFO, "LsapValidateForestTrustInfo: Record %d is invalid (%s:%d)\n", i, __FILE__, __LINE__ ));
  577. return FALSE;
  578. }
  579. //
  580. // DNS names must have their trailing period stripped. Now is a good time
  581. //
  582. LsapRemoveTrailingDot(( UNICODE_STRING * )&Record->ForestTrustData.TopLevelName, FALSE );
  583. //
  584. // Exclusion entries must have more than one DNS name component
  585. // (e.g. "acme.com" is valid but "acme" is not)
  586. //
  587. if ( Record->ForestTrustType == ForestTrustTopLevelNameEx &&
  588. DnsNameComponents( &Record->ForestTrustData.TopLevelName ) < 2 ) {
  589. LsapDsDebugOut(( DEB_FTINFO, "LsapValidateForestTrustInfo: Record %d is invalid (%s:%d)\n", i, __FILE__, __LINE__ ));
  590. return FALSE;
  591. }
  592. break;
  593. }
  594. case ForestTrustDomainInfo: {
  595. //
  596. // ISSUE-2000/07/28-markpu
  597. // are NULL SIDs allowed?
  598. //
  599. BYTE DomainSid[SECURITY_MAX_SID_SIZE];
  600. DWORD cbSid = sizeof( DomainSid );
  601. BOOLEAN Valid;
  602. if ( !RtlValidSid(( SID * )Record->ForestTrustData.DomainInfo.Sid ) ||
  603. !LsapValidateLsaUnicodeString( &Record->ForestTrustData.DomainInfo.DnsName ) ||
  604. !LsapValidateLsaUnicodeString( &Record->ForestTrustData.DomainInfo.NetbiosName )) {
  605. LsapDsDebugOut(( DEB_FTINFO, "LsapValidateForestTrustInfo: Record %d is invalid (%s:%d)\n", i, __FILE__, __LINE__ ));
  606. return FALSE;
  607. }
  608. //
  609. // SIDs passed in should be valid domain SIDs
  610. //
  611. if ( FALSE == GetWindowsAccountDomainSid(
  612. ( SID * )Record->ForestTrustData.DomainInfo.Sid,
  613. ( PSID )DomainSid,
  614. &cbSid )) {
  615. ASSERT( GetLastError() != ERROR_INVALID_SID ); // RtlValidSid check already performed
  616. LsapDsDebugOut(( DEB_FTINFO, "LsapValidateForestTrustInfo: Record %d is invalid, Error 0x%lx (%s:%d)\n", i, GetLastError(), __FILE__, __LINE__ ));
  617. return FALSE;
  618. } else {
  619. //
  620. // For domain SIDs, GetWindowsAccountDomainSid returns a SID equal to the one passed in.
  621. // If the two SIDs are not equal, the SID passed in is not a true domain SID
  622. //
  623. if ( !RtlEqualSid(
  624. ( PSID )DomainSid,
  625. ( PSID )Record->ForestTrustData.DomainInfo.Sid )) {
  626. LsapDsDebugOut(( DEB_FTINFO, "LsapValidateForestTrustInfo: Record %d is invalid (%s:%d)\n", i, __FILE__, __LINE__ ));
  627. return FALSE;
  628. }
  629. }
  630. //
  631. // DNS and NetBIOS names have additional tests applied to them
  632. //
  633. if ( Record->ForestTrustData.DomainInfo.NetbiosName.Length > 0 ) {
  634. LsapValidateNetbiosName(( UNICODE_STRING * )&Record->ForestTrustData.DomainInfo.NetbiosName, &Valid );
  635. if ( !Valid ) {
  636. LsapDsDebugOut(( DEB_FTINFO, "LsapValidateForestTrustInfo: Record %d is invalid (%s:%d)\n", i, __FILE__, __LINE__ ));
  637. return FALSE;
  638. }
  639. }
  640. LsapValidateDnsName(( UNICODE_STRING * )&Record->ForestTrustData.DomainInfo.DnsName, &Valid );
  641. if ( !Valid ) {
  642. LsapDsDebugOut(( DEB_FTINFO, "LsapValidateForestTrustInfo: Record %d is invalid (%s:%d)\n", i, __FILE__, __LINE__ ));
  643. return FALSE;
  644. }
  645. //
  646. // DNS names must have their trailing period stripped. Now is a good time
  647. //
  648. LsapRemoveTrailingDot(( UNICODE_STRING * )&Record->ForestTrustData.DomainInfo.DnsName, FALSE );
  649. break;
  650. }
  651. default:
  652. //
  653. // ISSUE-2000/07/21-markpu
  654. // add some binary blob checking
  655. //
  656. break;
  657. }
  658. }
  659. return TRUE;
  660. }
  661. ///////////////////////////////////////////////////////////////////////////////
  662. //
  663. // C Wrappers around the FTCache class
  664. //
  665. ///////////////////////////////////////////////////////////////////////////////
  666. NTSTATUS
  667. LsapForestTrustCacheInitialize()
  668. {
  669. NTSTATUS Status;
  670. LsapDsDebugOut(( DEB_FTINFO, "Forest trust cache being initialized\n" ));
  671. ASSERT( g_FTCache == NULL );
  672. g_FTCache = new FTCache;
  673. if ( g_FTCache == NULL ) {
  674. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapForestTrustCacheInitialize (%s:%d)\n", __FILE__, __LINE__ ));
  675. return STATUS_INSUFFICIENT_RESOURCES;
  676. }
  677. Status = g_FTCache->Initialize();
  678. if ( !NT_SUCCESS( Status )) {
  679. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInitialize: FTCache::Initialize returned 0x%x\n", Status ));
  680. delete g_FTCache;
  681. g_FTCache = NULL;
  682. }
  683. return Status;
  684. }
  685. inline void
  686. LsapForestTrustCacheSetLocalValid()
  687. {
  688. LsapDsDebugOut(( DEB_FTINFO, "Forest trust cache set \"local valid\"\n" ));
  689. ASSERT( LsapDbIsLockedTrustedDomainList());
  690. g_FTCache->SetLocalValid();
  691. }
  692. inline void
  693. LsapForestTrustCacheSetExternalValid()
  694. {
  695. LsapDsDebugOut(( DEB_FTINFO, "Forest trust cache set \"external valid\"\n" ));
  696. ASSERT( LsapDbIsLockedTrustedDomainList());
  697. g_FTCache->SetExternalValid();
  698. }
  699. inline void
  700. LsapForestTrustCacheSetInvalid()
  701. {
  702. LsapDsDebugOut(( DEB_FTINFO, "Forest trust cache set \"invalid\"\n" ));
  703. ASSERT( LsapDbIsLockedTrustedDomainList());
  704. g_FTCache->SetInvalid();
  705. }
  706. inline BOOLEAN
  707. LsapForestTrustCacheIsLocalValid()
  708. {
  709. ASSERT( LsapDbIsLockedTrustedDomainList());
  710. return g_FTCache->IsLocalValid();
  711. }
  712. inline BOOLEAN
  713. LsapForestTrustCacheIsExternalValid()
  714. {
  715. ASSERT( LsapDbIsLockedTrustedDomainList());
  716. return g_FTCache->IsExternalValid();
  717. }
  718. NTSTATUS
  719. LsapForestTrustCacheInsert(
  720. IN UNICODE_STRING * TrustedDomainName,
  721. IN OPTIONAL PSID TrustedDomainSid,
  722. IN LSA_FOREST_TRUST_INFORMATION * ForestTrustInfo,
  723. IN BOOLEAN LocalForestEntry
  724. )
  725. /*++
  726. Routine Description:
  727. Inserts forest trust information for particular trusted domain
  728. name into the cache.
  729. This routine gets called as a result of
  730. * the system preloading the cache or
  731. * replication traffic
  732. As a result, the data coming in can not be assumed to be collision-free.
  733. Collisions are resolved, and on the root domain PDC, the resulting forest
  734. trust data is written back out to the DS.
  735. Arguments:
  736. TrustedDomainName name of the TDO
  737. TrustedDomainSid SID of the TDO (can be NULL)
  738. ForestTrustInfo forest trust information
  739. LocalForestEntry does this data correspond to the local forest?
  740. Returns:
  741. STATUS_SUCCESS success
  742. STATUS_INTERNAL_ERROR
  743. STATUS_INSUFFICIENT_RESOURCES out of memory
  744. STATUS_INVALID_PARAMETER data passed in is inconsistent
  745. --*/
  746. {
  747. NTSTATUS Status;
  748. FTCache::TDO_ENTRY TdoEntryOld = {0};
  749. FTCache::TDO_ENTRY * TdoEntryNew = NULL;
  750. FTCache::CONFLICT_PAIR * ConflictPairs = NULL;
  751. ULONG ConflictPairsTotal = 0;
  752. BOOLEAN ObjectReferenced = FALSE;
  753. DOMAIN_SERVER_ROLE ServerRole = DomainServerRoleBackup;
  754. ASSERT( LsapDbIsLockedTrustedDomainList());
  755. //
  756. // Forest trust is not enabled until .NET forest mode is entered
  757. //
  758. // Local forest entries are allowed in always (the cache always needs to
  759. // contain information about the local forest)
  760. //
  761. if ( !LsapDbNoMoreWin2KForest() && !LocalForestEntry ) {
  762. return STATUS_SUCCESS;
  763. }
  764. LsarpReturnCheckSetup();
  765. LsapEnterFunc( "LsapForestTrustCacheInsert" );
  766. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsert called\n" ));
  767. if ( !LsapValidateForestTrustInfo( ForestTrustInfo )) {
  768. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustCacheInsert (%s:%d)\n", __FILE__, __LINE__ ));
  769. Status = STATUS_INVALID_PARAMETER;
  770. goto Error;
  771. }
  772. Status = g_FTCache->Insert(
  773. TrustedDomainName,
  774. TrustedDomainSid,
  775. ForestTrustInfo,
  776. LocalForestEntry,
  777. &TdoEntryOld,
  778. &TdoEntryNew,
  779. &ConflictPairs,
  780. &ConflictPairsTotal
  781. );
  782. if ( !NT_SUCCESS( Status )) {
  783. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsert: FTCache::Insert returned 0x%x\n", Status ));
  784. goto Error;
  785. }
  786. if ( ConflictPairs ) {
  787. g_FTCache->ReconcileConflictPairs(
  788. NULL, // let the winner be determined algorithmically
  789. ConflictPairs,
  790. ConflictPairsTotal
  791. );
  792. }
  793. //
  794. // If we are in the root domain, there is a chance
  795. // that this DC is a PDC and thus reconciled changes
  796. // need to be written out
  797. //
  798. if ( ConflictPairs && // conflicts were detected
  799. LsapDbDcInRootDomain() && // this is a root domain DC
  800. LsapSamOpened ) { // SAM is started (a must to call SamI APIs)
  801. //
  802. // Query the server role, PDC/BDC
  803. //
  804. ASSERT( LsapAccountDomainHandle );
  805. Status = SamIQueryServerRole(
  806. LsapAccountDomainHandle,
  807. &ServerRole
  808. );
  809. if ( !NT_SUCCESS(Status)) {
  810. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsert: SamIQueryServerRole returned 0x%x\n", Status ));
  811. goto Error;
  812. }
  813. if ( ServerRole == DomainServerRolePrimary ) {
  814. ULONG TdoNamesCount = 0;
  815. PUNICODE_STRING * TdoNames = NULL;
  816. ULONG i, j;
  817. for ( i = 0 ; i < ConflictPairsTotal ; i++ ) {
  818. PUNICODE_STRING String1 = NULL;
  819. PUNICODE_STRING String2 = NULL;
  820. //
  821. // Get trusted domain names corresponding to conflicting entries
  822. // Local forest entries are excepted -- they do not correspond
  823. // to regular TDOs, always win in conflict reconciliation
  824. // and do not get written out to disk during such reconciliation
  825. //
  826. switch ( ConflictPairs[i].EntryType1 ) {
  827. case ForestTrustTopLevelName:
  828. String1 = ConflictPairs[i].TlnEntry1->TdoEntry->LocalForestEntry ?
  829. NULL :
  830. &ConflictPairs[i].TlnEntry1->TdoEntry->TrustedDomainName;
  831. break;
  832. case ForestTrustDomainInfo:
  833. String1 = ConflictPairs[i].DomainInfoEntry1->TdoEntry->LocalForestEntry ?
  834. NULL :
  835. &ConflictPairs[i].DomainInfoEntry1->TdoEntry->TrustedDomainName;
  836. break;
  837. }
  838. switch ( ConflictPairs[i].EntryType2 ) {
  839. case ForestTrustTopLevelName:
  840. String2 = ConflictPairs[i].TlnEntry2->TdoEntry->LocalForestEntry ?
  841. NULL :
  842. &ConflictPairs[i].TlnEntry2->TdoEntry->TrustedDomainName;
  843. break;
  844. case ForestTrustDomainInfo:
  845. String2 = ConflictPairs[i].DomainInfoEntry2->TdoEntry->LocalForestEntry ?
  846. NULL :
  847. &ConflictPairs[i].DomainInfoEntry2->TdoEntry->TrustedDomainName;
  848. break;
  849. }
  850. //
  851. // No point continuing if neither name can be found
  852. //
  853. if ( !String1 && !String2 ) {
  854. continue;
  855. }
  856. //
  857. // Append the names to the array, uniquely
  858. //
  859. for ( j = 0 ; String1 && j < TdoNamesCount ; j++ ) {
  860. if ( RtlEqualUnicodeString(
  861. String1,
  862. TdoNames[j],
  863. TRUE )) {
  864. break;
  865. }
  866. }
  867. if ( String1 && j == TdoNamesCount ) {
  868. PUNICODE_STRING * TdoNamesT;
  869. TdoNamesT = ( TdoNames ?
  870. ( PUNICODE_STRING * )LocalReAlloc(
  871. TdoNames,
  872. ( TdoNamesCount + 1 ) * sizeof( PUNICODE_STRING ),
  873. 0 ) :
  874. ( PUNICODE_STRING * )LocalAlloc(
  875. 0,
  876. sizeof( PUNICODE_STRING )));
  877. if ( TdoNamesT == NULL ) {
  878. if ( TdoNames ) {
  879. LocalFree( TdoNames );
  880. }
  881. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapForestTrustCacheInsert (%s:%d)\n", __FILE__, __LINE__ ));
  882. Status = STATUS_INSUFFICIENT_RESOURCES;
  883. goto Error;
  884. }
  885. TdoNames = TdoNamesT;
  886. TdoNames[TdoNamesCount] = String1;
  887. TdoNamesCount += 1;
  888. }
  889. for ( j = 0 ; String2 && j < TdoNamesCount ; j++ ) {
  890. if ( RtlEqualUnicodeString(
  891. String2,
  892. TdoNames[j],
  893. TRUE )) {
  894. break;
  895. }
  896. }
  897. if ( String2 && j == TdoNamesCount ) {
  898. PUNICODE_STRING * TdoNamesT;
  899. TdoNamesT = ( TdoNames ?
  900. ( PUNICODE_STRING * )LocalReAlloc(
  901. TdoNames,
  902. ( TdoNamesCount + 1 ) * sizeof( PUNICODE_STRING ),
  903. 0 ) :
  904. ( PUNICODE_STRING * )LocalAlloc(
  905. 0,
  906. sizeof( PUNICODE_STRING )));
  907. if ( TdoNamesT == NULL ) {
  908. if ( TdoNames ) {
  909. LocalFree( TdoNames );
  910. }
  911. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapForestTrustCacheInsert (%s:%d)\n", __FILE__, __LINE__ ));
  912. Status = STATUS_INSUFFICIENT_RESOURCES;
  913. goto Error;
  914. }
  915. TdoNames = TdoNamesT;
  916. TdoNames[TdoNamesCount] = String2;
  917. TdoNamesCount += 1;
  918. }
  919. }
  920. ASSERT( TdoNamesCount > 0 );
  921. ASSERT( TdoNames != NULL );
  922. Status = LsapDbReferenceObject(
  923. LsapPolicyHandle,
  924. 0,
  925. PolicyObject,
  926. TrustedDomainObject,
  927. LSAP_DB_DS_OP_TRANSACTION // no lock acquired (must be done outside the routine)
  928. );
  929. if ( !NT_SUCCESS( Status )) {
  930. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsert: LsapDbReferenceObject returned 0x%x\n", Status ));
  931. LocalFree( TdoNames );
  932. goto Error;
  933. }
  934. ObjectReferenced = TRUE;
  935. //
  936. // Write every affected TDO out to disk
  937. //
  938. for ( i = 0 ; i < TdoNamesCount ; i++ ) {
  939. LSAP_DB_OBJECT_INFORMATION ObjInfo;
  940. LSAP_DB_ATTRIBUTE Attributes[LSAP_DB_ATTRS_INFO_CLASS_DOMAIN];
  941. LSAP_DB_ATTRIBUTE * NextAttribute;
  942. ULONG AttributeCount = 0;
  943. LSAPR_HANDLE TrustedDomainHandle = NULL;
  944. ULONG BlobLength = 0;
  945. BYTE * BlobData = NULL;
  946. FTCache::TDO_ENTRY * TdoEntry;
  947. LSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY * TrustInfoForName;
  948. //
  949. // Get the right name
  950. //
  951. Status = LsapDbLookupNameTrustedDomainListEx(
  952. ( LSAPR_UNICODE_STRING * )TdoNames[i],
  953. &TrustInfoForName
  954. );
  955. if ( !NT_SUCCESS( Status )) {
  956. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsert: LsapDbLookupNameTrustedDomainListEx returned 0x%lx for %wZ (%s:%d)\n", Status, ( UNICODE_STRING * )TrustedDomainName, __FILE__, __LINE__ ));
  957. LocalFree( TdoNames );
  958. goto Error;
  959. }
  960. //
  961. // Build a temporary handle
  962. //
  963. RtlZeroMemory( &ObjInfo, sizeof( ObjInfo ));
  964. ObjInfo.ObjectTypeId = TrustedDomainObject;
  965. ObjInfo.ContainerTypeId = NullObject;
  966. ObjInfo.Sid = NULL;
  967. ObjInfo.DesiredObjectAccess = TRUSTED_SET_AUTH;
  968. InitializeObjectAttributes(
  969. &ObjInfo.ObjectAttributes,
  970. ( UNICODE_STRING * )&TrustInfoForName->TrustInfoEx.Name,
  971. 0L,
  972. LsapPolicyHandle,
  973. NULL
  974. );
  975. //
  976. // Get a handle to the TDO
  977. //
  978. Status = LsapDbOpenObject(
  979. &ObjInfo,
  980. TRUSTED_SET_AUTH,
  981. 0,
  982. &TrustedDomainHandle
  983. );
  984. if ( !NT_SUCCESS( Status )) {
  985. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsert: LsapDbOpenObject returned 0x%x\n", Status ));
  986. LocalFree( TdoNames );
  987. goto Error;
  988. }
  989. //
  990. // Locate the cache entry corresponding to this TDO
  991. //
  992. TdoEntry = ( FTCache::TDO_ENTRY * )RtlLookupElementGenericTableAvl(
  993. &g_FTCache->m_TdoTable,
  994. TdoNames[i]
  995. );
  996. if ( TdoEntry == NULL ) {
  997. //
  998. // What do you mean "not there"???
  999. //
  1000. Status = STATUS_NOT_FOUND;
  1001. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsert: RtlLookupElementGenericTableAvl returned 0x%x\n", Status ));
  1002. ASSERT( FALSE );
  1003. LocalFree( TdoNames );
  1004. LsapDbCloseHandle( TrustedDomainHandle );
  1005. goto Error;
  1006. }
  1007. Status = g_FTCache->MarshalBlob(
  1008. TdoEntry,
  1009. &BlobLength,
  1010. &BlobData
  1011. );
  1012. if ( !NT_SUCCESS( Status )) {
  1013. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsert: FTCache::MarshalBlob returned 0x%x\n", Status ));
  1014. LocalFree( TdoNames );
  1015. LsapDbCloseHandle( TrustedDomainHandle );
  1016. goto Error;
  1017. }
  1018. NextAttribute = Attributes;
  1019. LsapDbInitializeAttributeDs(
  1020. NextAttribute,
  1021. TrDmForT,
  1022. BlobData,
  1023. BlobLength,
  1024. FALSE
  1025. );
  1026. AttributeCount++;
  1027. ASSERT( AttributeCount <= LSAP_DB_ATTRS_INFO_CLASS_DOMAIN );
  1028. //
  1029. // Write the attributes to the DS.
  1030. //
  1031. Status = LsapDbWriteAttributesObject(
  1032. TrustedDomainHandle,
  1033. Attributes,
  1034. AttributeCount
  1035. );
  1036. if ( !NT_SUCCESS( Status )) {
  1037. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsert: LsapDbWriteAttributesObject returned 0x%x\n", Status ));
  1038. LocalFree( TdoNames );
  1039. LsapDbCloseHandle( TrustedDomainHandle );
  1040. FtcFree( BlobData );
  1041. goto Error;
  1042. }
  1043. LsapDbCloseHandle( TrustedDomainHandle );
  1044. FtcFree( BlobData );
  1045. }
  1046. LocalFree( TdoNames );
  1047. }
  1048. }
  1049. Cleanup:
  1050. if ( ObjectReferenced ) {
  1051. Status = LsapDbDereferenceObject(
  1052. &LsapPolicyHandle,
  1053. PolicyObject,
  1054. TrustedDomainObject,
  1055. LSAP_DB_DS_OP_TRANSACTION |
  1056. LSAP_DB_OMIT_REPLICATOR_NOTIFICATION,
  1057. (SECURITY_DB_DELTA_TYPE) 0,
  1058. Status
  1059. );
  1060. }
  1061. //
  1062. // If operation completed successfully on a PDC,
  1063. // audit conflict resolution information here
  1064. //
  1065. if ( NT_SUCCESS( Status ) &&
  1066. ConflictPairs &&
  1067. ServerRole == DomainServerRolePrimary ) {
  1068. g_FTCache->AuditCollisions(
  1069. ConflictPairs,
  1070. ConflictPairsTotal
  1071. );
  1072. }
  1073. if ( TdoEntryOld.RecordCount > 0 ) {
  1074. g_FTCache->PurgeTdoEntry( &TdoEntryOld );
  1075. }
  1076. FtcFree( ConflictPairs );
  1077. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsert returning, Status: 0x%x\n", Status ));
  1078. LsapExitFunc( "LsapForestTrustCacheInsert", Status );
  1079. LsarpReturnPrologue();
  1080. return Status;
  1081. Error:
  1082. ASSERT( !NT_SUCCESS( Status ));
  1083. //
  1084. // Rollback the changes made to the cache
  1085. //
  1086. if ( TdoEntryNew ) {
  1087. g_FTCache->RollbackChanges( TdoEntryNew, &TdoEntryOld );
  1088. TdoEntryNew = NULL;
  1089. }
  1090. goto Cleanup;
  1091. }
  1092. inline NTSTATUS
  1093. LsapForestTrustCacheRemove(
  1094. IN UNICODE_STRING * TrustedDomainName
  1095. )
  1096. {
  1097. ASSERT( LsapDbIsLockedTrustedDomainList());
  1098. return g_FTCache->Remove( TrustedDomainName );
  1099. }
  1100. inline NTSTATUS
  1101. LsapForestTrustCacheRetrieve(
  1102. IN UNICODE_STRING * TrustedDomainName,
  1103. OUT LSA_FOREST_TRUST_INFORMATION * * ForestTrustInfo
  1104. )
  1105. {
  1106. ASSERT( LsapDbIsLockedTrustedDomainList());
  1107. return g_FTCache->Retrieve(
  1108. TrustedDomainName,
  1109. ForestTrustInfo
  1110. );
  1111. }
  1112. NTSTATUS
  1113. LsapAddToCollisionInfo(
  1114. IN OUT PLSA_FOREST_TRUST_COLLISION_INFORMATION * CollisionInfo,
  1115. IN ULONG Index,
  1116. IN LSA_FOREST_TRUST_COLLISION_RECORD_TYPE Type,
  1117. IN ULONG Flags,
  1118. IN OPTIONAL UNICODE_STRING * Name
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. Apends the given index and trusted domain name to the
  1123. provided collision information structure.
  1124. Arguments:
  1125. CollisionInfo structure to append to
  1126. Index new entry's index
  1127. Type type of collision
  1128. Flags new flags set as result of collision
  1129. Name name (only for certain types of collisions)
  1130. Returns:
  1131. STATUS_SUCCESS operation completed successfully
  1132. this routine takes ownership of ForestTrustRecord
  1133. STATUS_INSUFFICIENT_RESOURCES
  1134. --*/
  1135. {
  1136. NTSTATUS Status;
  1137. LSA_FOREST_TRUST_COLLISION_RECORD * CollisionRecord;
  1138. PLSA_FOREST_TRUST_COLLISION_RECORD * EntriesT;
  1139. BOOLEAN CollisionInfoAllocated = FALSE;
  1140. ASSERT( CollisionInfo != NULL );
  1141. //
  1142. // First, see if collision information for this index already exists,
  1143. // and if so, update the existing entry
  1144. //
  1145. if ( *CollisionInfo != NULL ) {
  1146. for ( ULONG i = 0 ; i < (*CollisionInfo)->RecordCount ; i += 1 ) {
  1147. PLSA_FOREST_TRUST_COLLISION_RECORD Record = (*CollisionInfo)->Entries[i];
  1148. if ( Record->Index == Index &&
  1149. Record->Type == Type &&
  1150. (( Name == NULL && Record->Name.Length == 0 ) ||
  1151. ( Name != NULL && RtlEqualUnicodeString(
  1152. Name,
  1153. &Record->Name,
  1154. TRUE )))) {
  1155. //
  1156. // This seems like an additional conflict for the same
  1157. // entry. Just add the new flags into the mix and get out.
  1158. //
  1159. Record->Flags |= Flags;
  1160. return STATUS_SUCCESS;
  1161. }
  1162. }
  1163. }
  1164. CollisionRecord = ( LSA_FOREST_TRUST_COLLISION_RECORD * )
  1165. FtcAllocate( sizeof( LSA_FOREST_TRUST_COLLISION_RECORD ));
  1166. if ( CollisionRecord == NULL ) {
  1167. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapAddToCollisionInfo (%s:%d)\n", __FILE__, __LINE__ ));
  1168. Status = STATUS_INSUFFICIENT_RESOURCES;
  1169. goto Error;
  1170. }
  1171. CollisionRecord->Index = Index;
  1172. CollisionRecord->Type = Type;
  1173. CollisionRecord->Flags = Flags;
  1174. if ( Name != NULL ) {
  1175. if ( FALSE == FtcCopyUnicodeString(
  1176. ( UNICODE_STRING * )&CollisionRecord->Name,
  1177. Name )) {
  1178. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapAddToCollisionInfo (%s:%d)\n", __FILE__, __LINE__ ));
  1179. Status = STATUS_INSUFFICIENT_RESOURCES;
  1180. goto Error;
  1181. }
  1182. }
  1183. if ( *CollisionInfo == NULL ) {
  1184. *CollisionInfo = ( LSA_FOREST_TRUST_COLLISION_INFORMATION * )
  1185. FtcAllocate( sizeof( LSA_FOREST_TRUST_COLLISION_INFORMATION ));
  1186. if ( *CollisionInfo == NULL ) {
  1187. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapAddToCollisionInfo (%s:%d)\n", __FILE__, __LINE__ ));
  1188. Status = STATUS_INSUFFICIENT_RESOURCES;
  1189. goto Error;
  1190. }
  1191. RtlZeroMemory( *CollisionInfo, sizeof( LSA_FOREST_TRUST_COLLISION_INFORMATION ));
  1192. CollisionInfoAllocated = TRUE;
  1193. }
  1194. EntriesT = ( LSA_FOREST_TRUST_COLLISION_RECORD * * )FtcReallocate(
  1195. (*CollisionInfo)->Entries,
  1196. (*CollisionInfo)->RecordCount * sizeof( LSA_FOREST_TRUST_COLLISION_RECORD * ),
  1197. ((*CollisionInfo)->RecordCount + 1) * sizeof( LSA_FOREST_TRUST_COLLISION_RECORD * )
  1198. );
  1199. if ( EntriesT == NULL ) {
  1200. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapAddToCollisionInfo (%s:%d)\n", __FILE__, __LINE__ ));
  1201. Status = STATUS_INSUFFICIENT_RESOURCES;
  1202. goto Error;
  1203. }
  1204. (*CollisionInfo)->Entries = EntriesT;
  1205. (*CollisionInfo)->Entries[(*CollisionInfo)->RecordCount] = CollisionRecord;
  1206. (*CollisionInfo)->RecordCount += 1;
  1207. Status = STATUS_SUCCESS;
  1208. Cleanup:
  1209. return Status;
  1210. Error:
  1211. ASSERT( !NT_SUCCESS( Status ));
  1212. if ( CollisionRecord ) {
  1213. FtcFree( CollisionRecord->Name.Buffer );
  1214. FtcFree( CollisionRecord );
  1215. }
  1216. if ( CollisionInfoAllocated ) {
  1217. FtcFree( *CollisionInfo );
  1218. *CollisionInfo = NULL;
  1219. }
  1220. goto Cleanup;
  1221. }
  1222. ///////////////////////////////////////////////////////////////////////////////
  1223. //
  1224. // FTCache public interface
  1225. //
  1226. ///////////////////////////////////////////////////////////////////////////////
  1227. FTCache::FTCache()
  1228. /*++
  1229. Routine Description:
  1230. FTCache constructor
  1231. Arguments:
  1232. None
  1233. Returns:
  1234. Nothing
  1235. NOTE: FTCache::Initialize() must be called before the object is usable
  1236. --*/
  1237. {
  1238. m_Initialized = FALSE;
  1239. m_LocalValid = FALSE;
  1240. m_ExternalValid = FALSE;
  1241. }
  1242. FTCache::~FTCache()
  1243. /*++
  1244. Routine Description:
  1245. FTCache destructor
  1246. Removes all cache contents as part of the destruction process
  1247. Arguments:
  1248. None
  1249. Returns:
  1250. Nothing
  1251. --*/
  1252. {
  1253. if ( m_Initialized ) {
  1254. Purge();
  1255. }
  1256. }
  1257. NTSTATUS
  1258. FTCache::Initialize()
  1259. /*++
  1260. Routine Description:
  1261. Initializes the forest trust cache.
  1262. The initialized cache is not populated and its Valid
  1263. bit is set to FALSE
  1264. Arguments:
  1265. None
  1266. Returns:
  1267. STATUS_SUCCESS cache initialized successfully
  1268. --*/
  1269. {
  1270. ASSERT( !m_Initialized );
  1271. RtlInitializeGenericTableAvl(
  1272. &m_TdoTable,
  1273. UnicodeStringCompareRoutine,
  1274. FtcAllocateRoutine,
  1275. FtcFreeRoutine,
  1276. NULL
  1277. );
  1278. RtlInitializeGenericTableAvl(
  1279. &m_TopLevelNameTable,
  1280. UnicodeStringCompareRoutine,
  1281. FtcAllocateRoutine,
  1282. FtcFreeRoutine,
  1283. NULL
  1284. );
  1285. RtlInitializeGenericTableAvl(
  1286. &m_DomainSidTable,
  1287. SidCompareRoutine,
  1288. FtcAllocateRoutine,
  1289. FtcFreeRoutine,
  1290. NULL
  1291. );
  1292. RtlInitializeGenericTableAvl(
  1293. &m_DnsNameTable,
  1294. UnicodeStringCompareRoutine,
  1295. FtcAllocateRoutine,
  1296. FtcFreeRoutine,
  1297. NULL
  1298. );
  1299. RtlInitializeGenericTableAvl(
  1300. &m_NetbiosNameTable,
  1301. UnicodeStringCompareRoutine,
  1302. FtcAllocateRoutine,
  1303. FtcFreeRoutine,
  1304. NULL
  1305. );
  1306. m_Initialized = TRUE;
  1307. return STATUS_SUCCESS;
  1308. }
  1309. void
  1310. FTCache::SetInvalid()
  1311. /*++
  1312. Routine Description:
  1313. Sets the cache to the "invalid" state and purges its contents
  1314. Arguments:
  1315. None
  1316. Returns:
  1317. Nothing
  1318. --*/
  1319. {
  1320. //
  1321. // Unregister DS notifications
  1322. //
  1323. if ( XrefNotificationHandle != NULL ||
  1324. UpnSuffixNotificationHandle != NULL ) {
  1325. NTSTATUS Status = 0;
  1326. BOOLEAN CloseTransaction = FALSE;
  1327. //
  1328. // Although we are not going to have a transaction, we need
  1329. // a valid thread state. Therefore we need to call
  1330. // LsapDsInitAllocAsNeededEx
  1331. //
  1332. Status = LsapDsInitAllocAsNeededEx(
  1333. LSAP_DB_READ_ONLY_TRANSACTION |
  1334. LSAP_DB_NO_LOCK |
  1335. LSAP_DB_DS_OP_TRANSACTION,
  1336. TrustedDomainObject,
  1337. &CloseTransaction
  1338. );
  1339. if ( NT_SUCCESS( Status )) {
  1340. if ( XrefNotificationHandle != NULL ) {
  1341. ULONG DirResult;
  1342. DirResult = DirNotifyUnRegister(
  1343. XrefNotificationHandle,
  1344. NULL // DirNotifyUnRegister does not use its second parameter anyway
  1345. );
  1346. ASSERT( 0 == DirResult );
  1347. //
  1348. // Bug 488913:
  1349. // DirNotifyUnRegister doesn't actually start a transaction so,
  1350. // LsapDsContinueTransaction shouldn't be called.
  1351. //
  1352. //
  1353. // Continue the transaction
  1354. //
  1355. // LsapDsContinueTransaction();
  1356. //
  1357. }
  1358. if ( UpnSuffixNotificationHandle != NULL ) {
  1359. ULONG DirResult;
  1360. DirResult = DirNotifyUnRegister(
  1361. UpnSuffixNotificationHandle,
  1362. NULL // DirNotifyUnRegister does not use its second parameter anyway
  1363. );
  1364. ASSERT( 0 == DirResult );
  1365. }
  1366. LsapDsDeleteAllocAsNeededEx(
  1367. LSAP_DB_READ_ONLY_TRANSACTION |
  1368. LSAP_DB_NO_LOCK |
  1369. LSAP_DB_DS_OP_TRANSACTION,
  1370. TrustedDomainObject,
  1371. CloseTransaction
  1372. );
  1373. }
  1374. //
  1375. // Clear the notification handle even if there was an error
  1376. // Got no choice here, really.
  1377. //
  1378. XrefNotificationHandle = NULL;
  1379. UpnSuffixNotificationHandle = NULL;
  1380. }
  1381. //
  1382. // Mark the cache as invalid
  1383. //
  1384. m_LocalValid = FALSE;
  1385. m_ExternalValid = FALSE;
  1386. //
  1387. // And since it's invalid, blow away its contents -- they need to be rebuilt anyway
  1388. //
  1389. Purge();
  1390. }
  1391. NTSTATUS
  1392. FTCache::Insert(
  1393. IN UNICODE_STRING * TrustedDomainName,
  1394. IN OPTIONAL PSID TrustedDomainSid,
  1395. IN LSA_FOREST_TRUST_INFORMATION * ForestTrustInfo,
  1396. IN BOOLEAN LocalForestEntry,
  1397. OUT TDO_ENTRY * TdoEntryOldOut,
  1398. OUT TDO_ENTRY * * TdoEntryNewOut,
  1399. OUT CONFLICT_PAIR * * ConflictPairs,
  1400. OUT ULONG * ConflictPairsTotal
  1401. )
  1402. /*++
  1403. Routine Description:
  1404. Inserts entries corresponding to the given TDO into the cache
  1405. Arguments:
  1406. TrustedDomainName Name of the TDO that the enries correspond to
  1407. TrustedDomainSid Sid of the TDO
  1408. ForestTrustInfo Entries to insert
  1409. LocalForestEntry Does this entry correspond to the local forest?
  1410. TdoEntryOldOut Used to return old TDO entry
  1411. TdoEntryNewOut Used to return new TDO entry
  1412. ConflictPairs Used to return conflict information
  1413. ConflictPairsTotal
  1414. Returns:
  1415. STATUS_SUCCESS Entry added successfully
  1416. STATUS_INSUFFICIENT_RESOURCES Ran out of memory; entry not added
  1417. STATUS_INVALID_PARAMETER Parameters were somehow incorrect
  1418. --*/
  1419. {
  1420. NTSTATUS Status = STATUS_SUCCESS;
  1421. TDO_ENTRY * TdoEntryNew = NULL;
  1422. LIST_ENTRY * ListEntry;
  1423. LARGE_INTEGER CurrentTime;
  1424. ULONG Current;
  1425. ASSERT( m_Initialized );
  1426. if ( TrustedDomainName == NULL ||
  1427. ForestTrustInfo == NULL ||
  1428. TdoEntryNewOut == NULL ||
  1429. TdoEntryOldOut == NULL ||
  1430. ConflictPairs == NULL ||
  1431. ConflictPairsTotal == NULL ) {
  1432. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1433. ASSERT( FALSE ); // should not happen in released code
  1434. return STATUS_INVALID_PARAMETER;
  1435. }
  1436. LsapDsDebugOut((
  1437. DEB_FTINFO,
  1438. "FTCache::Insert called, TDO: %wZ, Entries: %d, Local: %s\n",
  1439. TrustedDomainName,
  1440. ForestTrustInfo->RecordCount,
  1441. LocalForestEntry ? "Yes" : "No"
  1442. ));
  1443. RtlZeroMemory( TdoEntryOldOut, sizeof( TDO_ENTRY ));
  1444. *ConflictPairs = NULL;
  1445. *ConflictPairsTotal = 0;
  1446. #if DBG
  1447. //
  1448. // Debug only: display diagnostic information about what's being inserted
  1449. //
  1450. if ( LsaDsInfoLevel & DEB_FTINFO ) {
  1451. LsapDsDebugOut((
  1452. DEB_FTINFO,
  1453. "\n++++++++++++++++++ FTInfo Record List +++++++++++++++++++\n\n"
  1454. ));
  1455. for ( Current = 0 ; Current < ForestTrustInfo->RecordCount ; Current++ ) {
  1456. LSA_FOREST_TRUST_RECORD * Record = ForestTrustInfo->Entries[Current];
  1457. BOOLEAN Duplicate = FALSE;
  1458. switch ( Record->ForestTrustType ) {
  1459. case ForestTrustTopLevelName:
  1460. case ForestTrustTopLevelNameEx: {
  1461. LsapDsDebugOut((
  1462. DEB_FTINFO,
  1463. "%d. TopLevelName%s: %wZ (%s: %d)\n",
  1464. Current,
  1465. Record->ForestTrustType == ForestTrustTopLevelNameEx ? "Ex" : "",
  1466. &Record->ForestTrustData.TopLevelName,
  1467. Record->Flags ? "Disabled" : "Enabled",
  1468. Record->Flags
  1469. ));
  1470. break;
  1471. }
  1472. case ForestTrustDomainInfo: {
  1473. LsapDsDebugOut((
  1474. DEB_FTINFO,
  1475. "%d. DomainInfo: DNS %wZ, NB %wZ (%s: %d)\n",
  1476. Current,
  1477. &Record->ForestTrustData.DomainInfo.DnsName,
  1478. &Record->ForestTrustData.DomainInfo.NetbiosName,
  1479. Record->Flags ? "Disabled" : "Enabled",
  1480. Record->Flags
  1481. ));
  1482. break;
  1483. }
  1484. default:
  1485. LsapDsDebugOut((
  1486. DEB_FTINFO,
  1487. "%d. Unrecognized type: %d\n",
  1488. Current,
  1489. Record->ForestTrustType
  1490. ));
  1491. break;
  1492. }
  1493. }
  1494. LsapDsDebugOut((
  1495. DEB_FTINFO,
  1496. "\n---------------------------------------------------------\n\n"
  1497. ));
  1498. }
  1499. #endif
  1500. //
  1501. // Figure out if the cache contains information for this TDO already.
  1502. // If so, save off the existing info in case the changes need to
  1503. // be reverted later.
  1504. //
  1505. TdoEntryNew = ( TDO_ENTRY * )RtlLookupElementGenericTableAvl(
  1506. &m_TdoTable,
  1507. TrustedDomainName
  1508. );
  1509. if ( TdoEntryNew == NULL ) {
  1510. LsapDsDebugOut(( DEB_FTINFO, "Cache does not contain current information for %wZ\n", TrustedDomainName ));
  1511. CLONG EntrySize = sizeof( TDO_ENTRY ) + TrustedDomainName->Length + sizeof( WCHAR );
  1512. TDO_ENTRY * TdoEntry;
  1513. SafeAllocaAllocate( TdoEntry, EntrySize );
  1514. if ( TdoEntry == NULL ) {
  1515. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1516. Status = STATUS_INSUFFICIENT_RESOURCES;
  1517. goto Error;
  1518. }
  1519. TdoEntry->RecordCount = 0;
  1520. TdoEntry->TrustedDomainSid = NULL; // filled in later
  1521. //
  1522. // Initialize a cache entry for this TDO
  1523. //
  1524. FtcCopyUnicodeString(
  1525. &TdoEntry->TrustedDomainName,
  1526. TrustedDomainName,
  1527. TdoEntry->TrustedDomainNameBuffer
  1528. );
  1529. TdoEntryNew = ( TDO_ENTRY * )RtlInsertElementGenericTableAvl(
  1530. &m_TdoTable,
  1531. TdoEntry,
  1532. EntrySize,
  1533. NULL
  1534. );
  1535. SafeAllocaFree( TdoEntry );
  1536. TdoEntry = NULL;
  1537. if ( TdoEntryNew == NULL ) {
  1538. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1539. Status = STATUS_INSUFFICIENT_RESOURCES;
  1540. goto Error;
  1541. }
  1542. TdoEntryNew->TrustedDomainName.Buffer = TdoEntryNew->TrustedDomainNameBuffer;
  1543. ASSERT( ++sm_TdoEntries > 0 );
  1544. } else {
  1545. ASSERT( RtlEqualUnicodeString(
  1546. &TdoEntryNew->TrustedDomainName,
  1547. TrustedDomainName,
  1548. TRUE ));
  1549. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: Cache already contains information for %wZ\n", TrustedDomainName ));
  1550. if ( TdoEntryNew->LocalForestEntry != LocalForestEntry ) {
  1551. //
  1552. // Replacing a local forest entry with a non-local forest entry
  1553. // (or vice versa) is clearly bogus
  1554. //
  1555. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: LocalForestEntry flags mismatched (%s:%d)\n", __FILE__, __LINE__ ));
  1556. Status = STATUS_INVALID_PARAMETER;
  1557. ASSERT( FALSE ); // not sure if this is even possible
  1558. TdoEntryNew = NULL; // ensure no rollback at cleanup time
  1559. goto Error;
  1560. }
  1561. CopyTdoEntry( TdoEntryOldOut, TdoEntryNew );
  1562. }
  1563. ASSERT( TdoEntryNew != NULL );
  1564. //
  1565. // All InitializeListHead calls must take place AFTER
  1566. // the entry has been inserted into the table
  1567. // since they use self-referencing pointers
  1568. //
  1569. TdoEntryNew->RecordCount = 0;
  1570. TdoEntryNew->LocalForestEntry = LocalForestEntry;
  1571. InitializeListHead( &TdoEntryNew->TlnList );
  1572. InitializeListHead( &TdoEntryNew->DomainInfoList );
  1573. InitializeListHead( &TdoEntryNew->BinaryList );
  1574. //
  1575. // Store the SID with the entry
  1576. //
  1577. if ( TrustedDomainSid ) {
  1578. ULONG SidLength = RtlLengthSid( TrustedDomainSid );
  1579. TdoEntryNew->TrustedDomainSid = ( PSID )FtcAllocate( SidLength );
  1580. if ( TdoEntryNew->TrustedDomainSid == NULL ) {
  1581. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1582. Status = STATUS_INSUFFICIENT_RESOURCES;
  1583. goto Error;
  1584. }
  1585. RtlCopySid(
  1586. SidLength,
  1587. TdoEntryNew->TrustedDomainSid,
  1588. TrustedDomainSid
  1589. );
  1590. } else {
  1591. TdoEntryNew->TrustedDomainSid = NULL;
  1592. }
  1593. //
  1594. // All "new" entries will be given the same timestamp
  1595. //
  1596. GetSystemTimeAsFileTime(( LPFILETIME )&CurrentTime );
  1597. //
  1598. // Populate the forest trust cache with the information from ForestTrustInfo
  1599. // This is done without regard to collisions. A collision check follows.
  1600. //
  1601. for ( Current = 0 ; Current < ForestTrustInfo->RecordCount ; Current++ ) {
  1602. LSA_FOREST_TRUST_RECORD * Record = ForestTrustInfo->Entries[Current];
  1603. BOOLEAN Duplicate = FALSE;
  1604. switch ( Record->ForestTrustType ) {
  1605. case ForestTrustTopLevelName: {
  1606. UNICODE_STRING TopLevelName = Record->ForestTrustData.TopLevelName;
  1607. TLN_ENTRY * SubordinateEntry = NULL;
  1608. TLN_KEY * * TlnKeys = NULL;
  1609. TLN_ENTRY * * TlnEntries = NULL;
  1610. USHORT DnsComponents;
  1611. USHORT Component;
  1612. //
  1613. // If these asserts fire, you forgot to validate the
  1614. // data before passing it in. Use LsapValidateForestTrustInfo().
  1615. //
  1616. ASSERT( TopLevelName.Length > 0 );
  1617. ASSERT( TopLevelName.Buffer != NULL );
  1618. DnsComponents = DnsNameComponents( &TopLevelName );
  1619. SafeAllocaAllocate( TlnKeys, sizeof( TLN_KEY * ) * DnsComponents );
  1620. if ( TlnKeys == NULL ) {
  1621. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1622. Status = STATUS_INSUFFICIENT_RESOURCES;
  1623. goto TlnError;
  1624. }
  1625. RtlZeroMemory( TlnKeys, sizeof( TLN_KEY * ) * DnsComponents );
  1626. SafeAllocaAllocate( TlnEntries, sizeof( TLN_ENTRY * ) * DnsComponents );
  1627. if ( TlnEntries == NULL ) {
  1628. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1629. Status = STATUS_INSUFFICIENT_RESOURCES;
  1630. goto TlnError;
  1631. }
  1632. RtlZeroMemory( TlnEntries, sizeof( TLN_ENTRY * ) * DnsComponents );
  1633. for ( Component = 0 ; Component < DnsComponents ; Component++ ) {
  1634. //
  1635. // Move to the next component (except on first iteration through the loop)
  1636. //
  1637. if ( Component > 0 ) {
  1638. NextDnsComponent( &TopLevelName );
  1639. }
  1640. //
  1641. // Locate a match for this TLN in the cache
  1642. //
  1643. TlnKeys[Component] = ( TLN_KEY * )RtlLookupElementGenericTableAvl(
  1644. &m_TopLevelNameTable,
  1645. &TopLevelName
  1646. );
  1647. if ( TlnKeys[Component] == NULL ) {
  1648. //
  1649. // Nothing matching this top level name was found;
  1650. // Initialize and insert a new entry into the tree
  1651. //
  1652. CLONG KeySize = sizeof( TLN_KEY ) + TopLevelName.Length + sizeof( WCHAR );
  1653. TLN_KEY * TlnKeyNew;
  1654. SafeAllocaAllocate( TlnKeyNew, KeySize );
  1655. if ( TlnKeyNew == NULL ) {
  1656. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1657. Status = STATUS_INSUFFICIENT_RESOURCES;
  1658. goto TlnError;
  1659. }
  1660. TlnKeyNew->Count = 0;
  1661. FtcCopyUnicodeString(
  1662. &TlnKeyNew->TopLevelName,
  1663. &TopLevelName,
  1664. TlnKeyNew->TopLevelNameBuffer
  1665. );
  1666. TlnKeys[Component] = ( TLN_KEY * )RtlInsertElementGenericTableAvl(
  1667. &m_TopLevelNameTable,
  1668. TlnKeyNew,
  1669. KeySize,
  1670. NULL
  1671. );
  1672. SafeAllocaFree( TlnKeyNew );
  1673. TlnKeyNew = NULL;
  1674. if ( TlnKeys[Component] == NULL ) {
  1675. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1676. Status = STATUS_INSUFFICIENT_RESOURCES;
  1677. goto TlnError;
  1678. }
  1679. TlnKeys[Component]->TopLevelName.Buffer = TlnKeys[Component]->TopLevelNameBuffer;
  1680. ASSERT( ++sm_TlnKeys > 0 );
  1681. //
  1682. // All InitializeListHead calls must take place AFTER
  1683. // the entry has been inserted into the table
  1684. // since they use self-referential pointers
  1685. //
  1686. InitializeListHead( &TlnKeys[Component]->List );
  1687. } else {
  1688. //
  1689. // This name is known inside the cache.
  1690. // This could be duplicate, invalid parameter or a conflict.
  1691. // For now, check for duplicates and invalid
  1692. // parameter conditions only.
  1693. //
  1694. for ( ListEntry = TlnKeys[Component]->List.Flink;
  1695. ListEntry != &TlnKeys[Component]->List;
  1696. ListEntry = ListEntry->Flink ) {
  1697. TLN_ENTRY * TlnEntry;
  1698. TlnEntry = TLN_ENTRY::EntryFromAvlEntry( ListEntry );
  1699. if ( TlnEntry->TdoEntry != TdoEntryNew ) {
  1700. //
  1701. // Only interested in the entries for the same TDO here
  1702. //
  1703. continue;
  1704. }
  1705. if ( TlnEntry->Excluded ) {
  1706. //
  1707. // Having both a top level name and an exclusion
  1708. // record for the same name is clearly invalid.
  1709. //
  1710. // Also, a top level name can not be subordinate
  1711. // to an exclusion record for the same TLN.
  1712. //
  1713. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1714. Status = STATUS_INVALID_PARAMETER;
  1715. goto TlnError;
  1716. } else if ( TlnEntry->SubordinateEntry != NULL &&
  1717. SubordinateEntry == NULL ) {
  1718. //
  1719. // If we're looking at a subordinate entry
  1720. // (e.g. acme.com subordinate to NY.acme.com)
  1721. // and we're trying to insert a top level entry
  1722. // of acme.com, then the existece of the other
  1723. // top level entry is invalid (the namespace would
  1724. // be claimed by acme.com and NY.acme.com is redundant)
  1725. //
  1726. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1727. Status = STATUS_INVALID_PARAMETER;
  1728. goto TlnError;
  1729. } else if ( TlnEntry->SubordinateEntry == NULL &&
  1730. SubordinateEntry != NULL ) {
  1731. //
  1732. // If we're looking at a top-level entry (e.g. acme.com)
  1733. // and we're trying to insert a superior entry of another
  1734. // top level name that matches it (say "acme.com" for
  1735. // a TLN of "NY.acme.com") then we're doing something
  1736. // wrong.
  1737. //
  1738. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1739. Status = STATUS_INVALID_PARAMETER;
  1740. goto TlnError;
  1741. } else if ( TlnEntry->SubordinateEntry != NULL &&
  1742. SubordinateEntry != NULL ) {
  1743. //
  1744. // Both entries are superior entries. This will happen
  1745. // if both "WA.acme.com" and "NY.acme.com" are claimed
  1746. // by this TDO, so both "acme.com" entries must exist
  1747. // in the cache and it's not a problem.
  1748. //
  1749. // Do nothing
  1750. //
  1751. } else {
  1752. ASSERT( TlnEntry->SubordinateEntry == NULL );
  1753. ASSERT( SubordinateEntry == NULL );
  1754. //
  1755. // Found two identical top-level entries for the same
  1756. // TDO. Second entry is a duplicate and can be dropped.
  1757. //
  1758. // Note that the disabled status of the two can be
  1759. // different. Too bad. The later entry is ignored.
  1760. // Alternatively, this can be considered as invalid parameter.
  1761. //
  1762. LsapDsDebugOut(( DEB_FTINFO, "Record %d is a duplicate of entry %p (%s:%d)\n", Current, TlnEntry, __FILE__, __LINE__ ));
  1763. Duplicate = TRUE;
  1764. break;
  1765. }
  1766. }
  1767. if ( Duplicate ) {
  1768. break;
  1769. }
  1770. }
  1771. ASSERT( TlnKeys[Component] != NULL );
  1772. TlnEntries[Component] = ( TLN_ENTRY * )FtcAllocate( sizeof( TLN_ENTRY ));
  1773. if ( TlnEntries[Component] == NULL ) {
  1774. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1775. Status = STATUS_INSUFFICIENT_RESOURCES;
  1776. goto TlnError;
  1777. }
  1778. ASSERT( ++sm_TlnEntries > 0 );
  1779. //
  1780. // Associate this item with the TDO cache entry
  1781. //
  1782. InsertHeadList( &TdoEntryNew->TlnList, &TlnEntries[Component]->TdoListEntry );
  1783. //
  1784. // ... and also with the AVL tree entry
  1785. //
  1786. TlnKeys[Component]->Count += 1;
  1787. InsertHeadList( &TlnKeys[Component]->List, &TlnEntries[Component]->AvlListEntry );
  1788. //
  1789. // Initialize the rest of TLN_ENTRY fields
  1790. //
  1791. if ( Record->Time.LowPart == 0 && Record->Time.HighPart == 0 ) {
  1792. TlnEntries[Component]->Time = CurrentTime;
  1793. } else {
  1794. TlnEntries[Component]->Time = Record->Time;
  1795. }
  1796. TlnEntries[Component]->Excluded = FALSE;
  1797. TlnEntries[Component]->Index = Current;
  1798. TlnEntries[Component]->TdoEntry = TdoEntryNew;
  1799. TlnEntries[Component]->SubordinateEntry = SubordinateEntry;
  1800. TlnEntries[Component]->TlnKey = TlnKeys[Component];
  1801. TlnEntries[Component]->SetFlags( Record->Flags );
  1802. //
  1803. // Prepare for next iteration
  1804. //
  1805. SubordinateEntry = TlnEntries[Component];
  1806. }
  1807. SafeAllocaFree( TlnKeys );
  1808. SafeAllocaFree( TlnEntries );
  1809. break;
  1810. TlnError:
  1811. //
  1812. // Blow away all the entries and keys inserted in this round
  1813. //
  1814. for ( Component = 0 ; Component < DnsComponents ; Component++ ) {
  1815. if ( TlnEntries &&
  1816. TlnEntries[Component] != NULL ) {
  1817. ASSERT( sm_TlnEntries-- > 0 );
  1818. RemoveEntryList( &TlnEntries[Component]->TdoListEntry );
  1819. RemoveEntryList( &TlnEntries[Component]->AvlListEntry );
  1820. TlnEntries[Component]->TlnKey->Count -= 1;
  1821. FtcFree( TlnEntries[Component] );
  1822. }
  1823. if ( TlnKeys &&
  1824. TlnKeys[Component] != NULL &&
  1825. TlnKeys[Component]->Count == 0 ) {
  1826. BOOLEAN Found;
  1827. Found = RtlDeleteElementGenericTableAvl(
  1828. &m_TopLevelNameTable,
  1829. TlnKeys[Component]
  1830. );
  1831. ASSERT( sm_TlnKeys-- > 0 );
  1832. ASSERT( Found );
  1833. }
  1834. }
  1835. SafeAllocaFree( TlnKeys );
  1836. SafeAllocaFree( TlnEntries );
  1837. goto Error;
  1838. }
  1839. case ForestTrustTopLevelNameEx: {
  1840. UNICODE_STRING TopLevelName = Record->ForestTrustData.TopLevelName;
  1841. TLN_ENTRY * TlnEntry;
  1842. TLN_KEY * TlnKey;
  1843. //
  1844. // If these asserts fire, you forgot to validate the
  1845. // data before passing it in. Use LsapValidateForestTrustInfo().
  1846. //
  1847. ASSERT( TopLevelName.Length > 0 );
  1848. ASSERT( TopLevelName.Buffer != NULL );
  1849. if ( 1 >= DnsNameComponents( &TopLevelName )) {
  1850. //
  1851. // An exclusion record claims part of the namespace, and
  1852. // so must contain at least 2 DNS name components.
  1853. // e.g. 'acme.com' is valid but 'com' is not
  1854. //
  1855. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1856. Status = STATUS_INVALID_PARAMETER;
  1857. goto Error;
  1858. }
  1859. TlnKey = ( TLN_KEY * )RtlLookupElementGenericTableAvl(
  1860. &m_TopLevelNameTable,
  1861. &TopLevelName
  1862. );
  1863. if ( TlnKey == NULL ) {
  1864. //
  1865. // Nothing matching this top level name was found;
  1866. // Initialize and insert a new entry into the tree
  1867. //
  1868. CLONG KeySize = sizeof( TLN_KEY ) + TopLevelName.Length + sizeof( WCHAR );
  1869. TLN_KEY * TlnKeyNew;
  1870. SafeAllocaAllocate( TlnKeyNew, KeySize );
  1871. if ( TlnKeyNew == NULL ) {
  1872. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1873. Status = STATUS_INSUFFICIENT_RESOURCES;
  1874. goto Error;
  1875. }
  1876. TlnKeyNew->Count = 0;
  1877. FtcCopyUnicodeString(
  1878. &TlnKeyNew->TopLevelName,
  1879. &TopLevelName,
  1880. TlnKeyNew->TopLevelNameBuffer
  1881. );
  1882. TlnKey = ( TLN_KEY * )RtlInsertElementGenericTableAvl(
  1883. &m_TopLevelNameTable,
  1884. TlnKeyNew,
  1885. KeySize,
  1886. NULL
  1887. );
  1888. SafeAllocaFree( TlnKeyNew );
  1889. TlnKeyNew = NULL;
  1890. if ( TlnKey == NULL ) {
  1891. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1892. Status = STATUS_INSUFFICIENT_RESOURCES;
  1893. goto Error;
  1894. }
  1895. TlnKey->TopLevelName.Buffer = TlnKey->TopLevelNameBuffer;
  1896. ASSERT( ++sm_TlnKeys > 0 );
  1897. //
  1898. // All InitializeListHead calls must take place AFTER
  1899. // the entry has been inserted into the table
  1900. // since they use self-referential pointers
  1901. //
  1902. InitializeListHead( &TlnKey->List );
  1903. } else {
  1904. //
  1905. // This name is known inside the cache.
  1906. // This could be duplicate, invalid parameter or a conflict.
  1907. // For now, check for duplicates and invalid
  1908. // parameter conditions only.
  1909. //
  1910. for ( ListEntry = TlnKey->List.Flink;
  1911. ListEntry != &TlnKey->List;
  1912. ListEntry = ListEntry->Flink ) {
  1913. TLN_ENTRY * TlnEntry;
  1914. TlnEntry = TLN_ENTRY::EntryFromAvlEntry( ListEntry );
  1915. if ( TlnEntry->TdoEntry != TdoEntryNew ) {
  1916. //
  1917. // Only interested in the entries for the same TDO here
  1918. //
  1919. continue;
  1920. }
  1921. if ( TlnEntry->Excluded != TRUE ) {
  1922. //
  1923. // Having both a top level and an exclusion
  1924. // record for the same name is clearly broken.
  1925. //
  1926. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1927. Status = STATUS_INVALID_PARAMETER;
  1928. goto Error;
  1929. }
  1930. //
  1931. // If the other entry is for the same TDO as this one,
  1932. // this is bogus input. Ignore this record.
  1933. //
  1934. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: Record %d is a duplicate of entry %p (%s:%d)\n", Current, TlnEntry, __FILE__, __LINE__ ));
  1935. Duplicate = TRUE;
  1936. break;
  1937. }
  1938. if ( Duplicate ) {
  1939. break;
  1940. }
  1941. }
  1942. ASSERT( TlnKey != NULL );
  1943. TlnEntry = ( TLN_ENTRY * )FtcAllocate( sizeof( TLN_ENTRY ));
  1944. if ( TlnEntry == NULL ) {
  1945. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1946. Status = STATUS_INSUFFICIENT_RESOURCES;
  1947. goto Error;
  1948. }
  1949. ASSERT( ++sm_TlnEntries > 0 );
  1950. //
  1951. // Associate this item with the TDO cache entry
  1952. //
  1953. InsertHeadList( &TdoEntryNew->TlnList, &TlnEntry->TdoListEntry );
  1954. //
  1955. // ... and also with the AVL tree entry
  1956. //
  1957. TlnKey->Count += 1;
  1958. InsertHeadList( &TlnKey->List, &TlnEntry->AvlListEntry );
  1959. //
  1960. // Initialize the rest of TLN_ENTRY fields
  1961. //
  1962. TlnEntry->Excluded = TRUE;
  1963. TlnEntry->Index = Current;
  1964. TlnEntry->TdoEntry = TdoEntryNew;
  1965. TlnEntry->SuperiorEntry = NULL;
  1966. TlnEntry->TlnKey = TlnKey;
  1967. TlnEntry->SetFlags( Record->Flags ); // value ignored for exclusion entries
  1968. if ( Record->Time.LowPart == 0 && Record->Time.HighPart == 0 ) {
  1969. TlnEntry->Time = CurrentTime;
  1970. } else {
  1971. TlnEntry->Time = Record->Time;
  1972. }
  1973. break;
  1974. }
  1975. case ForestTrustDomainInfo: {
  1976. SID * Sid = ( SID * )Record->ForestTrustData.DomainInfo.Sid;
  1977. UNICODE_STRING * DnsName = &Record->ForestTrustData.DomainInfo.DnsName;
  1978. UNICODE_STRING * NetbiosName = &Record->ForestTrustData.DomainInfo.NetbiosName;
  1979. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  1980. DOMAIN_SID_KEY * SidKey;
  1981. DNS_NAME_KEY * DnsKey;
  1982. NETBIOS_NAME_KEY * NetbiosKey;
  1983. BOOLEAN NetbiosPresent = ( NetbiosName->Length > 0 && NetbiosName->Buffer != NULL );
  1984. ULONG SidLength;
  1985. BOOLEAN SidKeyAllocated = FALSE;
  1986. BOOLEAN DnsKeyAllocated = FALSE;
  1987. BOOLEAN NetbiosKeyAllocated = FALSE;
  1988. //
  1989. // If these asserts fire, you forgot to validate the
  1990. // data before passing it in. Use LsapValidateForestTrustInfo().
  1991. //
  1992. ASSERT( Sid );
  1993. ASSERT( DnsName->Length > 0 );
  1994. ASSERT( DnsName->Buffer != NULL );
  1995. if ( !RtlValidSid( Sid )) {
  1996. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  1997. Status = STATUS_INVALID_PARAMETER;
  1998. goto Error;
  1999. }
  2000. SidLength = RtlLengthSid( Sid );
  2001. ASSERT( SidLength > 0 );
  2002. SidKey = ( DOMAIN_SID_KEY * )RtlLookupElementGenericTableAvl(
  2003. &m_DomainSidTable,
  2004. &Sid
  2005. );
  2006. DnsKey = ( DNS_NAME_KEY * )RtlLookupElementGenericTableAvl(
  2007. &m_DnsNameTable,
  2008. DnsName
  2009. );
  2010. if ( NetbiosPresent ) {
  2011. NetbiosKey = (NETBIOS_NAME_KEY * )RtlLookupElementGenericTableAvl(
  2012. &m_NetbiosNameTable,
  2013. NetbiosName
  2014. );
  2015. } else {
  2016. NetbiosKey = NULL;
  2017. }
  2018. if ( SidKey == NULL ) {
  2019. //
  2020. // Nothing matching this domain SID was found;
  2021. // Initialize and insert a new entry into the tree
  2022. //
  2023. CLONG KeySize = sizeof( DOMAIN_SID_KEY ) + SidLength;
  2024. DOMAIN_SID_KEY * SidKeyNew;
  2025. SafeAllocaAllocate( SidKeyNew, KeySize );
  2026. if ( SidKeyNew == NULL ) {
  2027. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2028. Status = STATUS_INSUFFICIENT_RESOURCES;
  2029. goto DomainInfoError;
  2030. }
  2031. SidKeyNew->Count = 0;
  2032. SidKeyNew->DomainSid = ( SID * )SidKeyNew->SidBuffer;
  2033. RtlCopySid( SidLength, SidKeyNew->DomainSid, Sid );
  2034. SidKey = ( DOMAIN_SID_KEY * )RtlInsertElementGenericTableAvl(
  2035. &m_DomainSidTable,
  2036. SidKeyNew,
  2037. KeySize,
  2038. NULL
  2039. );
  2040. SafeAllocaFree( SidKeyNew );
  2041. SidKeyNew = NULL;
  2042. if ( SidKey == NULL ) {
  2043. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2044. Status = STATUS_INSUFFICIENT_RESOURCES;
  2045. goto DomainInfoError;
  2046. }
  2047. SidKey->DomainSid = ( SID * )SidKey->SidBuffer;
  2048. SidKeyAllocated = TRUE;
  2049. ASSERT( ++sm_SidKeys > 0 );
  2050. //
  2051. // All InitializeListHead calls must take place AFTER
  2052. // the entry has been inserted into the table
  2053. // since they use self-referential pointers
  2054. //
  2055. InitializeListHead( &SidKey->List );
  2056. } else {
  2057. //
  2058. // This SID is known inside the cache.
  2059. // Check for duplicates here, for conflicts later.
  2060. //
  2061. for ( ListEntry = SidKey->List.Flink;
  2062. ListEntry != &SidKey->List;
  2063. ListEntry = ListEntry->Flink ) {
  2064. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  2065. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromSidEntry( ListEntry );
  2066. if ( DomainInfoEntry->TdoEntry != TdoEntryNew ) {
  2067. //
  2068. // Only interested in the entries for the same TDO here
  2069. //
  2070. continue;
  2071. }
  2072. LsapDsDebugOut(( DEB_FTINFO, "Record %d is a duplicate of entry %p (%s:%d)\n", Current, DomainInfoEntry, __FILE__, __LINE__ ));
  2073. Duplicate = TRUE;
  2074. break;
  2075. }
  2076. if ( Duplicate ) {
  2077. goto DuplicateEntry;
  2078. }
  2079. }
  2080. ASSERT( SidKey != NULL );
  2081. if ( DnsKey == NULL ) {
  2082. //
  2083. // Nothing matches this DNS name
  2084. // Initialize and insert a new entry into the tree
  2085. //
  2086. CLONG KeySize = sizeof( DNS_NAME_KEY ) + DnsName->Length + sizeof( WCHAR );
  2087. DNS_NAME_KEY * DnsKeyNew;
  2088. SafeAllocaAllocate( DnsKeyNew, KeySize );
  2089. if ( DnsKeyNew == NULL ) {
  2090. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2091. Status = STATUS_INSUFFICIENT_RESOURCES;
  2092. goto DomainInfoError;
  2093. }
  2094. DnsKeyNew->Count = 0;
  2095. FtcCopyUnicodeString(
  2096. &DnsKeyNew->DnsName,
  2097. DnsName,
  2098. DnsKeyNew->DnsNameBuffer
  2099. );
  2100. DnsKey = ( DNS_NAME_KEY * )RtlInsertElementGenericTableAvl(
  2101. &m_DnsNameTable,
  2102. DnsKeyNew,
  2103. KeySize,
  2104. NULL
  2105. );
  2106. SafeAllocaFree( DnsKeyNew );
  2107. DnsKeyNew = NULL;
  2108. if ( DnsKey == NULL ) {
  2109. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2110. Status = STATUS_INSUFFICIENT_RESOURCES;
  2111. goto DomainInfoError;
  2112. }
  2113. DnsKey->DnsName.Buffer = DnsKey->DnsNameBuffer;
  2114. DnsKeyAllocated = TRUE;
  2115. ASSERT( ++sm_DnsNameKeys > 0 );
  2116. //
  2117. // All InitializeListHead calls must take place AFTER
  2118. // the entry has been inserted into the table
  2119. // since they use self-referential pointers
  2120. //
  2121. InitializeListHead( &DnsKey->List );
  2122. } else {
  2123. //
  2124. // This name is known inside the cache.
  2125. // Check for duplicates here, for conflicts later.
  2126. //
  2127. for ( ListEntry = DnsKey->List.Flink;
  2128. ListEntry != &DnsKey->List;
  2129. ListEntry = ListEntry->Flink ) {
  2130. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  2131. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromDnsEntry( ListEntry );
  2132. if ( DomainInfoEntry->TdoEntry != TdoEntryNew ) {
  2133. //
  2134. // Only interested in the entries for the same TDO here
  2135. //
  2136. continue;
  2137. }
  2138. LsapDsDebugOut(( DEB_FTINFO, "Record %d is a duplicate of entry %p (%s:%d)\n", Current, DomainInfoEntry, __FILE__, __LINE__ ));
  2139. Duplicate = TRUE;
  2140. break;
  2141. }
  2142. if ( Duplicate ) {
  2143. goto DuplicateEntry;
  2144. }
  2145. }
  2146. ASSERT( DnsKey != NULL );
  2147. if ( NetbiosPresent && NetbiosKey == NULL ) {
  2148. //
  2149. // Nothing matches this NetbiosName
  2150. // Initialize and insert a new entry into the tree
  2151. //
  2152. CLONG KeySize = sizeof( NETBIOS_NAME_KEY ) + NetbiosName->Length + sizeof( WCHAR );
  2153. NETBIOS_NAME_KEY * NetbiosKeyNew;
  2154. SafeAllocaAllocate( NetbiosKeyNew, KeySize );
  2155. if ( NetbiosKeyNew == NULL ) {
  2156. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2157. Status = STATUS_INSUFFICIENT_RESOURCES;
  2158. goto DomainInfoError;
  2159. }
  2160. NetbiosKeyNew->Count = 0;
  2161. FtcCopyUnicodeString(
  2162. &NetbiosKeyNew->NetbiosName,
  2163. NetbiosName,
  2164. NetbiosKeyNew->NetbiosNameBuffer
  2165. );
  2166. NetbiosKey = ( NETBIOS_NAME_KEY * )RtlInsertElementGenericTableAvl(
  2167. &m_NetbiosNameTable,
  2168. NetbiosKeyNew,
  2169. KeySize,
  2170. NULL
  2171. );
  2172. SafeAllocaFree( NetbiosKeyNew );
  2173. NetbiosKeyNew = NULL;
  2174. if ( NetbiosKey == NULL ) {
  2175. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2176. Status = STATUS_INSUFFICIENT_RESOURCES;
  2177. goto DomainInfoError;
  2178. }
  2179. NetbiosKey->NetbiosName.Buffer = NetbiosKey->NetbiosNameBuffer;
  2180. NetbiosKeyAllocated = TRUE;
  2181. ASSERT( ++sm_NetbiosNameKeys > 0 );
  2182. //
  2183. // All InitializeListHead calls must take place AFTER
  2184. // the entry has been inserted into the table
  2185. // since they use self-referential pointers
  2186. //
  2187. InitializeListHead( &NetbiosKey->List );
  2188. } else if ( NetbiosKey != NULL ) {
  2189. //
  2190. // This name is known inside the cache.
  2191. // Check for duplicates here, for conflicts later.
  2192. //
  2193. for ( ListEntry = NetbiosKey->List.Flink;
  2194. ListEntry != &NetbiosKey->List;
  2195. ListEntry = ListEntry->Flink ) {
  2196. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  2197. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromNetbiosEntry( ListEntry );
  2198. if ( DomainInfoEntry->TdoEntry != TdoEntryNew ) {
  2199. //
  2200. // Only interested in the entries for the same TDO here
  2201. //
  2202. continue;
  2203. }
  2204. LsapDsDebugOut(( DEB_FTINFO, "Record %d is a duplicate of entry %p (%s:%d)\n", Current, DomainInfoEntry, __FILE__, __LINE__ ));
  2205. Duplicate = TRUE;
  2206. break;
  2207. }
  2208. if ( Duplicate ) {
  2209. goto DuplicateEntry;
  2210. }
  2211. }
  2212. ASSERT( !NetbiosPresent || NetbiosKey != NULL );
  2213. DomainInfoEntry = ( DOMAIN_INFO_ENTRY * )FtcAllocate( sizeof( DOMAIN_INFO_ENTRY ));
  2214. if ( DomainInfoEntry == NULL ) {
  2215. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2216. Status = STATUS_INSUFFICIENT_RESOURCES;
  2217. goto DomainInfoError;
  2218. }
  2219. DomainInfoEntry->Sid = ( SID * )FtcAllocate( SidLength );
  2220. if ( DomainInfoEntry->Sid == NULL ) {
  2221. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2222. FtcFree( DomainInfoEntry );
  2223. Status = STATUS_INSUFFICIENT_RESOURCES;
  2224. goto DomainInfoError;
  2225. }
  2226. ASSERT( ++sm_DomainInfoEntries > 0 );
  2227. //
  2228. // Associate this item with the TDO cache entry
  2229. //
  2230. InsertHeadList( &TdoEntryNew->DomainInfoList, &DomainInfoEntry->TdoListEntry );
  2231. //
  2232. // And also with the AVL list entries
  2233. //
  2234. SidKey->Count += 1;
  2235. InsertHeadList( &SidKey->List, &DomainInfoEntry->SidAvlListEntry );
  2236. DnsKey->Count += 1;
  2237. InsertHeadList( &DnsKey->List, &DomainInfoEntry->DnsAvlListEntry );
  2238. if ( NetbiosPresent ) {
  2239. NetbiosKey->Count += 1;
  2240. InsertHeadList( &NetbiosKey->List, &DomainInfoEntry->NetbiosAvlListEntry );
  2241. } else {
  2242. InitializeListHead( &DomainInfoEntry->NetbiosAvlListEntry );
  2243. }
  2244. //
  2245. // Initialize the rest of DomainInfoEntry fields
  2246. //
  2247. if ( Record->Time.LowPart == 0 && Record->Time.HighPart == 0 ) {
  2248. DomainInfoEntry->Time = CurrentTime;
  2249. } else {
  2250. DomainInfoEntry->Time = Record->Time;
  2251. }
  2252. DomainInfoEntry->Index = Current;
  2253. RtlCopySid( SidLength, DomainInfoEntry->Sid, Sid );
  2254. DomainInfoEntry->TdoEntry = TdoEntryNew;
  2255. DomainInfoEntry->SubordinateTo = NULL;
  2256. DomainInfoEntry->SidKey = SidKey;
  2257. DomainInfoEntry->DnsKey = DnsKey;
  2258. DomainInfoEntry->NetbiosKey = NetbiosKey;
  2259. DomainInfoEntry->SetFlags( Record->Flags );
  2260. break;
  2261. DuplicateEntry:
  2262. //
  2263. // Duplicates aren't errors!
  2264. //
  2265. ASSERT( NT_SUCCESS( Status ));
  2266. DomainInfoError:
  2267. if ( SidKeyAllocated ) {
  2268. BOOLEAN Found;
  2269. Found = RtlDeleteElementGenericTableAvl(
  2270. &m_DomainSidTable,
  2271. &Sid
  2272. );
  2273. ASSERT( sm_SidKeys-- > 0 );
  2274. }
  2275. if ( DnsKeyAllocated ) {
  2276. BOOLEAN Found;
  2277. Found = RtlDeleteElementGenericTableAvl(
  2278. &m_DnsNameTable,
  2279. &DnsName
  2280. );
  2281. ASSERT( sm_DnsNameKeys-- > 0 );
  2282. ASSERT( Found );
  2283. }
  2284. if ( NetbiosKeyAllocated ) {
  2285. BOOLEAN Found;
  2286. Found = RtlDeleteElementGenericTableAvl(
  2287. &m_NetbiosNameTable,
  2288. &NetbiosName
  2289. );
  2290. ASSERT( sm_NetbiosNameKeys-- > 0 );
  2291. ASSERT( Found );
  2292. }
  2293. if ( !NT_SUCCESS( Status )) {
  2294. goto Error;
  2295. } else {
  2296. break;
  2297. }
  2298. }
  2299. default: {
  2300. BINARY_ENTRY * BinaryEntry;
  2301. BinaryEntry = ( BINARY_ENTRY * )FtcAllocate( sizeof( BINARY_ENTRY ));
  2302. if ( BinaryEntry == NULL ) {
  2303. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2304. Status = STATUS_INSUFFICIENT_RESOURCES;
  2305. goto Error;
  2306. }
  2307. BinaryEntry->Data.Length = Record->ForestTrustData.Data.Length;
  2308. if ( BinaryEntry->Data.Length > 0 ) {
  2309. BinaryEntry->Data.Buffer = ( BYTE * )FtcAllocate( BinaryEntry->Data.Length );
  2310. if ( BinaryEntry->Data.Buffer == NULL ) {
  2311. FtcFree( BinaryEntry );
  2312. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2313. Status = STATUS_INSUFFICIENT_RESOURCES;
  2314. goto Error;
  2315. }
  2316. RtlCopyMemory(
  2317. BinaryEntry->Data.Buffer,
  2318. Record->ForestTrustData.Data.Buffer,
  2319. BinaryEntry->Data.Length
  2320. );
  2321. } else {
  2322. BinaryEntry->Data.Buffer = NULL;
  2323. }
  2324. ASSERT( ++sm_BinaryEntries > 0 );
  2325. //
  2326. // Associate this item with the TDO cache entry
  2327. //
  2328. InsertHeadList( &TdoEntryNew->BinaryList, &BinaryEntry->TdoListEntry );
  2329. //
  2330. // Initialize the rest of BinaryEntry fields
  2331. //
  2332. BinaryEntry->Type = Record->ForestTrustType;
  2333. BinaryEntry->SetFlags( Record->Flags );
  2334. break;
  2335. }
  2336. }
  2337. if ( !Duplicate ) {
  2338. TdoEntryNew->RecordCount += 1;
  2339. }
  2340. }
  2341. ASSERT( TdoEntryNew->RecordCount <= ForestTrustInfo->RecordCount );
  2342. //
  2343. // Before testing for conflicts, validate the records for internal
  2344. // consistency. Lack of consistency is an invalid parameter, not a conflict.
  2345. //
  2346. //
  2347. // First validate top-level and excluded entries
  2348. //
  2349. for ( ListEntry = TdoEntryNew->TlnList.Flink;
  2350. ListEntry != &TdoEntryNew->TlnList;
  2351. ListEntry = ListEntry->Flink ) {
  2352. TLN_ENTRY * TlnEntry;
  2353. TlnEntry = TLN_ENTRY::EntryFromTdoEntry( ListEntry );
  2354. if ( TlnEntry->Excluded ) {
  2355. ASSERT( TlnEntry->SuperiorEntry == NULL );
  2356. //
  2357. // An excluded entry must be subordinate to a top level name
  2358. // for the same TDO
  2359. //
  2360. UNICODE_STRING ExcludedName = TlnEntry->TlnKey->TopLevelName;
  2361. //
  2362. // The name was validated prior to inserting it into the tree
  2363. //
  2364. ASSERT( 1 < DnsNameComponents( &ExcludedName ));
  2365. for ( NextDnsComponent( &ExcludedName );
  2366. ExcludedName.Length > 0;
  2367. NextDnsComponent( &ExcludedName )) {
  2368. TLN_KEY * TlnKeySup = ( TLN_KEY * )RtlLookupElementGenericTableAvl(
  2369. &m_TopLevelNameTable,
  2370. &ExcludedName
  2371. );
  2372. if ( TlnKeySup == NULL ) {
  2373. continue;
  2374. }
  2375. for ( LIST_ENTRY * ListEntrySup = TlnKeySup->List.Flink;
  2376. ListEntrySup != &TlnKeySup->List;
  2377. ListEntrySup = ListEntrySup->Flink ) {
  2378. TLN_ENTRY * TlnEntrySup;
  2379. TlnEntrySup = TLN_ENTRY::EntryFromAvlEntry( ListEntrySup );
  2380. if ( TlnEntrySup->TdoEntry != TdoEntryNew ) {
  2381. //
  2382. // Only interested in the entries for the same TDO here
  2383. //
  2384. continue;
  2385. }
  2386. if ( TlnEntrySup->Excluded ) {
  2387. //
  2388. // Another entry for the same TDO excludes a superior namespace.
  2389. // UI wants to retain both (in case sales.redmond.microsoft.com is
  2390. // already excluded and now the admin wants to exclude
  2391. // redmond.microsoft.com also)
  2392. //
  2393. continue;
  2394. }
  2395. if ( TlnEntrySup->SubordinateEntry != NULL ) {
  2396. //
  2397. // Skip over superior entries -- they do not participate
  2398. // in consistency checking because they just point to
  2399. // real top level entries
  2400. //
  2401. continue;
  2402. }
  2403. //
  2404. // Found our superior entry! Remember it.
  2405. //
  2406. TlnEntry->SuperiorEntry = TlnEntrySup;
  2407. break;
  2408. }
  2409. if ( TlnEntry->SuperiorEntry != NULL ) {
  2410. break;
  2411. }
  2412. }
  2413. if ( TlnEntry->SuperiorEntry == NULL ) {
  2414. //
  2415. // This excluded top-level name entry does not have
  2416. // a superior TLN, thus it is invalid.
  2417. //
  2418. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2419. Status = STATUS_INVALID_PARAMETER;
  2420. goto Error;
  2421. }
  2422. }
  2423. }
  2424. //
  2425. // Now validate domain info entries.
  2426. // Each domain info entry must be subordinate to a top level name.
  2427. //
  2428. // An exception is made for domain info entries that have the
  2429. // "administratively disabled" bits set and are not subordinate
  2430. // to any top level name. Such entries are treated as "store and ignore"
  2431. // to prevent rogue trusted domains from making the trusting side
  2432. // forget about administratively disabled entries.
  2433. //
  2434. for ( ListEntry = TdoEntryNew->DomainInfoList.Flink;
  2435. ListEntry != &TdoEntryNew->DomainInfoList;
  2436. ListEntry = ListEntry->Flink ) {
  2437. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  2438. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromTdoEntry( ListEntry );
  2439. //
  2440. // DomainInfoEntry->SubordinateTo is the field we seek to fill in
  2441. //
  2442. ASSERT( DomainInfoEntry->SubordinateTo == NULL );
  2443. for ( UNICODE_STRING SuperiorName = DomainInfoEntry->DnsKey->DnsName;
  2444. SuperiorName.Length > 0;
  2445. NextDnsComponent( &SuperiorName )) {
  2446. TLN_KEY * TlnKeySup = ( TLN_KEY * )RtlLookupElementGenericTableAvl(
  2447. &m_TopLevelNameTable,
  2448. &SuperiorName
  2449. );
  2450. if ( TlnKeySup == NULL ) {
  2451. continue;
  2452. }
  2453. for ( LIST_ENTRY * ListEntrySup = TlnKeySup->List.Flink;
  2454. ListEntrySup != &TlnKeySup->List;
  2455. ListEntrySup = ListEntrySup->Flink ) {
  2456. TLN_ENTRY * TlnEntrySup;
  2457. TlnEntrySup = TLN_ENTRY::EntryFromAvlEntry( ListEntrySup );
  2458. if ( TlnEntrySup->TdoEntry != TdoEntryNew ) {
  2459. //
  2460. // Only interested in the entries for the same TDO here
  2461. //
  2462. continue;
  2463. }
  2464. if ( TlnEntrySup->Excluded ) {
  2465. //
  2466. // Looking for non-excluded TLNs only
  2467. //
  2468. continue;
  2469. }
  2470. if ( TlnEntrySup->SubordinateEntry == NULL ) {
  2471. //
  2472. // Found our match: a non-excluded TLN that is not a
  2473. // subordinate of another TLN
  2474. //
  2475. DomainInfoEntry->SubordinateTo = TlnEntrySup;
  2476. break;
  2477. }
  2478. }
  2479. if ( DomainInfoEntry->SubordinateTo != NULL ) {
  2480. //
  2481. // Found the entry we're subordinate to, stop the search here
  2482. //
  2483. break;
  2484. }
  2485. }
  2486. if ( DomainInfoEntry->SubordinateTo == NULL &&
  2487. !DomainInfoEntry->IsSidAdminDisabled()) {
  2488. //
  2489. // This name is not admin-disabled and
  2490. // does not have a superior TLN.
  2491. // Thus it is invalid.
  2492. //
  2493. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Insert (%s:%d)\n", __FILE__, __LINE__ ));
  2494. Status = STATUS_INVALID_PARAMETER;
  2495. goto Error;
  2496. }
  2497. }
  2498. //
  2499. // At this point, the newly inserted trusted domain entry is internally
  2500. // consistent. Code that follows fully assumes this fact.
  2501. //
  2502. //
  2503. // Rules for an enabled top level name record:
  2504. //
  2505. // * Must not be equal to an enabled TLN for another TDO
  2506. // * Must not be subordinate to an enabled TLN for another TDO
  2507. // unless the other TDO has a corresponding exclusion record
  2508. // * Must not be superior to an enabled TLN for another TDO
  2509. // unless this TDO has a corresponding exclusion record
  2510. //
  2511. for ( ListEntry = TdoEntryNew->TlnList.Flink;
  2512. ListEntry != &TdoEntryNew->TlnList;
  2513. ListEntry = ListEntry->Flink ) {
  2514. TLN_ENTRY * ThisEntry;
  2515. ThisEntry = TLN_ENTRY::EntryFromTdoEntry( ListEntry );
  2516. if ( ThisEntry->Excluded ) {
  2517. //
  2518. // Nothing to check at the moment (validity was verified above)
  2519. //
  2520. continue;
  2521. }
  2522. if ( !ThisEntry->Enabled()) {
  2523. //
  2524. // Records that are not enabled are not considered for collision detection
  2525. //
  2526. continue;
  2527. }
  2528. for ( LIST_ENTRY * ListEntrySup = ThisEntry->TlnKey->List.Flink;
  2529. ListEntrySup != &ThisEntry->TlnKey->List;
  2530. ListEntrySup = ListEntrySup->Flink ) {
  2531. TLN_ENTRY * OtherEntry;
  2532. TLN_ENTRY * ConflictEntry = NULL;
  2533. OtherEntry = TLN_ENTRY::EntryFromAvlEntry( ListEntrySup );
  2534. if ( OtherEntry->TdoEntry == TdoEntryNew ||
  2535. OtherEntry->TdoEntry == TdoEntryOldOut ) {
  2536. //
  2537. // Only interested in entries corresponding to other TDOs
  2538. //
  2539. continue;
  2540. }
  2541. if ( OtherEntry->Excluded ) {
  2542. //
  2543. // Not interested in excluded entries
  2544. //
  2545. continue;
  2546. }
  2547. if ( !OtherEntry->Enabled()) {
  2548. //
  2549. // Not interested in disabled entries
  2550. //
  2551. continue;
  2552. }
  2553. //
  2554. // Several types of conflicts are possible:
  2555. //
  2556. if ( ThisEntry->SubordinateEntry == NULL &&
  2557. OtherEntry->SubordinateEntry == NULL ) {
  2558. //
  2559. // - this forest claims "acme.com"
  2560. // - the other forest also claims "acme.com"
  2561. //
  2562. ConflictEntry = OtherEntry;
  2563. LsapDsDebugOut(( DEB_FTINFO, "Entry %p is in conflict with entry %p (%s:%d)\n", ThisEntry, OtherEntry, __FILE__, __LINE__ ));
  2564. } else if ( ThisEntry->SubordinateEntry == NULL &&
  2565. OtherEntry->SubordinateEntry != NULL ) {
  2566. //
  2567. // - this forest claims "acme.com"
  2568. // - the other forest claims "foo.ny.acme.com"
  2569. // - this forest does not disown
  2570. // either "ny.acme.com" or "foo.ny.acme.com"
  2571. //
  2572. TLN_ENTRY * SubEntry;
  2573. for ( SubEntry = OtherEntry->SubordinateEntry;
  2574. SubEntry != NULL;
  2575. SubEntry = SubEntry->SubordinateEntry ) {
  2576. if ( ThisEntry->TdoEntry->Excludes( &SubEntry->TlnKey->TopLevelName )) {
  2577. break;
  2578. }
  2579. }
  2580. //
  2581. // SubEntry == NULL means the above loop has terminated
  2582. // without having found a matching exclusion record.
  2583. // Hence, this entry is in conflict
  2584. //
  2585. if ( SubEntry == NULL ) {
  2586. ConflictEntry = OtherEntry;
  2587. LsapDsDebugOut(( DEB_FTINFO, "Entry %p is in conflict with entry %p (%s:%d)\n", ThisEntry, OtherEntry, __FILE__, __LINE__ ));
  2588. }
  2589. } else if ( ThisEntry->SubordinateEntry != NULL &&
  2590. OtherEntry->SubordinateEntry == NULL ) {
  2591. //
  2592. // - this forest claims "foo.ny.acme.com"
  2593. // - the other forest claims "acme.com"
  2594. // - the other forest does not disown
  2595. // either "ny.acme.com" or "foo.ny.acme.com"
  2596. //
  2597. TLN_ENTRY * SubEntry;
  2598. for ( SubEntry = ThisEntry->SubordinateEntry;
  2599. SubEntry != NULL;
  2600. SubEntry = SubEntry->SubordinateEntry ) {
  2601. if ( OtherEntry->TdoEntry->Excludes( &SubEntry->TlnKey->TopLevelName )) {
  2602. break;
  2603. }
  2604. }
  2605. //
  2606. // SubEntry == NULL means the above loop has terminated
  2607. // without having found a matching exclusion record.
  2608. // Hence, this entry is in conflict
  2609. //
  2610. if ( SubEntry == NULL ) {
  2611. ConflictEntry = OtherEntry;
  2612. LsapDsDebugOut(( DEB_FTINFO, "Entry %p is in conflict with entry %p (%s:%d)\n", ThisEntry, OtherEntry, __FILE__, __LINE__ ));
  2613. }
  2614. }
  2615. if ( ConflictEntry != NULL &&
  2616. ( ThisEntry->SubordinateEntry != NULL ||
  2617. OtherEntry->SubordinateEntry != NULL ) &&
  2618. ( ThisEntry->TdoEntry->LocalForestEntry ||
  2619. OtherEntry->TdoEntry->LocalForestEntry )) {
  2620. //
  2621. // Non-equality conflicts where one of the sides is
  2622. // the local forest are allowed to stay, otherwise a
  2623. // forest named "bar.com" would not be able to establish
  2624. // trust with another forest named "foo.bar.com"
  2625. //
  2626. LsapDsDebugOut(( DEB_FTINFO, "Conflict between entry %p and entry %p has been cleared (%s:%d)\n", ThisEntry, OtherEntry, __FILE__, __LINE__ ));
  2627. ConflictEntry = NULL;
  2628. }
  2629. if ( ConflictEntry != NULL ) {
  2630. TLN_ENTRY * ConflictThis = ThisEntry;
  2631. TLN_ENTRY * ConflictOther = OtherEntry;
  2632. while ( ConflictThis->SubordinateEntry != NULL ) {
  2633. ConflictThis = ConflictThis->SubordinateEntry;
  2634. }
  2635. while ( ConflictOther->SubordinateEntry != NULL ) {
  2636. ConflictOther = ConflictOther->SubordinateEntry;
  2637. }
  2638. Status = AddConflictPair(
  2639. ConflictPairs,
  2640. ConflictPairsTotal,
  2641. ForestTrustTopLevelName,
  2642. ConflictThis,
  2643. LSA_TLN_DISABLED_CONFLICT,
  2644. ForestTrustTopLevelName,
  2645. ConflictOther,
  2646. LSA_TLN_DISABLED_CONFLICT
  2647. );
  2648. if ( !NT_SUCCESS( Status )) {
  2649. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: AddConflictPair returned 0x%x\n", Status ));
  2650. goto Error;
  2651. }
  2652. LsapDsDebugOut(( DEB_FTINFO, "Entry %p (index %d) is in conflict with entry %p (%s:%d)\n", ConflictThis, ConflictThis->Index, ConflictOther, __FILE__, __LINE__ ));
  2653. }
  2654. }
  2655. }
  2656. //
  2657. // Rules for an enabled domain information record:
  2658. //
  2659. // * No part of the DNS name must be equal to that of an enabled
  2660. // top level name corresponding to a different TDO unless the other
  2661. // TDO explicitly disowns the DNS name of this record
  2662. // * No part must be equal to that of an enabled domain info entry
  2663. // corresponding to a different TDO
  2664. //
  2665. for ( ListEntry = TdoEntryNew->DomainInfoList.Flink;
  2666. ListEntry != &TdoEntryNew->DomainInfoList;
  2667. ListEntry = ListEntry->Flink ) {
  2668. DOMAIN_INFO_ENTRY * ThisEntry;
  2669. ThisEntry = DOMAIN_INFO_ENTRY::EntryFromTdoEntry( ListEntry );
  2670. if ( ThisEntry->SubordinateTo == NULL ) {
  2671. //
  2672. // Skip over store-and-ignore entries
  2673. //
  2674. ASSERT( ThisEntry->IsSidAdminDisabled());
  2675. continue;
  2676. }
  2677. if ( !ThisEntry->SubordinateTo->Enabled()) {
  2678. //
  2679. // Only consider enabled entries
  2680. //
  2681. continue;
  2682. }
  2683. if ( ThisEntry->TdoEntry->Excludes( &ThisEntry->DnsKey->DnsName )) {
  2684. //
  2685. // Entries excluded by this TDO are not considered either
  2686. //
  2687. continue;
  2688. }
  2689. //
  2690. // Check for SID conflicts
  2691. //
  2692. if ( ThisEntry->SidEnabled()) {
  2693. for ( LIST_ENTRY * ListEntrySid = ThisEntry->SidKey->List.Flink;
  2694. ListEntrySid != &ThisEntry->SidKey->List;
  2695. ListEntrySid = ListEntrySid->Flink ) {
  2696. DOMAIN_INFO_ENTRY * OtherEntry;
  2697. OtherEntry = DOMAIN_INFO_ENTRY::EntryFromSidEntry( ListEntrySid );
  2698. if ( OtherEntry->SubordinateTo == NULL ) {
  2699. //
  2700. // Skip over store-and-ignore entries
  2701. //
  2702. ASSERT( OtherEntry->IsSidAdminDisabled());
  2703. continue;
  2704. }
  2705. if ( OtherEntry->TdoEntry == TdoEntryNew ||
  2706. OtherEntry->TdoEntry == TdoEntryOldOut ) {
  2707. //
  2708. // Only interested in entries corresponding to other TDOs
  2709. //
  2710. continue;
  2711. }
  2712. if ( !OtherEntry->SidEnabled() ||
  2713. !OtherEntry->SubordinateTo->Enabled()) {
  2714. //
  2715. // Only interested in enabled entries
  2716. //
  2717. continue;
  2718. }
  2719. //
  2720. // Conflict! SID claimed by two forests!
  2721. //
  2722. Status = AddConflictPair(
  2723. ConflictPairs,
  2724. ConflictPairsTotal,
  2725. ForestTrustDomainInfo,
  2726. ThisEntry,
  2727. LSA_SID_DISABLED_CONFLICT,
  2728. ForestTrustDomainInfo,
  2729. OtherEntry,
  2730. LSA_SID_DISABLED_CONFLICT
  2731. );
  2732. if ( !NT_SUCCESS( Status )) {
  2733. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: AddConflictPair returned 0x%x\n", Status ));
  2734. goto Error;
  2735. }
  2736. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: Entry %p (index %d) is in conflict with entry %p (%s:%d)\n", ThisEntry, ThisEntry->Index, OtherEntry, __FILE__, __LINE__ ));
  2737. }
  2738. //
  2739. // Cross-check DNS names with Netbios names
  2740. //
  2741. NETBIOS_NAME_KEY * NetbiosKey = ( NETBIOS_NAME_KEY * )RtlLookupElementGenericTableAvl(
  2742. &m_NetbiosNameTable,
  2743. &ThisEntry->DnsKey->DnsName
  2744. );
  2745. if ( NetbiosKey != NULL ) {
  2746. for ( LIST_ENTRY * ListEntryNB = NetbiosKey->List.Flink;
  2747. ListEntryNB != &NetbiosKey->List;
  2748. ListEntryNB = ListEntryNB->Flink ) {
  2749. DOMAIN_INFO_ENTRY * OtherEntry;
  2750. OtherEntry = DOMAIN_INFO_ENTRY::EntryFromNetbiosEntry( ListEntryNB );
  2751. if ( OtherEntry->SubordinateTo == NULL ) {
  2752. //
  2753. // Skip over store-and-ignore entries
  2754. //
  2755. ASSERT( OtherEntry->IsSidAdminDisabled());
  2756. continue;
  2757. }
  2758. if ( OtherEntry->TdoEntry == TdoEntryNew ||
  2759. OtherEntry->TdoEntry == TdoEntryOldOut ) {
  2760. //
  2761. // Only interested in entries corresponding to other TDOs
  2762. //
  2763. continue;
  2764. }
  2765. if ( !OtherEntry->NetbiosEnabled() ||
  2766. !OtherEntry->SubordinateTo->Enabled()) {
  2767. //
  2768. // Only interested in enabled entries
  2769. //
  2770. continue;
  2771. }
  2772. //
  2773. // Conflict! DNS name claimed by a Netbios name in another forest!
  2774. //
  2775. Status = AddConflictPair(
  2776. ConflictPairs,
  2777. ConflictPairsTotal,
  2778. ForestTrustDomainInfo,
  2779. ThisEntry,
  2780. LSA_SID_DISABLED_CONFLICT,
  2781. ForestTrustDomainInfo,
  2782. OtherEntry,
  2783. LSA_NB_DISABLED_CONFLICT
  2784. );
  2785. if ( !NT_SUCCESS( Status )) {
  2786. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: AddConflictPair returned 0x%x\n", Status ));
  2787. goto Error;
  2788. }
  2789. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: Entry %p (index %d) is in conflict with entry %p (%s:%d)\n", ThisEntry, ThisEntry->Index, OtherEntry, __FILE__, __LINE__ ));
  2790. }
  2791. }
  2792. }
  2793. //
  2794. // Check for NETBIOS conflicts
  2795. //
  2796. if ( ThisEntry->NetbiosKey &&
  2797. ThisEntry->NetbiosEnabled()) {
  2798. for ( LIST_ENTRY * ListEntryNB = ThisEntry->NetbiosKey->List.Flink;
  2799. ListEntryNB != &ThisEntry->NetbiosKey->List;
  2800. ListEntryNB = ListEntryNB->Flink ) {
  2801. DOMAIN_INFO_ENTRY * OtherEntry;
  2802. OtherEntry = DOMAIN_INFO_ENTRY::EntryFromNetbiosEntry( ListEntryNB );
  2803. if ( OtherEntry->SubordinateTo == NULL ) {
  2804. //
  2805. // Skip over store-and-ignore entries
  2806. //
  2807. ASSERT( OtherEntry->IsSidAdminDisabled());
  2808. continue;
  2809. }
  2810. if ( OtherEntry->TdoEntry == TdoEntryNew ||
  2811. OtherEntry->TdoEntry == TdoEntryOldOut ) {
  2812. //
  2813. // Only interested in entries corresponding to other TDOs
  2814. //
  2815. continue;
  2816. }
  2817. if ( !OtherEntry->NetbiosEnabled() ||
  2818. OtherEntry->NetbiosKey == NULL ||
  2819. !OtherEntry->SubordinateTo->Enabled()) {
  2820. //
  2821. // Only interested in enabled entries
  2822. //
  2823. continue;
  2824. }
  2825. //
  2826. // Conflict! Netbios name claimed by two forests!
  2827. //
  2828. Status = AddConflictPair(
  2829. ConflictPairs,
  2830. ConflictPairsTotal,
  2831. ForestTrustDomainInfo,
  2832. ThisEntry,
  2833. LSA_NB_DISABLED_CONFLICT,
  2834. ForestTrustDomainInfo,
  2835. OtherEntry,
  2836. LSA_NB_DISABLED_CONFLICT
  2837. );
  2838. if ( !NT_SUCCESS( Status )) {
  2839. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: AddConflictPair returned 0x%x\n", Status ));
  2840. goto Error;
  2841. }
  2842. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: Entry %p (index %d) is in conflict with entry %p (%s:%d)\n", ThisEntry, ThisEntry->Index, OtherEntry, __FILE__, __LINE__ ));
  2843. }
  2844. //
  2845. // Cross-check Netbios names with DNS names
  2846. //
  2847. DNS_NAME_KEY * DnsKey = ( DNS_NAME_KEY * )RtlLookupElementGenericTableAvl(
  2848. &m_DnsNameTable,
  2849. &ThisEntry->NetbiosKey->NetbiosName
  2850. );
  2851. if ( DnsKey != NULL ) {
  2852. for ( LIST_ENTRY * ListEntryDns = DnsKey->List.Flink;
  2853. ListEntryDns != &DnsKey->List;
  2854. ListEntryDns = ListEntryDns->Flink ) {
  2855. DOMAIN_INFO_ENTRY * OtherEntry;
  2856. OtherEntry = DOMAIN_INFO_ENTRY::EntryFromDnsEntry( ListEntryDns );
  2857. if ( OtherEntry->SubordinateTo == NULL ) {
  2858. //
  2859. // Skip over store-and-ignore entries
  2860. //
  2861. ASSERT( OtherEntry->IsSidAdminDisabled());
  2862. continue;
  2863. }
  2864. if ( OtherEntry->TdoEntry == TdoEntryNew ||
  2865. OtherEntry->TdoEntry == TdoEntryOldOut ) {
  2866. //
  2867. // Only interested in entries corresponding to other TDOs
  2868. //
  2869. continue;
  2870. }
  2871. if ( !OtherEntry->SidEnabled() ||
  2872. !OtherEntry->SubordinateTo->Enabled()) {
  2873. //
  2874. // Only interested in enabled entries
  2875. //
  2876. continue;
  2877. }
  2878. //
  2879. // Conflict! Netbios name claimed by a DNS name in another forest!
  2880. //
  2881. Status = AddConflictPair(
  2882. ConflictPairs,
  2883. ConflictPairsTotal,
  2884. ForestTrustDomainInfo,
  2885. ThisEntry,
  2886. LSA_NB_DISABLED_CONFLICT,
  2887. ForestTrustDomainInfo,
  2888. OtherEntry,
  2889. LSA_SID_DISABLED_CONFLICT
  2890. );
  2891. if ( !NT_SUCCESS( Status )) {
  2892. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: AddConflictPair returned 0x%x\n", Status ));
  2893. goto Error;
  2894. }
  2895. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert: Entry %p (index %d) is in conflict with entry %p (%s:%d)\n", ThisEntry, ThisEntry->Index, OtherEntry, __FILE__, __LINE__ ));
  2896. }
  2897. }
  2898. }
  2899. }
  2900. //
  2901. // At this time, ConflictPairs array contains a
  2902. // complete list of pairs of entries that conflicted
  2903. //
  2904. Status = STATUS_SUCCESS;
  2905. Cleanup:
  2906. *TdoEntryNewOut = TdoEntryNew;
  2907. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Insert returning, Status: 0x%x\n", Status ));
  2908. return Status;
  2909. Error:
  2910. ASSERT( !NT_SUCCESS( Status ));
  2911. if ( TdoEntryNew ) {
  2912. RollbackChanges( TdoEntryNew, TdoEntryOldOut );
  2913. TdoEntryNew = NULL;
  2914. }
  2915. //
  2916. // Make sure no "old entry" nonsense is returned
  2917. // to the caller in case of error
  2918. //
  2919. ASSERT( TdoEntryOldOut->RecordCount == 0 );
  2920. if ( *ConflictPairs != NULL ) {
  2921. FtcFree( *ConflictPairs );
  2922. *ConflictPairs = NULL;
  2923. *ConflictPairsTotal = 0;
  2924. }
  2925. goto Cleanup;
  2926. }
  2927. NTSTATUS
  2928. FTCache::Remove(
  2929. IN UNICODE_STRING * TrustedDomainName
  2930. )
  2931. /*++
  2932. Routine Description:
  2933. Removes all entires corresponding to the given trusted domain information
  2934. name from the forest trust cache
  2935. Arguments:
  2936. TrustedDomainName name of the TDO to be wiped from the cache
  2937. Returns:
  2938. STATUS_SUCCESS entries corresponding to the given TDO have been
  2939. successfully removed
  2940. STATUS_NOT_FOUND there was no entry by this name in the cache
  2941. STATUS_INVALID_PARAMETER name of the TDO was invalid
  2942. --*/
  2943. {
  2944. NTSTATUS Status;
  2945. TDO_ENTRY * TdoEntry = NULL;
  2946. ASSERT( m_Initialized );
  2947. if ( TrustedDomainName == NULL ) {
  2948. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Remove\n" ));
  2949. return STATUS_INVALID_PARAMETER;
  2950. }
  2951. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Remove called, TDO: %wZ\n", TrustedDomainName ));
  2952. //
  2953. // Locate the cache entry corresponding to this TDO
  2954. //
  2955. TdoEntry = ( TDO_ENTRY * )RtlLookupElementGenericTableAvl(
  2956. &m_TdoTable,
  2957. TrustedDomainName
  2958. );
  2959. if ( TdoEntry == NULL ) {
  2960. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Remove could not locate an entry for %wZ\n", TrustedDomainName ));
  2961. Status = STATUS_NOT_FOUND;
  2962. goto Error;
  2963. } else if ( TdoEntry->LocalForestEntry ) {
  2964. //
  2965. // The information about the local forest can not be removed,
  2966. // it can only be replaced.
  2967. //
  2968. // The entire cache must be invalidated in order to get rid of it.
  2969. //
  2970. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Remove not removing local entry %wZ\n", TrustedDomainName ));
  2971. } else {
  2972. RemoveTdoEntry( TdoEntry );
  2973. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Remove successfully removed entry %wZ\n", TrustedDomainName ));
  2974. }
  2975. Status = STATUS_SUCCESS;
  2976. Cleanup:
  2977. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Remove returning, Status: 0x%x\n", Status ));
  2978. return Status;
  2979. Error:
  2980. ASSERT( !NT_SUCCESS( Status ));
  2981. goto Cleanup;
  2982. }
  2983. NTSTATUS
  2984. FTCache::Retrieve(
  2985. IN UNICODE_STRING * TrustedDomainName,
  2986. OUT LSA_FOREST_TRUST_INFORMATION * * ForestTrustInfo
  2987. )
  2988. /*++
  2989. Routine Description:
  2990. Retrieves forest trust information corresponding to a given TDO name
  2991. from the forest trust cache
  2992. Arguments:
  2993. TrustedDomainName name of the TDO to be queried
  2994. ForestTrustInfo used to return forest trust information data
  2995. for that TDO
  2996. Returns:
  2997. STATUS_SUCCESS entries corresponding to the given TDO have been
  2998. successfully returned
  2999. STATUS_NOT_FOUND this TDO is not in the cache
  3000. STATUS_INSUFFICIENT_RESOURCES out of memory
  3001. STATUS_INVALID_PARAMETER name of the TDO was invalid
  3002. STATUS_INTERNAL_ERROR the cache is in an inconsistent state
  3003. --*/
  3004. {
  3005. NTSTATUS Status;
  3006. LIST_ENTRY * ListEntry;
  3007. TDO_ENTRY * TdoEntry = NULL;
  3008. if ( TrustedDomainName == NULL ||
  3009. ForestTrustInfo == NULL ) {
  3010. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Retrieve (%s:%d)\n", __FILE__, __LINE__ ));
  3011. return STATUS_INVALID_PARAMETER;
  3012. }
  3013. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Retrieve called, TDO: %wZ\n", TrustedDomainName ));
  3014. *ForestTrustInfo = NULL;
  3015. //
  3016. // If the cache is not valid, do not even bother to proceed
  3017. //
  3018. if ( !IsExternalValid()) {
  3019. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Retrieve called on an invalid cache\n" ));
  3020. Status = STATUS_INTERNAL_ERROR;
  3021. goto Error;
  3022. }
  3023. //
  3024. // Locate the cache entry corresponding to this TDO
  3025. //
  3026. TdoEntry = ( TDO_ENTRY * )RtlLookupElementGenericTableAvl(
  3027. &m_TdoTable,
  3028. TrustedDomainName
  3029. );
  3030. if ( TdoEntry == NULL ) {
  3031. Status = STATUS_NOT_FOUND;
  3032. goto Error;
  3033. } else if ( TdoEntry->LocalForestEntry ) {
  3034. //
  3035. // The caller should ensure that local forest info is not retrieved
  3036. //
  3037. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Retrieve called asking for local trust information\n" ));
  3038. Status = STATUS_NOT_FOUND;
  3039. ASSERT( FALSE );
  3040. goto Error;
  3041. }
  3042. *ForestTrustInfo = ( LSA_FOREST_TRUST_INFORMATION * )FtcAllocate(
  3043. sizeof( LSA_FOREST_TRUST_INFORMATION )
  3044. );
  3045. if ( *ForestTrustInfo == NULL ) {
  3046. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Retrieve (%s:%d)\n", __FILE__, __LINE__ ));
  3047. Status = STATUS_INSUFFICIENT_RESOURCES;
  3048. goto Error;
  3049. }
  3050. (*ForestTrustInfo)->RecordCount = 0;
  3051. (*ForestTrustInfo)->Entries = ( LSA_FOREST_TRUST_RECORD * * )FtcAllocate(
  3052. TdoEntry->RecordCount * sizeof( LSA_FOREST_TRUST_RECORD * )
  3053. );
  3054. if ( (*ForestTrustInfo)->Entries == NULL ) {
  3055. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Retrieve (%s:%d)\n", __FILE__, __LINE__ ));
  3056. Status = STATUS_INSUFFICIENT_RESOURCES;
  3057. goto Error;
  3058. }
  3059. //
  3060. // Read top level name entries for this TDO
  3061. //
  3062. for ( ListEntry = TdoEntry->TlnList.Flink;
  3063. ListEntry != &TdoEntry->TlnList;
  3064. ListEntry = ListEntry->Flink ) {
  3065. TLN_ENTRY * TlnEntry;
  3066. LSA_FOREST_TRUST_RECORD * Record;
  3067. TlnEntry = TLN_ENTRY::EntryFromTdoEntry( ListEntry );
  3068. if ( TlnEntry->Excluded ||
  3069. TlnEntry->SubordinateEntry == NULL ) {
  3070. Record = RecordFromTopLevelNameEntry( TlnEntry );
  3071. if ( Record == NULL ) {
  3072. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Retrieve (%s:%d)\n", __FILE__, __LINE__ ));
  3073. Status = STATUS_INSUFFICIENT_RESOURCES;
  3074. goto Error;
  3075. }
  3076. ASSERT( (*ForestTrustInfo)->RecordCount < TdoEntry->RecordCount );
  3077. (*ForestTrustInfo)->Entries[(*ForestTrustInfo)->RecordCount] = Record;
  3078. (*ForestTrustInfo)->RecordCount += 1;
  3079. }
  3080. }
  3081. //
  3082. // Read domain info entries for this TDO
  3083. //
  3084. for ( ListEntry = TdoEntry->DomainInfoList.Flink;
  3085. ListEntry != &TdoEntry->DomainInfoList;
  3086. ListEntry = ListEntry->Flink ) {
  3087. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  3088. LSA_FOREST_TRUST_RECORD * Record;
  3089. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromTdoEntry( ListEntry );
  3090. Record = RecordFromDomainInfoEntry( DomainInfoEntry );
  3091. if ( Record == NULL ) {
  3092. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Retrieve (%s:%d)\n", __FILE__, __LINE__ ));
  3093. Status = STATUS_INSUFFICIENT_RESOURCES;
  3094. goto Error;
  3095. }
  3096. ASSERT( (*ForestTrustInfo)->RecordCount < TdoEntry->RecordCount );
  3097. (*ForestTrustInfo)->Entries[(*ForestTrustInfo)->RecordCount] = Record;
  3098. (*ForestTrustInfo)->RecordCount += 1;
  3099. }
  3100. //
  3101. // Read binary entries for this TDO
  3102. //
  3103. for ( ListEntry = TdoEntry->BinaryList.Flink;
  3104. ListEntry != &TdoEntry->BinaryList;
  3105. ListEntry = ListEntry->Flink ) {
  3106. BINARY_ENTRY * BinaryEntry;
  3107. LSA_FOREST_TRUST_RECORD * Record;
  3108. BinaryEntry = BINARY_ENTRY::EntryFromTdoEntry( ListEntry );
  3109. Record = RecordFromBinaryEntry( BinaryEntry );
  3110. if ( Record == NULL ) {
  3111. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::Retrieve (%s:%d)\n", __FILE__, __LINE__ ));
  3112. Status = STATUS_INSUFFICIENT_RESOURCES;
  3113. goto Error;
  3114. }
  3115. ASSERT( (*ForestTrustInfo)->RecordCount < TdoEntry->RecordCount );
  3116. (*ForestTrustInfo)->Entries[(*ForestTrustInfo)->RecordCount] = Record;
  3117. (*ForestTrustInfo)->RecordCount += 1;
  3118. }
  3119. ASSERT( (*ForestTrustInfo)->RecordCount == TdoEntry->RecordCount );
  3120. Status = STATUS_SUCCESS;
  3121. Cleanup:
  3122. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Retrieve returning, Status: 0x%x\n", Status ));
  3123. return Status;
  3124. Error:
  3125. ASSERT( !NT_SUCCESS( Status ));
  3126. LsapFreeForestTrustInfo( *ForestTrustInfo );
  3127. FtcFree( *ForestTrustInfo );
  3128. *ForestTrustInfo = NULL;
  3129. goto Cleanup;
  3130. }
  3131. NTSTATUS
  3132. FTCache::Match(
  3133. IN LSA_ROUTING_MATCH_TYPE Type,
  3134. IN PVOID Data,
  3135. IN BOOLEAN SearchLocal,
  3136. OUT OPTIONAL UNICODE_STRING * TrustedDomainName,
  3137. OUT OPTIONAL PSID * TrustedDomainSid
  3138. )
  3139. /*++
  3140. Routine Description:
  3141. Finds match for given data in the cache
  3142. Arguments:
  3143. Type Type of Data parameter
  3144. Data Data to match
  3145. SearchLocal Search the local information only
  3146. TrustedDomainName Used to return the match, if one was found.
  3147. Caller must use LsaIFree_LSAPR_UNICODE_STRING_BUFFER
  3148. TrustedDomainSid Used to return the match, if one was found.
  3149. Caller must use MIDL_user_free
  3150. Returns:
  3151. STATUS_SUCCESS Match was found
  3152. STATUS_NO_MATCH Match was not found
  3153. STATUS_INVALID_PARAMETER Check the inputs
  3154. STATUS_INTERNAL_ERROR Cache is internally inconsistent
  3155. STATUS_INSUFFICIENT_RESOURCES Out of memory
  3156. --*/
  3157. {
  3158. NTSTATUS Status = STATUS_SUCCESS;
  3159. SID * Sid = NULL;
  3160. UNICODE_STRING * String = NULL;
  3161. BOOLEAN IsLocal = !SearchLocal; // Equivalent to "no match by default"
  3162. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Match called\n" ));
  3163. if ( Data == NULL ) {
  3164. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Match (%s:%d)\n", __FILE__, __LINE__ ));
  3165. return STATUS_INVALID_PARAMETER;
  3166. }
  3167. if ( TrustedDomainName ) {
  3168. RtlZeroMemory( TrustedDomainName, sizeof( UNICODE_STRING ));
  3169. }
  3170. if ( TrustedDomainSid ) {
  3171. *TrustedDomainSid = NULL;
  3172. }
  3173. switch ( Type ) {
  3174. case RoutingMatchDomainSid:
  3175. Sid = ( SID * )Data;
  3176. if ( !RtlValidSid( Sid )) {
  3177. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Match (%s:%d)\n", __FILE__, __LINE__ ));
  3178. return STATUS_INVALID_PARAMETER;
  3179. }
  3180. break;
  3181. case RoutingMatchDomainName:
  3182. case RoutingMatchUpn:
  3183. case RoutingMatchSpn:
  3184. case RoutingMatchNamespace:
  3185. String = ( UNICODE_STRING * )Data;
  3186. if ( !LsapValidateLsaUnicodeString( String )) {
  3187. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Match (%s:%d)\n", __FILE__, __LINE__ ));
  3188. return STATUS_INVALID_PARAMETER;
  3189. }
  3190. //
  3191. // ISSUE-2000/07/24-markpu
  3192. // is it appopriate to modify UPNs and SPNs prior to matching?
  3193. //
  3194. LsapRemoveTrailingDot( String, FALSE );
  3195. break;
  3196. default:
  3197. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::Match (%s:%d)\n", __FILE__, __LINE__ ));
  3198. return STATUS_INVALID_PARAMETER;
  3199. }
  3200. LsapDbAcquireReadLockTrustedDomainList();
  3201. if ( SearchLocal && !IsLocalValid()) {
  3202. //
  3203. // Searching a local cache and local information is invalid -- rebuild
  3204. //
  3205. LsapDbConvertReadLockTrustedDomainListToExclusive();
  3206. Status = LsapForestTrustInsertLocalInfo();
  3207. LsapDbConvertWriteLockTrustedDomainListToShared();
  3208. if ( !NT_SUCCESS( Status )) {
  3209. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Match: attempt to rebuild the cache failed with 0x%x\n", Status ));
  3210. goto Error;
  3211. } else {
  3212. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Match: cache rebuilt successfully\n" ));
  3213. }
  3214. }
  3215. if ( !SearchLocal && !IsExternalValid()) {
  3216. //
  3217. // Searching for non-local information
  3218. // Rebuilding code on a GC outside of a root domain differs
  3219. // from what is done on every DC in the root domain
  3220. //
  3221. if ( SamIAmIGC() && !LsapDbDcInRootDomain()) {
  3222. LsapDbConvertReadLockTrustedDomainListToExclusive();
  3223. LsapForestTrustCacheSetInvalid();
  3224. //
  3225. // DCs in the root domain must not allow other forests to claim SIDs
  3226. // and namespaces that conflict with their own forest
  3227. // For that, the information about the current forest is inserted
  3228. // into the forest trust cache as just another (though special) entry
  3229. //
  3230. Status = LsapForestTrustInsertLocalInfo();
  3231. if ( NT_SUCCESS( Status )) {
  3232. Status = LsapRebuildFtCacheGC();
  3233. }
  3234. LsapDbConvertWriteLockTrustedDomainListToShared();
  3235. } else {
  3236. LsapDbConvertReadLockTrustedDomainListToExclusive();
  3237. Status = LsapDbBuildTrustedDomainCache();
  3238. LsapDbConvertWriteLockTrustedDomainListToShared();
  3239. }
  3240. if ( !NT_SUCCESS( Status )) {
  3241. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Match: attempt to rebuild the cache failed with 0x%x\n", Status ));
  3242. goto Error;
  3243. } else {
  3244. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Match: cache rebuilt successfully\n" ));
  3245. }
  3246. }
  3247. //
  3248. // The information we're looking for better be valid
  3249. //
  3250. ASSERT(( SearchLocal && IsLocalValid()) || ( !SearchLocal && IsExternalValid()));
  3251. //
  3252. // Guard against stack overflows and such
  3253. //
  3254. __try {
  3255. switch ( Type ) {
  3256. case RoutingMatchDomainSid:
  3257. Status = MatchSid( Sid, &IsLocal, TrustedDomainName, TrustedDomainSid );
  3258. break;
  3259. case RoutingMatchDomainName:
  3260. Status = MatchDnsName( String, &IsLocal, TrustedDomainName, TrustedDomainSid );
  3261. if ( Status == STATUS_NO_MATCH ) {
  3262. Status = MatchNetbiosName( String, &IsLocal, TrustedDomainName, TrustedDomainSid );
  3263. }
  3264. break;
  3265. case RoutingMatchUpn:
  3266. Status = MatchUpn( String, &IsLocal, TrustedDomainName, TrustedDomainSid );
  3267. break;
  3268. case RoutingMatchSpn:
  3269. Status = MatchSpn( String, &IsLocal, TrustedDomainName, TrustedDomainSid );
  3270. break;
  3271. case RoutingMatchNamespace:
  3272. Status = MatchNamespace( String, &IsLocal, TrustedDomainName, TrustedDomainSid );
  3273. break;
  3274. default:
  3275. ASSERT( FALSE );
  3276. }
  3277. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  3278. Status = GetExceptionCode();
  3279. goto Error;
  3280. }
  3281. //
  3282. // If we were looking for a local match and found a non-local match instead,
  3283. // that's the same as if no match was found.
  3284. //
  3285. if ( NT_SUCCESS( Status ) &&
  3286. (( IsLocal == FALSE ) != ( SearchLocal == FALSE ))) {
  3287. Status = STATUS_NO_MATCH;
  3288. if ( TrustedDomainName != NULL ) {
  3289. LsaIFree_LSAPR_UNICODE_STRING_BUFFER(
  3290. ( PLSAPR_UNICODE_STRING ) TrustedDomainName
  3291. );
  3292. RtlZeroMemory( TrustedDomainName, sizeof( UNICODE_STRING ));
  3293. }
  3294. if ( TrustedDomainSid != NULL ) {
  3295. MIDL_user_free( *TrustedDomainSid );
  3296. *TrustedDomainSid = NULL;
  3297. }
  3298. goto Error;
  3299. }
  3300. Cleanup:
  3301. LsapDbReleaseLockTrustedDomainList();
  3302. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Match returning, Status: 0x%lx\n", Status ));
  3303. return Status;
  3304. Error:
  3305. ASSERT( !NT_SUCCESS( Status ));
  3306. goto Cleanup;
  3307. }
  3308. ///////////////////////////////////////////////////////////////////////////////
  3309. //
  3310. // FTCache private methods
  3311. //
  3312. ///////////////////////////////////////////////////////////////////////////////
  3313. void
  3314. FTCache::Purge()
  3315. /*++
  3316. Routine Description:
  3317. Removes the contents of the cache
  3318. Arguments:
  3319. None
  3320. Returns:
  3321. Nothing
  3322. --*/
  3323. {
  3324. TDO_ENTRY * TdoEntry;
  3325. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Purge called\n" ));
  3326. for ( TdoEntry = ( TDO_ENTRY * )RtlEnumerateGenericTableAvl( &m_TdoTable, TRUE );
  3327. TdoEntry != NULL;
  3328. TdoEntry = ( TDO_ENTRY * )RtlEnumerateGenericTableAvl( &m_TdoTable, TRUE )) {
  3329. RemoveTdoEntry( TdoEntry );
  3330. }
  3331. LsapDsDebugOut(( DEB_FTINFO, "FTCache::Purge returning\n" ));
  3332. }
  3333. void
  3334. FTCache::RollbackChanges(
  3335. IN TDO_ENTRY * TdoEntryNew,
  3336. IN TDO_ENTRY * TdoEntryOld
  3337. )
  3338. /*++
  3339. Routine Description:
  3340. Arguments:
  3341. TdoEntryNew result of inserting new data into the cache
  3342. TdoEntryOld old contents of the cache
  3343. (Record count of 0 indicates no previous contents)
  3344. Returns:
  3345. Nothing
  3346. --*/
  3347. {
  3348. ASSERT( TdoEntryNew );
  3349. ASSERT( TdoEntryOld );
  3350. if ( TdoEntryOld->RecordCount > 0 ) {
  3351. //
  3352. // Reinstate old contents of the entry
  3353. // if the old entry is non-empty
  3354. //
  3355. PurgeTdoEntry( TdoEntryNew );
  3356. CopyTdoEntry( TdoEntryNew, TdoEntryOld );
  3357. } else {
  3358. //
  3359. // Altogether remove the node from the tree
  3360. // if there is nothing to reinstate
  3361. //
  3362. RemoveTdoEntry( TdoEntryNew );
  3363. }
  3364. //
  3365. // We've taken over the old entry.
  3366. // Leave it in an invalid state.
  3367. //
  3368. RtlZeroMemory( TdoEntryOld, sizeof( TDO_ENTRY ));
  3369. }
  3370. void
  3371. FTCache::PurgeTdoEntry(
  3372. IN TDO_ENTRY * TdoEntry
  3373. )
  3374. /*++
  3375. Routine Description:
  3376. Cleans up all entries associated with a given TDO entry
  3377. but leaves the other fields alone
  3378. Arguments:
  3379. TdoEntry entry to purge
  3380. Returns:
  3381. Nothing
  3382. --*/
  3383. {
  3384. //
  3385. // Remove TDO entries from the top level name table
  3386. //
  3387. while ( !IsListEmpty( &TdoEntry->TlnList )) {
  3388. TLN_ENTRY * TlnEntry;
  3389. TlnEntry = TLN_ENTRY::EntryFromTdoEntry( TdoEntry->TlnList.Flink );
  3390. RemoveEntryList( &TlnEntry->TdoListEntry );
  3391. RemoveEntryList( &TlnEntry->AvlListEntry );
  3392. ASSERT( TlnEntry->TlnKey );
  3393. TlnEntry->TlnKey->Count -= 1;
  3394. //
  3395. // If this is the last entry for this top level name in the tree,
  3396. // remove the associated key from the list
  3397. //
  3398. if ( IsListEmpty( &TlnEntry->TlnKey->List )) {
  3399. BOOLEAN Found;
  3400. ASSERT( TlnEntry->TlnKey->Count == 0 );
  3401. Found = RtlDeleteElementGenericTableAvl(
  3402. &m_TopLevelNameTable,
  3403. &TlnEntry->TlnKey->TopLevelName
  3404. );
  3405. ASSERT( sm_TlnKeys-- > 0 );
  3406. ASSERT( Found ); // better be there!!!
  3407. }
  3408. FtcFree( TlnEntry );
  3409. ASSERT( sm_TlnEntries-- > 0 );
  3410. }
  3411. //
  3412. // Remove TDO entries from the DomainInfo-related tables
  3413. //
  3414. while ( !IsListEmpty( &TdoEntry->DomainInfoList )) {
  3415. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  3416. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromTdoEntry( TdoEntry->DomainInfoList.Flink );
  3417. RemoveEntryList( &DomainInfoEntry->TdoListEntry );
  3418. RemoveEntryList( &DomainInfoEntry->SidAvlListEntry );
  3419. RemoveEntryList( &DomainInfoEntry->DnsAvlListEntry );
  3420. RemoveEntryList( &DomainInfoEntry->NetbiosAvlListEntry );
  3421. ASSERT( DomainInfoEntry->SidKey );
  3422. DomainInfoEntry->SidKey->Count -= 1;
  3423. //
  3424. // If this is the last entry for the domain SID in the tree,
  3425. // remove the associated key from the list
  3426. //
  3427. if ( IsListEmpty( &DomainInfoEntry->SidKey->List )) {
  3428. BOOLEAN Found;
  3429. ASSERT( DomainInfoEntry->SidKey->Count == 0 );
  3430. Found = RtlDeleteElementGenericTableAvl(
  3431. &m_DomainSidTable,
  3432. &DomainInfoEntry->SidKey->DomainSid
  3433. );
  3434. ASSERT( sm_SidKeys-- > 0 );
  3435. ASSERT( Found ); // better be there!
  3436. }
  3437. ASSERT( DomainInfoEntry->DnsKey );
  3438. DomainInfoEntry->DnsKey->Count -= 1;
  3439. //
  3440. // If this is the last entry for the DNS name in the tree,
  3441. // remove the associated key from the list
  3442. //
  3443. if ( IsListEmpty( &DomainInfoEntry->DnsKey->List )) {
  3444. BOOLEAN Found;
  3445. ASSERT( DomainInfoEntry->DnsKey->Count == 0 );
  3446. Found = RtlDeleteElementGenericTableAvl(
  3447. &m_DnsNameTable,
  3448. &DomainInfoEntry->DnsKey->DnsName
  3449. );
  3450. ASSERT( sm_DnsNameKeys-- > 0 );
  3451. ASSERT( Found ); // better be there!
  3452. }
  3453. if ( DomainInfoEntry->NetbiosKey != NULL ) {
  3454. DomainInfoEntry->NetbiosKey->Count -= 1;
  3455. //
  3456. // If this is the last entry for the DNS name in the tree,
  3457. // remove the associated key from the list
  3458. //
  3459. if ( IsListEmpty( &DomainInfoEntry->NetbiosKey->List )) {
  3460. BOOLEAN Found;
  3461. ASSERT( DomainInfoEntry->NetbiosKey->Count == 0 );
  3462. Found = RtlDeleteElementGenericTableAvl(
  3463. &m_NetbiosNameTable,
  3464. &DomainInfoEntry->NetbiosKey->NetbiosName
  3465. );
  3466. ASSERT( sm_NetbiosNameKeys-- > 0 );
  3467. ASSERT( Found ); // better be there!
  3468. }
  3469. }
  3470. FtcFree( DomainInfoEntry->Sid );
  3471. FtcFree( DomainInfoEntry );
  3472. ASSERT( sm_DomainInfoEntries-- > 0 );
  3473. }
  3474. //
  3475. // Remove binary entries for this TDO
  3476. //
  3477. while ( !IsListEmpty( &TdoEntry->BinaryList )) {
  3478. BINARY_ENTRY * BinaryEntry;
  3479. BinaryEntry = BINARY_ENTRY::EntryFromTdoEntry( TdoEntry->BinaryList.Flink );
  3480. RemoveEntryList( &BinaryEntry->TdoListEntry );
  3481. FtcFree( BinaryEntry->Data.Buffer );
  3482. FtcFree( BinaryEntry );
  3483. ASSERT( sm_BinaryEntries-- > 0 );
  3484. }
  3485. //
  3486. // This entry no longer contains anything of interest
  3487. //
  3488. TdoEntry->RecordCount = 0;
  3489. FtcFree( TdoEntry->TrustedDomainSid );
  3490. TdoEntry->TrustedDomainSid = NULL;
  3491. ASSERT( IsListEmpty( &TdoEntry->TlnList ));
  3492. ASSERT( IsListEmpty( &TdoEntry->DomainInfoList ));
  3493. ASSERT( IsListEmpty( &TdoEntry->BinaryList ));
  3494. }
  3495. void
  3496. FTCache::RemoveTdoEntry(
  3497. IN TDO_ENTRY * TdoEntry
  3498. )
  3499. /*++
  3500. Routine Description:
  3501. Removes the corresponding TdoEntry and all its associated data from the cache
  3502. Arguments:
  3503. TdoEntry Entry to remove
  3504. Returns:
  3505. Nothing
  3506. --*/
  3507. {
  3508. BOOLEAN Found;
  3509. ASSERT( TdoEntry );
  3510. LsapDsDebugOut(( DEB_FTINFO, "FTCache::RemoveTdoEntry called, TdoEntry is %p\n", TdoEntry ));
  3511. PurgeTdoEntry( TdoEntry );
  3512. //
  3513. // Remove the cache entry from the list and free it
  3514. //
  3515. Found = RtlDeleteElementGenericTableAvl(
  3516. &m_TdoTable,
  3517. &TdoEntry->TrustedDomainName
  3518. );
  3519. ASSERT( sm_TdoEntries-- > 0 );
  3520. ASSERT( Found );
  3521. LsapDsDebugOut(( DEB_FTINFO, "FTCache::RemoveTdoEntry returning\n" ));
  3522. }
  3523. void
  3524. FTCache::CopyTdoEntry(
  3525. IN TDO_ENTRY * Destination,
  3526. IN TDO_ENTRY * Source
  3527. )
  3528. /*++
  3529. Routine Description:
  3530. Creates a temporary copy of a TDO entry, the copy is used in rollback code.
  3531. No new memory is allocated, the data is merely stored away for a while.
  3532. Arguments:
  3533. Destination Entry to fill in
  3534. Source Entry to get the data from
  3535. Returns:
  3536. Nothing
  3537. --*/
  3538. {
  3539. LIST_ENTRY * ListEntry;
  3540. *Destination = *Source;
  3541. //
  3542. // Make the list entries point to the backup copy of the TDO entry
  3543. // (we're about to reuse the contents of *Source)
  3544. //
  3545. if ( IsListEmpty( &Source->TlnList )) {
  3546. InitializeListHead( &Destination->TlnList );
  3547. } else {
  3548. Destination->TlnList.Flink->Blink = &Destination->TlnList;
  3549. Destination->TlnList.Blink->Flink = &Destination->TlnList;
  3550. }
  3551. if ( IsListEmpty( &Source->DomainInfoList )) {
  3552. InitializeListHead( &Destination->DomainInfoList );
  3553. } else {
  3554. Destination->DomainInfoList.Flink->Blink = &Destination->DomainInfoList;
  3555. Destination->DomainInfoList.Blink->Flink = &Destination->DomainInfoList;
  3556. }
  3557. if ( IsListEmpty( &Source->BinaryList )) {
  3558. InitializeListHead( &Destination->BinaryList );
  3559. } else {
  3560. Destination->BinaryList.Flink->Blink = &Destination->BinaryList;
  3561. Destination->BinaryList.Blink->Flink = &Destination->BinaryList;
  3562. }
  3563. //
  3564. // Point all the "TdoEntry" member variables of all components to
  3565. // Destination so there is no confusion when testing for duplicates
  3566. //
  3567. for ( ListEntry = Destination->TlnList.Flink;
  3568. ListEntry != &Destination->TlnList;
  3569. ListEntry = ListEntry->Flink ) {
  3570. TLN_ENTRY * TlnEntry;
  3571. TlnEntry = TLN_ENTRY::EntryFromTdoEntry( ListEntry );
  3572. TlnEntry->TdoEntry = Destination;
  3573. }
  3574. for ( ListEntry = Destination->DomainInfoList.Flink;
  3575. ListEntry != &Destination->DomainInfoList;
  3576. ListEntry = ListEntry->Flink ) {
  3577. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  3578. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromTdoEntry( ListEntry );
  3579. DomainInfoEntry->TdoEntry = Destination;
  3580. }
  3581. }
  3582. LSA_FOREST_TRUST_RECORD *
  3583. FTCache::RecordFromTopLevelNameEntry(
  3584. IN TLN_ENTRY * Entry
  3585. )
  3586. /*++
  3587. Routine Description:
  3588. Creates a forest trust record structure from a top level name entry
  3589. Arguments:
  3590. Entry top level name entry to convert
  3591. Returns:
  3592. Allocated top level name record or NULL if out of memory
  3593. --*/
  3594. {
  3595. LSA_FOREST_TRUST_RECORD * Record;
  3596. ASSERT( Entry->Excluded ||
  3597. Entry->SubordinateEntry == NULL );
  3598. Record = ( LSA_FOREST_TRUST_RECORD * )FtcAllocate(
  3599. sizeof( LSA_FOREST_TRUST_RECORD )
  3600. );
  3601. if ( Record == NULL ) {
  3602. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::RecordFromTopLevelEntry (%s:%d)\n", __FILE__, __LINE__ ));
  3603. goto Error;
  3604. }
  3605. Record->Time = Entry->Time;
  3606. Record->Flags = Entry->Flags();
  3607. Record->ForestTrustType = Entry->Excluded ?
  3608. ForestTrustTopLevelNameEx :
  3609. ForestTrustTopLevelName;
  3610. if ( FALSE == FtcCopyUnicodeString(
  3611. &Record->ForestTrustData.TopLevelName,
  3612. &Entry->TlnKey->TopLevelName )) {
  3613. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::RecordFromTopLevelEntry (%s:%d)\n", __FILE__, __LINE__ ));
  3614. goto Error;
  3615. }
  3616. Cleanup:
  3617. return Record;
  3618. Error:
  3619. FtcFree( Record );
  3620. Record = NULL;
  3621. goto Cleanup;
  3622. }
  3623. LSA_FOREST_TRUST_RECORD *
  3624. FTCache::RecordFromDomainInfoEntry(
  3625. IN DOMAIN_INFO_ENTRY * Entry
  3626. )
  3627. /*++
  3628. Routine Description:
  3629. Creates a forest trust record structure from a domain info entry
  3630. Arguments:
  3631. Entry domain info entry to convert
  3632. Returns:
  3633. Allocated domain info record or NULL if out of memory
  3634. --*/
  3635. {
  3636. LSA_FOREST_TRUST_RECORD * Record;
  3637. ULONG SidLength;
  3638. Record = ( LSA_FOREST_TRUST_RECORD * )FtcAllocate(
  3639. sizeof( LSA_FOREST_TRUST_RECORD )
  3640. );
  3641. if ( Record == NULL ) {
  3642. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::RecordFromDomainInfoEntry (%s:%d)\n", __FILE__, __LINE__ ));
  3643. goto Error;
  3644. }
  3645. ASSERT( RtlValidSid( Entry->Sid ));
  3646. SidLength = RtlLengthSid( Entry->Sid );
  3647. ASSERT( SidLength > 0 );
  3648. Record->Time = Entry->Time;
  3649. Record->Flags = Entry->Flags();
  3650. Record->ForestTrustType = ForestTrustDomainInfo;
  3651. Record->ForestTrustData.DomainInfo.Sid = ( SID * )FtcAllocate( SidLength );
  3652. if ( Record->ForestTrustData.DomainInfo.Sid == NULL ) {
  3653. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::RecordFromDomainInfoEntry (%s:%d)\n", __FILE__, __LINE__ ));
  3654. goto Error;
  3655. }
  3656. RtlCopySid( SidLength, ( SID * )Record->ForestTrustData.DomainInfo.Sid, Entry->Sid );
  3657. if ( FALSE == FtcCopyUnicodeString(
  3658. ( UNICODE_STRING * )&Record->ForestTrustData.DomainInfo.DnsName,
  3659. &Entry->DnsKey->DnsName )) {
  3660. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::RecordFromDomainInfoEntry (%s:%d)\n", __FILE__, __LINE__ ));
  3661. FtcFree( Record->ForestTrustData.DomainInfo.Sid );
  3662. goto Error;
  3663. }
  3664. if ( Entry->NetbiosKey != NULL ) {
  3665. if ( FALSE == FtcCopyUnicodeString(
  3666. ( UNICODE_STRING * )&Record->ForestTrustData.DomainInfo.NetbiosName,
  3667. &Entry->NetbiosKey->NetbiosName )) {
  3668. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::RecordFromDomainInfoEntry (%s:%d)\n", __FILE__, __LINE__ ));
  3669. FtcFree( Record->ForestTrustData.DomainInfo.DnsName.Buffer );
  3670. FtcFree( Record->ForestTrustData.DomainInfo.Sid );
  3671. goto Error;
  3672. }
  3673. } else {
  3674. Record->ForestTrustData.DomainInfo.NetbiosName.Buffer = NULL;
  3675. Record->ForestTrustData.DomainInfo.NetbiosName.Length = 0;
  3676. Record->ForestTrustData.DomainInfo.NetbiosName.MaximumLength = 0;
  3677. }
  3678. Cleanup:
  3679. return Record;
  3680. Error:
  3681. FtcFree( Record );
  3682. Record = NULL;
  3683. goto Cleanup;
  3684. }
  3685. LSA_FOREST_TRUST_RECORD *
  3686. FTCache::RecordFromBinaryEntry(
  3687. IN BINARY_ENTRY * Entry
  3688. )
  3689. /*++
  3690. Routine Description:
  3691. Creates a forest trust record structure from a binary entry
  3692. Arguments:
  3693. Entry binary entry to convert
  3694. Returns:
  3695. Allocated binary record or NULL if out of memory
  3696. --*/
  3697. {
  3698. LSA_FOREST_TRUST_RECORD * Record;
  3699. Record = ( LSA_FOREST_TRUST_RECORD * )FtcAllocate(
  3700. sizeof( LSA_FOREST_TRUST_RECORD )
  3701. );
  3702. if ( Record == NULL ) {
  3703. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::RecordFromBinaryEntry (%s:%d)\n", __FILE__, __LINE__ ));
  3704. goto Error;
  3705. }
  3706. Record->Time = Entry->Time;
  3707. Record->Flags = Entry->Flags();
  3708. Record->ForestTrustType = Entry->Type;
  3709. Record->ForestTrustData.Data.Length = Entry->Data.Length;
  3710. if ( Entry->Data.Length > 0 ) {
  3711. Record->ForestTrustData.Data.Buffer = ( BYTE * )FtcAllocate( Entry->Data.Length );
  3712. if ( Record->ForestTrustData.Data.Buffer == NULL ) {
  3713. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::RecordFromBinaryEntry (%s:%d)\n", __FILE__, __LINE__ ));
  3714. goto Error;
  3715. }
  3716. RtlCopyMemory(
  3717. Record->ForestTrustData.Data.Buffer,
  3718. Entry->Data.Buffer,
  3719. Entry->Data.Length
  3720. );
  3721. } else {
  3722. Record->ForestTrustData.Data.Buffer = NULL;
  3723. }
  3724. Cleanup:
  3725. return Record;
  3726. Error:
  3727. FtcFree( Record );
  3728. Record = NULL;
  3729. goto Cleanup;
  3730. }
  3731. NTSTATUS
  3732. FTCache::MatchSid(
  3733. IN SID * Sid,
  3734. OUT BOOLEAN * IsLocal,
  3735. OUT OPTIONAL UNICODE_STRING * TrustedDomainName,
  3736. OUT OPTIONAL PSID * TrustedDomainSid
  3737. )
  3738. /*++
  3739. Routine Description:
  3740. Locates a match for the given SID in the cache
  3741. Arguments:
  3742. Sid SID to match
  3743. IsLocal Indicates whether the result is a local match
  3744. TrustedDomainName Used to return the name of the trusted domain
  3745. TrustedDomainSid Used to return the SID of the trusted domain
  3746. Returns:
  3747. STATUS_SUCCESS Match was found
  3748. STATUS_NO_MATCH Match was not found
  3749. STATUS_INSUFFICIENT_RESOURCES Out of memory
  3750. STATUS_INVALID_PARAMETER Sid passed in not valid
  3751. STATUS_INVALID_SID Sid passed in not a valid account SID
  3752. STATUS_BUFFER_OVERFLOW Sid too long
  3753. --*/
  3754. {
  3755. NTSTATUS Status;
  3756. DOMAIN_SID_KEY * SidKey;
  3757. UNICODE_STRING * MatchName = NULL;
  3758. PSID MatchSid = NULL;
  3759. DWORD SidBuffer[256];
  3760. DWORD cbSid = sizeof( SidBuffer );
  3761. PSID DomainSid = ( PSID )SidBuffer;
  3762. //
  3763. // Caller must validate parameters
  3764. //
  3765. ASSERT( Sid );
  3766. ASSERT( RtlValidSid( Sid ));
  3767. if ( FALSE == GetWindowsAccountDomainSid(
  3768. Sid,
  3769. SidBuffer,
  3770. &cbSid )) {
  3771. DWORD ErrorCode = GetLastError();
  3772. switch( ErrorCode ) {
  3773. case ERROR_INVALID_SID:
  3774. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::MatchSid (%s:%d)\n", __FILE__, __LINE__ ));
  3775. Status = STATUS_INVALID_PARAMETER;
  3776. break;
  3777. case ERROR_INVALID_PARAMETER:
  3778. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::MatchSid (%s:%d)\n", __FILE__, __LINE__ ));
  3779. Status = STATUS_INVALID_PARAMETER;
  3780. break;
  3781. case ERROR_NON_ACCOUNT_SID:
  3782. Status = STATUS_INVALID_SID;
  3783. break;
  3784. case ERROR_INSUFFICIENT_BUFFER:
  3785. Status = STATUS_BUFFER_OVERFLOW;
  3786. break;
  3787. default:
  3788. ASSERT( FALSE ); // map the error code
  3789. Status = ErrorCode;
  3790. break;
  3791. }
  3792. goto Error;
  3793. }
  3794. SidKey = ( DOMAIN_SID_KEY * )RtlLookupElementGenericTableAvl(
  3795. &m_DomainSidTable,
  3796. &DomainSid
  3797. );
  3798. if ( SidKey == NULL ) {
  3799. Status = STATUS_NO_MATCH;
  3800. goto Error;
  3801. }
  3802. for ( LIST_ENTRY * ListEntry = SidKey->List.Flink;
  3803. ListEntry != &SidKey->List;
  3804. ListEntry = ListEntry->Flink ) {
  3805. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  3806. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromSidEntry( ListEntry );
  3807. if ( DomainInfoEntry->SubordinateTo == NULL ) {
  3808. //
  3809. // Skip over store-and-ignore entries
  3810. //
  3811. ASSERT( DomainInfoEntry->IsSidAdminDisabled());
  3812. continue;
  3813. }
  3814. //
  3815. // Conditions for an entry to be considered a match:
  3816. //
  3817. // - Entry must be enabled
  3818. // - corresponding top-level entry must be enabled
  3819. // - this entry must not be disowned by its TDO
  3820. //
  3821. if ( DomainInfoEntry->SidEnabled() &&
  3822. DomainInfoEntry->SubordinateTo->Enabled() &&
  3823. !DomainInfoEntry->TdoEntry->Excludes( &DomainInfoEntry->DnsKey->DnsName )) {
  3824. MatchName = &DomainInfoEntry->TdoEntry->TrustedDomainName;
  3825. MatchSid = DomainInfoEntry->TdoEntry->TrustedDomainSid;
  3826. *IsLocal = DomainInfoEntry->TdoEntry->LocalForestEntry;
  3827. break;
  3828. }
  3829. }
  3830. if ( MatchName == NULL || MatchSid == NULL ) {
  3831. Status = STATUS_NO_MATCH;
  3832. goto Error;
  3833. } else {
  3834. if ( TrustedDomainName &&
  3835. !FtcCopyUnicodeString( TrustedDomainName, MatchName )) {
  3836. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchSid (%s:%d)\n", __FILE__, __LINE__ ));
  3837. Status = STATUS_INSUFFICIENT_RESOURCES;
  3838. goto Error;
  3839. }
  3840. if ( TrustedDomainSid &&
  3841. !FtcCopySid( TrustedDomainSid, MatchSid )) {
  3842. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchSid (%s:%d)\n", __FILE__, __LINE__ ));
  3843. Status = STATUS_INSUFFICIENT_RESOURCES;
  3844. goto Error;
  3845. }
  3846. }
  3847. Status = STATUS_SUCCESS;
  3848. Cleanup:
  3849. return Status;
  3850. Error:
  3851. ASSERT( !NT_SUCCESS( Status ));
  3852. if ( TrustedDomainName ) {
  3853. FtcFree( TrustedDomainName->Buffer );
  3854. RtlZeroMemory( TrustedDomainName, sizeof( UNICODE_STRING ));
  3855. }
  3856. if ( TrustedDomainSid ) {
  3857. FtcFree( *TrustedDomainSid );
  3858. *TrustedDomainSid = NULL;
  3859. }
  3860. goto Cleanup;
  3861. }
  3862. NTSTATUS
  3863. FTCache::MatchDnsName(
  3864. IN UNICODE_STRING * Name,
  3865. OUT BOOLEAN * IsLocal,
  3866. OUT OPTIONAL UNICODE_STRING * TrustedDomainName,
  3867. OUT OPTIONAL PSID * TrustedDomainSid
  3868. )
  3869. /*++
  3870. Routine Description:
  3871. Locates a match for the given DNS in the cache
  3872. Arguments:
  3873. Name DNS name to match
  3874. IsLocal Indicates whether the result is a local match
  3875. TrustedDomainName Used to return the name of the trusted domain
  3876. TrustedDomainSid Used to return the SID of the trusted domain
  3877. Returns:
  3878. STATUS_SUCCESS Match was found
  3879. STATUS_NO_MATCH Match was not found
  3880. STATUS_INSUFFICIENT_RESOURCES Out of memory
  3881. --*/
  3882. {
  3883. NTSTATUS Status;
  3884. DNS_NAME_KEY * DnsKey;
  3885. UNICODE_STRING * MatchName = NULL;
  3886. PSID MatchSid = NULL;
  3887. //
  3888. // Caller must validate parameters
  3889. //
  3890. ASSERT( Name );
  3891. ASSERT( LsapValidateLsaUnicodeString( Name ));
  3892. DnsKey = ( DNS_NAME_KEY * )RtlLookupElementGenericTableAvl(
  3893. &m_DnsNameTable,
  3894. Name
  3895. );
  3896. if ( DnsKey == NULL ) {
  3897. Status = STATUS_NO_MATCH;
  3898. goto Error;
  3899. }
  3900. for ( LIST_ENTRY * ListEntry = DnsKey->List.Flink;
  3901. ListEntry != &DnsKey->List;
  3902. ListEntry = ListEntry->Flink ) {
  3903. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  3904. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromDnsEntry( ListEntry );
  3905. if ( DomainInfoEntry->SubordinateTo == NULL ) {
  3906. //
  3907. // Skip over store-and-ignore entries
  3908. //
  3909. ASSERT( DomainInfoEntry->IsSidAdminDisabled());
  3910. continue;
  3911. }
  3912. //
  3913. // Conditions for an entry to be considered a match:
  3914. //
  3915. // - Entry must be enabled
  3916. // - corresponding top-level entry must be enabled
  3917. // - this entry must not be disowned by its TDO
  3918. //
  3919. if ( DomainInfoEntry->SidEnabled() &&
  3920. DomainInfoEntry->SubordinateTo->Enabled() &&
  3921. !DomainInfoEntry->TdoEntry->Excludes( &DomainInfoEntry->DnsKey->DnsName )) {
  3922. MatchName = &DomainInfoEntry->TdoEntry->TrustedDomainName;
  3923. MatchSid = DomainInfoEntry->TdoEntry->TrustedDomainSid;
  3924. *IsLocal = DomainInfoEntry->TdoEntry->LocalForestEntry;
  3925. break;
  3926. }
  3927. }
  3928. if ( MatchName == NULL || MatchSid == NULL ) {
  3929. Status = STATUS_NO_MATCH;
  3930. goto Error;
  3931. } else {
  3932. if ( TrustedDomainName &&
  3933. !FtcCopyUnicodeString( TrustedDomainName, MatchName )) {
  3934. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchDnsName (%s:%d)\n", __FILE__, __LINE__ ));
  3935. Status = STATUS_INSUFFICIENT_RESOURCES;
  3936. goto Error;
  3937. }
  3938. if ( TrustedDomainSid &&
  3939. !FtcCopySid( TrustedDomainSid, MatchSid )) {
  3940. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchDnsName (%s:%d)\n", __FILE__, __LINE__ ));
  3941. Status = STATUS_INSUFFICIENT_RESOURCES;
  3942. goto Error;
  3943. }
  3944. }
  3945. Status = STATUS_SUCCESS;
  3946. Cleanup:
  3947. return Status;
  3948. Error:
  3949. ASSERT( !NT_SUCCESS( Status ));
  3950. if ( TrustedDomainName ) {
  3951. FtcFree( TrustedDomainName->Buffer );
  3952. RtlZeroMemory( TrustedDomainName, sizeof( UNICODE_STRING ));
  3953. }
  3954. if ( TrustedDomainSid ) {
  3955. FtcFree( *TrustedDomainSid );
  3956. *TrustedDomainSid = NULL;
  3957. }
  3958. goto Cleanup;
  3959. }
  3960. NTSTATUS
  3961. FTCache::MatchNetbiosName(
  3962. IN UNICODE_STRING * Name,
  3963. OUT BOOLEAN * IsLocal,
  3964. OUT OPTIONAL UNICODE_STRING * TrustedDomainName,
  3965. OUT OPTIONAL PSID * TrustedDomainSid
  3966. )
  3967. /*++
  3968. Routine Description:
  3969. Locates a match for the given NetBios name in the cache
  3970. Arguments:
  3971. Name NetBios name to match
  3972. IsLocal Indicates whether the result is a local match
  3973. TrustedDomainName Used to return the name of the trusted domain
  3974. TrustedDomainSid Used to return the SID of the trusted domain
  3975. Returns:
  3976. STATUS_SUCCESS Match was found
  3977. STATUS_NO_MATCH Match was not found
  3978. STATUS_INSUFFICIENT_RESOURCES Out of memory
  3979. --*/
  3980. {
  3981. NTSTATUS Status;
  3982. NETBIOS_NAME_KEY * NetbiosKey;
  3983. UNICODE_STRING * MatchName = NULL;
  3984. PSID MatchSid = NULL;
  3985. //
  3986. // Caller must validate parameters
  3987. //
  3988. ASSERT( Name );
  3989. ASSERT( LsapValidateLsaUnicodeString( Name ));
  3990. NetbiosKey = ( NETBIOS_NAME_KEY * )RtlLookupElementGenericTableAvl(
  3991. &m_NetbiosNameTable,
  3992. Name
  3993. );
  3994. if ( NetbiosKey == NULL ) {
  3995. Status = STATUS_NO_MATCH;
  3996. goto Error;
  3997. }
  3998. for ( LIST_ENTRY * ListEntry = NetbiosKey->List.Flink;
  3999. ListEntry != &NetbiosKey->List;
  4000. ListEntry = ListEntry->Flink ) {
  4001. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  4002. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromNetbiosEntry( ListEntry );
  4003. if ( DomainInfoEntry->SubordinateTo == NULL ) {
  4004. //
  4005. // Skip over store-and-ignore entries
  4006. //
  4007. ASSERT( DomainInfoEntry->IsSidAdminDisabled());
  4008. continue;
  4009. }
  4010. //
  4011. // Conditions for a netbios entry to be considered a match:
  4012. //
  4013. // - Entry must be enabled
  4014. // - Netbios portion must be enabled
  4015. // - corresponding top-level entry must be enabled
  4016. // - this entry must not be disowned by its TDO
  4017. //
  4018. if ( DomainInfoEntry->NetbiosEnabled() &&
  4019. DomainInfoEntry->SubordinateTo->Enabled() &&
  4020. !DomainInfoEntry->TdoEntry->Excludes( &DomainInfoEntry->DnsKey->DnsName )) {
  4021. MatchName = &DomainInfoEntry->TdoEntry->TrustedDomainName;
  4022. MatchSid = DomainInfoEntry->TdoEntry->TrustedDomainSid;
  4023. *IsLocal = DomainInfoEntry->TdoEntry->LocalForestEntry;
  4024. break;
  4025. }
  4026. }
  4027. if ( MatchName == NULL || MatchSid == NULL ) {
  4028. Status = STATUS_NO_MATCH;
  4029. goto Error;
  4030. } else {
  4031. if ( TrustedDomainName &&
  4032. !FtcCopyUnicodeString( TrustedDomainName, MatchName )) {
  4033. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchNetbiosName (%s:%d)\n", __FILE__, __LINE__ ));
  4034. Status = STATUS_INSUFFICIENT_RESOURCES;
  4035. goto Error;
  4036. }
  4037. if ( TrustedDomainSid &&
  4038. !FtcCopySid( TrustedDomainSid, MatchSid )) {
  4039. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchSid (%s:%d)\n", __FILE__, __LINE__ ));
  4040. Status = STATUS_INSUFFICIENT_RESOURCES;
  4041. goto Error;
  4042. }
  4043. }
  4044. Status = STATUS_SUCCESS;
  4045. Cleanup:
  4046. return Status;
  4047. Error:
  4048. ASSERT( !NT_SUCCESS( Status ));
  4049. if ( TrustedDomainName ) {
  4050. FtcFree( TrustedDomainName->Buffer );
  4051. RtlZeroMemory( TrustedDomainName, sizeof( UNICODE_STRING ));
  4052. }
  4053. if ( TrustedDomainSid ) {
  4054. FtcFree( *TrustedDomainSid );
  4055. *TrustedDomainSid = NULL;
  4056. }
  4057. goto Cleanup;
  4058. }
  4059. NTSTATUS
  4060. FTCache::MatchUpn(
  4061. IN UNICODE_STRING * Name,
  4062. OUT BOOLEAN * IsLocal,
  4063. OUT OPTIONAL UNICODE_STRING * TrustedDomainName,
  4064. OUT OPTIONAL PSID * TrustedDomainSid
  4065. )
  4066. /*++
  4067. Routine Description:
  4068. Locates a match for the given UPN in the cache.
  4069. UPNs are parsed to select the suffix to the right of the rightmost "@" symbol.
  4070. Suffix is compared with the FTInfo records of type TLN.
  4071. A substring comparision is performed.
  4072. o The suffix must be equal to, or subordinate to, the value in the TLN record.
  4073. o The suffix must be compared against all external TLN records and the
  4074. longest substring match wins.
  4075. o If the suffix is equal to, or subordinate to, a TlnExclusion record, no
  4076. match is possible for that particular forest TDO.
  4077. Arguments:
  4078. Name UPN to match
  4079. IsLocal Indicates whether the result is a local match
  4080. TrustedDomainName Used to return the name of the trusted domain
  4081. TrustedDomainSid Used to return the SID of the trusted domain
  4082. Returns:
  4083. STATUS_SUCCESS Match was found
  4084. STATUS_NO_MATCH Match was not found
  4085. STATUS_INSUFFICIENT_RESOURCES Out of memory
  4086. STATUS_INVALID_PARAMETER The UPN is malformed
  4087. --*/
  4088. {
  4089. NTSTATUS Status;
  4090. TLN_KEY * TlnKey = NULL;
  4091. UNICODE_STRING Suffix = { 0 };
  4092. TLN_ENTRY * MatchingTln;
  4093. SHORT Index;
  4094. //
  4095. // Caller must validate parameters
  4096. //
  4097. ASSERT( Name );
  4098. ASSERT( LsapValidateLsaUnicodeString( Name ));
  4099. //
  4100. // Extract the suffix from the UPN
  4101. //
  4102. for ( Index = Name->Length / 2 - 1;
  4103. Index >= 0;
  4104. Index -= 1 ) {
  4105. if ( Name->Buffer[Index] == L'@' ) {
  4106. Index += 1;
  4107. Suffix.Length = Name->Length - Index * sizeof( WCHAR );
  4108. Suffix.MaximumLength = Suffix.Length;
  4109. Suffix.Buffer = &Name->Buffer[Index];
  4110. break;
  4111. }
  4112. }
  4113. //
  4114. // Reject '@' at beginning or end of UPN, or UPNs with missing '@'
  4115. //
  4116. if ( Index == 0 || Index == 1 || Index == Name->Length / 2 ) {
  4117. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::MatchUpn (%s:%d)\n", __FILE__, __LINE__ ));
  4118. return STATUS_INVALID_PARAMETER;
  4119. }
  4120. Status = MatchNamespace( &Suffix, IsLocal, TrustedDomainName, TrustedDomainSid );
  4121. if ( !NT_SUCCESS( Status )) {
  4122. goto Error;
  4123. }
  4124. Cleanup:
  4125. return Status;
  4126. Error:
  4127. ASSERT( !NT_SUCCESS( Status ));
  4128. goto Cleanup;
  4129. }
  4130. NTSTATUS
  4131. FTCache::MatchSpn(
  4132. IN UNICODE_STRING * Name,
  4133. OUT BOOLEAN * IsLocal,
  4134. OUT OPTIONAL UNICODE_STRING * TrustedDomainName,
  4135. OUT OPTIONAL PSID * TrustedDomainSid
  4136. )
  4137. /*++
  4138. Routine Description:
  4139. Locates a match for the given SPN in the cache
  4140. SPNs are the most complicated name form to parse and match. The matching
  4141. function parses the name starting from the right and proceeds in the
  4142. following order until it gets the first match, or exhausts all possibilities.
  4143. >Domain component is found: Either the Kerberos client or the KDC will
  4144. probably be able to route the request. If not, the matching function is
  4145. called.
  4146. The suffix to the right of the "@" is compared against FTInfo records of
  4147. type TLN, using a substring comparison.
  4148. o The suffix must be equal to, or subordinate to, the value in the TLN record.
  4149. o The suffix must be compared against all external TLN records and the
  4150. longest substring match wins.
  4151. o If the suffix is equal to, or subordinate to, a TlnExclusion record, no
  4152. match is possible for that particular forest TDO.
  4153. The next component to the left, ServiceName or InstanceName, is subjected
  4154. to the same substring comparison.
  4155. Both tests must generate a match, and both results must point to the same
  4156. forest TDO. Otherwise, no match is returned to the caller.
  4157. >ServiceName component is found first: Uses same substring comparison
  4158. described above.
  4159. The entire ServiceName value is compared against FTInfo records of type TLN.
  4160. >InstanceName component is found first: Uses same substring comparison
  4161. described above.
  4162. The entire InstanceName value is compared against FTInfo records of type TLN.
  4163. Arguments:
  4164. Name SPN to match
  4165. IsLocal Indicates whether the result is a local match
  4166. TrustedDomainName Used to return the name of the trusted domain
  4167. TrustedDomainSid Used to return the SID of the trusted domain
  4168. Returns:
  4169. STATUS_SUCCESS Match was found
  4170. STATUS_NO_MATCH Match was not found
  4171. STATUS_INSUFFICIENT_RESOURCES Out of memory
  4172. --*/
  4173. {
  4174. NTSTATUS Status;
  4175. UNICODE_STRING * MatchName = NULL;
  4176. PSID MatchSid = NULL;
  4177. WCHAR InstanceBuffer[ DNS_MAX_NAME_LENGTH + 1 ];
  4178. WCHAR DomainBuffer[ DNS_MAX_NAME_LENGTH + 1 ];
  4179. WCHAR RealmBuffer[ DNS_MAX_NAME_LENGTH + 1 ];
  4180. DWORD InstanceLength = DNS_MAX_NAME_LENGTH + 1;
  4181. DWORD DomainLength = DNS_MAX_NAME_LENGTH + 1;
  4182. DWORD RealmLength = DNS_MAX_NAME_LENGTH + 1;
  4183. UNICODE_STRING Instance = {0};
  4184. UNICODE_STRING Domain = {0};
  4185. UNICODE_STRING Realm = {0};
  4186. //
  4187. // Caller must validate parameters
  4188. //
  4189. ASSERT( Name );
  4190. ASSERT( LsapValidateLsaUnicodeString( Name ));
  4191. //
  4192. // Dissect the SPN into its constituent components
  4193. //
  4194. Status = DsCrackSpn3W(
  4195. Name->Buffer,
  4196. Name->Length / sizeof( WCHAR ),
  4197. NULL, // service class (don't care)
  4198. NULL, // service class (don't care)
  4199. &InstanceLength,
  4200. InstanceBuffer,
  4201. NULL, // instance port (don't care)
  4202. &DomainLength,
  4203. DomainBuffer,
  4204. &RealmLength,
  4205. RealmBuffer
  4206. );
  4207. if ( Status == ERROR_INVALID_PARAMETER ) {
  4208. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::MatchSpn (%s:%d)\n", __FILE__, __LINE__ ));
  4209. Status = STATUS_INVALID_PARAMETER;
  4210. } else if ( Status == ERROR_BUFFER_OVERFLOW ) {
  4211. Status = STATUS_BUFFER_OVERFLOW;
  4212. } else if ( Status != ERROR_SUCCESS ) {
  4213. //
  4214. // This assert will fire if DsCrackSpn3W returns
  4215. // an unrecognized ERROR_ code (need to map to STATUS_ code)
  4216. //
  4217. ASSERT( FALSE );
  4218. }
  4219. if ( Status != STATUS_SUCCESS ) {
  4220. goto Error;
  4221. }
  4222. //
  4223. // Instance name and service name lengths include terminators
  4224. //
  4225. ASSERT( InstanceLength > 0 );
  4226. ASSERT( DomainLength > 0 );
  4227. ASSERT( RealmLength > 0 );
  4228. InstanceLength--;
  4229. DomainLength--;
  4230. RealmLength--;
  4231. Instance.Length = ( USHORT )InstanceLength * sizeof( WCHAR );
  4232. Instance.MaximumLength = Instance.Length + sizeof( WCHAR );
  4233. Instance.Buffer = InstanceBuffer;
  4234. Domain.Length = ( USHORT )DomainLength * sizeof( WCHAR );
  4235. Domain.MaximumLength = Domain.Length + sizeof( WCHAR );
  4236. Domain.Buffer = DomainBuffer;
  4237. Realm.Length = ( USHORT )RealmLength * sizeof( WCHAR );
  4238. Realm.MaximumLength = Realm.Length + sizeof( WCHAR );
  4239. Realm.Buffer = RealmBuffer;
  4240. //
  4241. // Case 1: Domain name (realm) is present
  4242. //
  4243. if ( Realm.Length > 0 ) {
  4244. TLN_ENTRY * MatchRealm; // match for realm name component
  4245. TLN_ENTRY * MatchOther; // match for the other (domain or instance) component
  4246. MatchRealm = LongestSubstringMatchTln( IsLocal, &Realm );
  4247. if ( MatchRealm == NULL ) {
  4248. Status = STATUS_NO_MATCH;
  4249. goto Error;
  4250. } else if ( Domain.Length > 0 ) {
  4251. MatchOther = LongestSubstringMatchTln( IsLocal, &Domain );
  4252. } else if ( Instance.Length > 0 ) {
  4253. MatchOther = LongestSubstringMatchTln( IsLocal, &Instance );
  4254. } else {
  4255. MatchOther = NULL;
  4256. }
  4257. if ( MatchOther == NULL ) {
  4258. Status = STATUS_NO_MATCH;
  4259. goto Error;
  4260. } else if ( MatchRealm->TdoEntry != MatchOther->TdoEntry ) {
  4261. Status = STATUS_NO_MATCH;
  4262. goto Error;
  4263. } else {
  4264. MatchName = &MatchRealm->TdoEntry->TrustedDomainName;
  4265. MatchSid = MatchRealm->TdoEntry->TrustedDomainSid;
  4266. }
  4267. if ( TrustedDomainName &&
  4268. !FtcCopyUnicodeString( TrustedDomainName, MatchName )) {
  4269. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchNamespace (%s:%d)\n", __FILE__, __LINE__ ));
  4270. Status = STATUS_INSUFFICIENT_RESOURCES;
  4271. goto Error;
  4272. }
  4273. if ( TrustedDomainSid &&
  4274. !FtcCopySid( TrustedDomainSid, MatchSid )) {
  4275. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchNamespace (%s:%d)\n", __FILE__, __LINE__ ));
  4276. Status = STATUS_INSUFFICIENT_RESOURCES;
  4277. goto Error;
  4278. }
  4279. } else if ( Domain.Length > 0 ) {
  4280. Status = MatchNamespace( &Domain, IsLocal, TrustedDomainName, TrustedDomainSid );
  4281. } else if ( Instance.Length > 0 ) {
  4282. Status = MatchNamespace( &Instance, IsLocal, TrustedDomainName, TrustedDomainSid );
  4283. } else {
  4284. Status = STATUS_NO_MATCH;
  4285. }
  4286. if ( !NT_SUCCESS( Status )) {
  4287. goto Error;
  4288. }
  4289. Cleanup:
  4290. return Status;
  4291. Error:
  4292. if ( TrustedDomainName ) {
  4293. FtcFree( TrustedDomainName->Buffer );
  4294. RtlZeroMemory( TrustedDomainName, sizeof( UNICODE_STRING ));
  4295. }
  4296. if ( TrustedDomainSid ) {
  4297. FtcFree( *TrustedDomainSid );
  4298. *TrustedDomainSid = NULL;
  4299. }
  4300. ASSERT( !NT_SUCCESS( Status ));
  4301. goto Cleanup;
  4302. }
  4303. NTSTATUS
  4304. FTCache::MatchNamespace(
  4305. IN UNICODE_STRING * Name,
  4306. OUT BOOLEAN * IsLocal,
  4307. OUT OPTIONAL UNICODE_STRING * TrustedDomainName,
  4308. OUT OPTIONAL PSID * TrustedDomainSid
  4309. )
  4310. /*++
  4311. Routine Description:
  4312. Locates a match for the given namespace in the cache.
  4313. Namespace is compared with the FTInfo records of type TLN.
  4314. A substring comparision is performed.
  4315. o The namespace must be equal to, or subordinate to, the value in the
  4316. TLN record.
  4317. o The namespace must be compared against all TLN records and the
  4318. longest substring match wins.
  4319. o If the namespace is equal to, or subordinate to, a TlnExclusion record, no
  4320. match is possible for that particular forest TDO.
  4321. Arguments:
  4322. Name Namespace to match
  4323. IsLocal Indicates whether the result is a local match
  4324. TrustedDomainName Used to return the name of the trusted domain name
  4325. TrustedDomainSid Used to return the SID of the trusted domain
  4326. Returns:
  4327. STATUS_SUCCESS Match was found
  4328. STATUS_NO_MATCH Match was not found
  4329. STATUS_INSUFFICIENT_RESOURCES Out of memory
  4330. --*/
  4331. {
  4332. NTSTATUS Status;
  4333. TLN_KEY * TlnKey = NULL;
  4334. TLN_ENTRY * MatchingTln;
  4335. //
  4336. // Caller must validate parameters
  4337. //
  4338. ASSERT( Name );
  4339. ASSERT( LsapValidateLsaUnicodeString( Name ));
  4340. MatchingTln = LongestSubstringMatchTln( IsLocal, Name );
  4341. if ( MatchingTln == NULL ) {
  4342. Status = STATUS_NO_MATCH;
  4343. goto Error;
  4344. }
  4345. if ( TrustedDomainName &&
  4346. !FtcCopyUnicodeString( TrustedDomainName, &MatchingTln->TdoEntry->TrustedDomainName )) {
  4347. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchNamespace (%s:%d)\n", __FILE__, __LINE__ ));
  4348. Status = STATUS_INSUFFICIENT_RESOURCES;
  4349. goto Error;
  4350. }
  4351. if ( TrustedDomainSid &&
  4352. !FtcCopySid( TrustedDomainSid, MatchingTln->TdoEntry->TrustedDomainSid )) {
  4353. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchNamespace (%s:%d)\n", __FILE__, __LINE__ ));
  4354. Status = STATUS_INSUFFICIENT_RESOURCES;
  4355. goto Error;
  4356. }
  4357. Status = STATUS_SUCCESS;
  4358. Cleanup:
  4359. return Status;
  4360. Error:
  4361. ASSERT( !NT_SUCCESS( Status ));
  4362. if ( TrustedDomainName ) {
  4363. FtcFree( TrustedDomainName->Buffer );
  4364. RtlZeroMemory( TrustedDomainName, sizeof( UNICODE_STRING ));
  4365. }
  4366. if ( TrustedDomainSid ) {
  4367. FtcFree( *TrustedDomainSid );
  4368. *TrustedDomainSid = NULL;
  4369. }
  4370. goto Cleanup;
  4371. }
  4372. FTCache::TLN_ENTRY *
  4373. FTCache::LongestSubstringMatchTln(
  4374. OUT BOOLEAN * IsLocal,
  4375. IN UNICODE_STRING * String
  4376. )
  4377. /*++
  4378. Routine Description:
  4379. Finds a longest substring match to a given string
  4380. among all the enabled TLN records.
  4381. Arguments:
  4382. IsLocal Indicates whether the result is a local match
  4383. String string to match. must not be NULL.
  4384. Returns:
  4385. NULL if no match,
  4386. a pointer to a TLN entry otherwise
  4387. --*/
  4388. {
  4389. TLN_ENTRY * Match = NULL;
  4390. ASSERT( String );
  4391. for ( UNICODE_STRING Temp = *String;
  4392. Temp.Length > 0;
  4393. NextDnsComponent( &Temp )) {
  4394. TLN_KEY * TlnKey = ( TLN_KEY * )RtlLookupElementGenericTableAvl(
  4395. &m_TopLevelNameTable,
  4396. &Temp
  4397. );
  4398. if ( TlnKey == NULL ) {
  4399. continue;
  4400. }
  4401. for ( LIST_ENTRY * ListEntry = TlnKey->List.Flink;
  4402. ListEntry != &TlnKey->List;
  4403. ListEntry = ListEntry->Flink ) {
  4404. TLN_ENTRY * TlnEntry;
  4405. TlnEntry = TLN_ENTRY::EntryFromAvlEntry( ListEntry );
  4406. if ( TlnEntry->Excluded ) {
  4407. //
  4408. // Skip over excluded entries
  4409. //
  4410. continue;
  4411. }
  4412. //
  4413. // Conditions for a top level entry to be considered a match:
  4414. //
  4415. // - Entry must be enabled
  4416. // - Entry must not be a pseudo entry
  4417. // - the string must not be disowned by the entry's TDO
  4418. //
  4419. if ( TlnEntry->Enabled() &&
  4420. TlnEntry->SubordinateEntry == NULL &&
  4421. !TlnEntry->TdoEntry->Excludes( String )) {
  4422. Match = TlnEntry;
  4423. *IsLocal = TlnEntry->TdoEntry->LocalForestEntry;
  4424. break;
  4425. }
  4426. }
  4427. if ( Match != NULL ) {
  4428. break;
  4429. }
  4430. }
  4431. return Match;
  4432. }
  4433. NTSTATUS
  4434. FTCache::AddConflictPair(
  4435. IN OUT FTCache::CONFLICT_PAIR * * ConflictPairs,
  4436. IN OUT ULONG * ConflictPairsTotal,
  4437. IN LSA_FOREST_TRUST_RECORD_TYPE Type1,
  4438. IN void * Conflict1,
  4439. IN ULONG Flag1,
  4440. IN LSA_FOREST_TRUST_RECORD_TYPE Type2,
  4441. IN void * Conflict2,
  4442. IN ULONG Flag2
  4443. )
  4444. /*++
  4445. Routine Description:
  4446. Adds a given pair of records to an array of such pairs
  4447. Arguments:
  4448. ConflictPairs an array of conflict pairs to add to
  4449. ConflictPairsCount number of entries in ConflictPairs
  4450. Type1 type of the first side of conflict
  4451. Conflict1 first side of conflict
  4452. Flag1 flags of the first side of conflict
  4453. Type2 type of the second side of conflict
  4454. Conflict2 second side of conflict
  4455. Flag2 flags of the second side of conflict
  4456. Returns:
  4457. STATUS_SUCCESS if happy
  4458. STATUS_INSUFFICIENT_RESOURCES if out of memory
  4459. --*/
  4460. {
  4461. NTSTATUS Status;
  4462. ASSERT( ConflictPairs );
  4463. ASSERT( ConflictPairsTotal );
  4464. ASSERT( Conflict1 );
  4465. ASSERT( Conflict2 );
  4466. if ( *ConflictPairs == NULL ) {
  4467. *ConflictPairs = ( CONFLICT_PAIR * )FtcAllocate( sizeof( CONFLICT_PAIR ));
  4468. if ( ConflictPairs == NULL ) {
  4469. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::AddConflictPair (%s:%d)\n", __FILE__, __LINE__ ));
  4470. Status = STATUS_INSUFFICIENT_RESOURCES;
  4471. goto Error;
  4472. }
  4473. } else {
  4474. CONFLICT_PAIR * ConflictPairsT;
  4475. ConflictPairsT = ( CONFLICT_PAIR * )FtcReallocate(
  4476. *ConflictPairs,
  4477. sizeof( CONFLICT_PAIR ) * ( *ConflictPairsTotal ),
  4478. sizeof( CONFLICT_PAIR ) * ( *ConflictPairsTotal + 1 ));
  4479. if ( ConflictPairsT == NULL ) {
  4480. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::AddConflictPair (%s:%d)\n", __FILE__, __LINE__ ));
  4481. Status = STATUS_INSUFFICIENT_RESOURCES;
  4482. goto Error;
  4483. }
  4484. *ConflictPairs = ConflictPairsT;
  4485. }
  4486. ASSERT( *ConflictPairs );
  4487. (*ConflictPairs)[*ConflictPairsTotal].EntryType1 = Type1;
  4488. (*ConflictPairs)[*ConflictPairsTotal].Entry1 = Conflict1;
  4489. (*ConflictPairs)[*ConflictPairsTotal].Flag1 = Flag1;
  4490. (*ConflictPairs)[*ConflictPairsTotal].EntryType2 = Type2;
  4491. (*ConflictPairs)[*ConflictPairsTotal].Entry2 = Conflict2;
  4492. (*ConflictPairs)[*ConflictPairsTotal].Flag2 = Flag2;
  4493. *ConflictPairsTotal += 1;
  4494. Status = STATUS_SUCCESS;
  4495. Cleanup:
  4496. return Status;
  4497. Error:
  4498. ASSERT( !NT_SUCCESS( Status ));
  4499. goto Cleanup;
  4500. }
  4501. void
  4502. FTCache::ReconcileConflictPairs(
  4503. IN OPTIONAL const TDO_ENTRY * TdoEntry,
  4504. IN CONFLICT_PAIR * ConflictPairs,
  4505. IN ULONG ConflictPairsTotal
  4506. )
  4507. /*++
  4508. Routine Description:
  4509. Iterates through an array of conflict pairs and marks
  4510. entries corresponding to a given TDO entry as disabled
  4511. Arguments:
  4512. TdoEntry entry to be reconciled:
  4513. every conflict pair matching this entry
  4514. will be marked as disabled due to conflict
  4515. if NULL, the side of the conflict belonging
  4516. to a TDO with an alphabetically smaller name wins
  4517. unless it is the local forest entry, which always wins
  4518. ConflictPairs array of conflict pair records
  4519. ConflictPairsTotal
  4520. Returns:
  4521. Nothing
  4522. --*/
  4523. {
  4524. ASSERT( ConflictPairs );
  4525. for ( ULONG i = 0 ; i < ConflictPairsTotal ; i++ ) {
  4526. CONFLICT_PAIR& Pair = ConflictPairs[i];
  4527. if ( TdoEntry == NULL ) {
  4528. //
  4529. // Extract TDO entries corresponding to each
  4530. // side of the conflict so we can compare the
  4531. // TDO names and decide who wins
  4532. //
  4533. RTL_GENERIC_COMPARE_RESULTS Result;
  4534. TDO_ENTRY * TdoEntry1 = Pair.TdoEntry1();
  4535. TDO_ENTRY * TdoEntry2 = Pair.TdoEntry2();
  4536. if ( TdoEntry1->LocalForestEntry ) {
  4537. //
  4538. // A local forest entry can not lose
  4539. //
  4540. Pair.DisableEntry2();
  4541. } else if ( TdoEntry2->LocalForestEntry ) {
  4542. Pair.DisableEntry1();
  4543. } else {
  4544. //
  4545. // Compare TDO names of the conflicting entries
  4546. // Alphabetically smaller name wins
  4547. // This algorithm is deterministic
  4548. //
  4549. Result = UnicodeStringCompareRoutine(
  4550. NULL,
  4551. &TdoEntry1->TrustedDomainName,
  4552. &TdoEntry2->TrustedDomainName
  4553. );
  4554. if ( Result == GenericGreaterThan ) {
  4555. Pair.DisableEntry1();
  4556. } else if ( Result == GenericLessThan ) {
  4557. Pair.DisableEntry2();
  4558. } else {
  4559. ASSERT( FALSE ); // two TDO names can not be equal!!!
  4560. }
  4561. }
  4562. } else {
  4563. if ( TdoEntry == Pair.TdoEntry1()) {
  4564. Pair.DisableEntry1();
  4565. }
  4566. if ( TdoEntry == Pair.TdoEntry2()) {
  4567. Pair.DisableEntry2();
  4568. }
  4569. }
  4570. }
  4571. }
  4572. NTSTATUS
  4573. FTCache::GenerateConflictInfo(
  4574. IN CONFLICT_PAIR * ConflictPairs,
  4575. IN ULONG ConflictPairsTotal,
  4576. IN TDO_ENTRY * TdoEntry,
  4577. OUT PLSA_FOREST_TRUST_COLLISION_INFORMATION * CollisionInfo
  4578. )
  4579. /*++
  4580. Routine Description:
  4581. Generates conflict information in the format expected by the
  4582. caller from the conflict pairs array
  4583. Arguments:
  4584. ConflictPairs array of entries representing conflict information
  4585. ConflictPairsTotal count of entries in the "ConflitPairs" array
  4586. TdoEntry TDO entry in conflict
  4587. CollisionInfo used to return generated collision data
  4588. Returns:
  4589. STATUS_SUCCESS happy
  4590. STATUS_INSUFFICIENT_RESOURCES ran out of memory generated collision data
  4591. STATUS_INVALID_PARAMETER will also assert if invalid data encountered
  4592. --*/
  4593. {
  4594. NTSTATUS Status;
  4595. ASSERT( ConflictPairs );
  4596. ASSERT( TdoEntry );
  4597. ASSERT( CollisionInfo && *CollisionInfo == NULL );
  4598. for ( ULONG i = 0 ; i < ConflictPairsTotal ; i++ ) {
  4599. CONFLICT_PAIR& Pair = ConflictPairs[i];
  4600. ULONG Index;
  4601. ULONG Flags;
  4602. UNICODE_STRING * String;
  4603. switch ( Pair.EntryType1 ) {
  4604. case ForestTrustTopLevelName:
  4605. case ForestTrustTopLevelNameEx: {
  4606. ASSERT( Pair.TlnEntry1 );
  4607. ASSERT( Pair.TlnEntry1->TdoEntry == TdoEntry );
  4608. Index = Pair.TlnEntry1->Index;
  4609. Flags = Pair.TlnEntry1->Flags() | Pair.Flag1;
  4610. break;
  4611. }
  4612. case ForestTrustDomainInfo: {
  4613. ASSERT( Pair.DomainInfoEntry1 );
  4614. ASSERT( Pair.DomainInfoEntry1->TdoEntry == TdoEntry );
  4615. Index = Pair.DomainInfoEntry1->Index;
  4616. Flags = Pair.DomainInfoEntry1->Flags() | Pair.Flag1;
  4617. break;
  4618. }
  4619. default:
  4620. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::GenerateConflictInfo (%s:%d)\n", __FILE__, __LINE__ ));
  4621. Status = STATUS_INVALID_PARAMETER;
  4622. ASSERT( FALSE );
  4623. goto Error;
  4624. }
  4625. switch ( Pair.EntryType2 ) {
  4626. case ForestTrustTopLevelName:
  4627. case ForestTrustTopLevelNameEx: {
  4628. ASSERT( Pair.TlnEntry2 );
  4629. ASSERT( Pair.TlnEntry2->TdoEntry != TdoEntry );
  4630. String = &Pair.TlnEntry2->TdoEntry->TrustedDomainName;
  4631. break;
  4632. }
  4633. case ForestTrustDomainInfo: {
  4634. ASSERT( Pair.DomainInfoEntry2 );
  4635. ASSERT( Pair.DomainInfoEntry2->TdoEntry != TdoEntry );
  4636. String = &Pair.DomainInfoEntry2->TdoEntry->TrustedDomainName;
  4637. break;
  4638. }
  4639. default:
  4640. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::GenerateConflictInfo (%s:%d)\n", __FILE__, __LINE__ ));
  4641. Status = STATUS_INVALID_PARAMETER;
  4642. ASSERT( FALSE );
  4643. goto Error;
  4644. }
  4645. Status = LsapAddToCollisionInfo(
  4646. CollisionInfo,
  4647. Index,
  4648. CollisionTdo,
  4649. Flags,
  4650. String
  4651. );
  4652. if ( !NT_SUCCESS( Status )) {
  4653. goto Error;
  4654. }
  4655. }
  4656. Status = STATUS_SUCCESS;
  4657. Cleanup:
  4658. return Status;
  4659. Error:
  4660. ASSERT( !NT_SUCCESS( Status ));
  4661. //
  4662. // Cleanup generated conflict info
  4663. //
  4664. LsapFreeCollisionInfo( CollisionInfo );
  4665. ASSERT( *CollisionInfo == NULL );
  4666. goto Cleanup;
  4667. }
  4668. BOOLEAN
  4669. FTCache::TDO_ENTRY::Excludes(
  4670. IN const UNICODE_STRING * Name
  4671. )
  4672. /*++
  4673. Routine Description:
  4674. Determines if the given unicode name is disowned by this TDO_ENTRY
  4675. Arguments:
  4676. Name name to check
  4677. Returns:
  4678. TRUE if name is identical to one of the namespaces disowned by this tdo
  4679. or if it is subordinate to one of the disowned namespaces
  4680. FALSE otherwise
  4681. --*/
  4682. {
  4683. BOOLEAN Result = FALSE;
  4684. for ( LIST_ENTRY * ListEntry = TlnList.Flink;
  4685. ListEntry != &TlnList;
  4686. ListEntry = ListEntry->Flink ) {
  4687. TLN_ENTRY * TlnEntry;
  4688. TlnEntry = TLN_ENTRY::EntryFromTdoEntry( ListEntry );
  4689. if ( !TlnEntry->Excluded ) {
  4690. continue;
  4691. }
  4692. //
  4693. // Only those exclusion entries that have a superior TLN are considered,
  4694. // the rest are "stored and ignored"
  4695. //
  4696. if ( TlnEntry->SuperiorEntry == NULL ) {
  4697. continue;
  4698. }
  4699. if ( RtlEqualUnicodeString(
  4700. &TlnEntry->TlnKey->TopLevelName,
  4701. Name,
  4702. TRUE )) {
  4703. Result = TRUE;
  4704. break;
  4705. } else if ( IsSubordinate( Name, &TlnEntry->TlnKey->TopLevelName )) {
  4706. Result = TRUE;
  4707. break;
  4708. }
  4709. }
  4710. return Result;
  4711. }
  4712. void
  4713. FTCache::AuditChanges(
  4714. IN OPTIONAL const TDO_ENTRY * TdoEntryOld,
  4715. IN OPTIONAL const TDO_ENTRY * TdoEntryNew
  4716. )
  4717. /*++
  4718. Routine Description:
  4719. Computes differences between two TDO_ENTRY structures
  4720. and calls the corresponding auditing routines
  4721. Arguments:
  4722. TdoEntryOld old data (can be NULL in case of addition)
  4723. TdoEntryNew new data (can be NULL in case of deletion)
  4724. Returns:
  4725. Nothing (auditing failures are ignored)
  4726. --*/
  4727. {
  4728. //
  4729. // Log a new or modified TLN
  4730. //
  4731. #define LogNewTLN( TopLevelName, ForestName ) \
  4732. { \
  4733. Status = SpmpReportEventU( \
  4734. EVENTLOG_WARNING_TYPE, \
  4735. LSA_FOREST_CLAIMED_NEW_TLN, \
  4736. 0, \
  4737. 0, \
  4738. NULL, \
  4739. 2, \
  4740. TopLevelName, \
  4741. ForestName \
  4742. ); \
  4743. \
  4744. if ( !NT_SUCCESS( Status )) { \
  4745. \
  4746. goto Cleanup; \
  4747. } \
  4748. }
  4749. //
  4750. // Criteria for logging the new or modified
  4751. // TLN
  4752. //
  4753. #define MustLogNewTLN( TlnEntry ) \
  4754. (( !TlnEntry->Excluded ) && \
  4755. ( TlnEntry->Flags() & LSA_TLN_DISABLED_NEW ))
  4756. NTSTATUS Status;
  4757. LUID OperationId;
  4758. BOOLEAN AuditingEnabled;
  4759. if ( TdoEntryOld == NULL &&
  4760. TdoEntryNew == NULL ) {
  4761. //
  4762. // Give us at least something!
  4763. //
  4764. return;
  4765. }
  4766. //
  4767. // No auditing is performed on local forest entries
  4768. //
  4769. if ( TdoEntryOld && TdoEntryOld->LocalForestEntry ) {
  4770. return;
  4771. }
  4772. if ( TdoEntryNew && TdoEntryNew->LocalForestEntry ) {
  4773. return;
  4774. }
  4775. AuditingEnabled = LsapAdtAuditingEnabledHint(
  4776. AuditCategoryPolicyChange,
  4777. EVENTLOG_AUDIT_SUCCESS
  4778. );
  4779. if ( !AuditingEnabled ) {
  4780. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing of x-forest trust changes skipped\n" ));
  4781. }
  4782. Status = NtAllocateLocallyUniqueId( &OperationId );
  4783. if ( !NT_SUCCESS( Status )) {
  4784. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Can not allocate a LUID for auditing (0x%lx)\n", Status ));
  4785. return;
  4786. }
  4787. if ( TdoEntryOld == NULL || TdoEntryNew == NULL ) {
  4788. LIST_ENTRY * ListEntry;
  4789. //
  4790. // This is an add or remove operation
  4791. // Figure out which one it is and apply to every entry
  4792. //
  4793. typedef NTSTATUS
  4794. (*PFNAUDITFN)(
  4795. IN PUNICODE_STRING ForestName,
  4796. IN PSID ForestSid,
  4797. IN PLUID OperationId,
  4798. IN LSA_FOREST_TRUST_RECORD_TYPE EntryType,
  4799. IN ULONG Flags,
  4800. IN PUNICODE_STRING TopLevelName,
  4801. IN PUNICODE_STRING DnsName,
  4802. IN PUNICODE_STRING NetbiosName,
  4803. IN PSID Sid
  4804. );
  4805. const BOOLEAN Adding = ( TdoEntryNew ? TRUE : FALSE );
  4806. const TDO_ENTRY * Entry = ( Adding ? TdoEntryNew : TdoEntryOld );
  4807. PFNAUDITFN AuditChangeFn = ( Adding ?
  4808. LsapAdtTrustedForestInfoEntryAdd :
  4809. LsapAdtTrustedForestInfoEntryRem );
  4810. //
  4811. // New data is being added to the cache
  4812. //
  4813. for ( ListEntry = Entry->TlnList.Flink;
  4814. ListEntry != &Entry->TlnList;
  4815. ListEntry = ListEntry->Flink ) {
  4816. TLN_ENTRY * TlnEntry;
  4817. TlnEntry = TLN_ENTRY::EntryFromTdoEntry( ListEntry );
  4818. //
  4819. // Skip over "pseudo" entries
  4820. //
  4821. if ( !( TlnEntry->Excluded ||
  4822. TlnEntry->SubordinateEntry == NULL )) {
  4823. continue;
  4824. }
  4825. //
  4826. // Bug 494666: log disabled TLN entries (since they are new)
  4827. // regardless of auditing being enabled or not
  4828. //
  4829. if ( Adding &&
  4830. MustLogNewTLN( TlnEntry )) {
  4831. LogNewTLN(
  4832. &( TlnEntry->TlnKey->TopLevelName ),
  4833. &( Entry->TrustedDomainName )
  4834. );
  4835. }
  4836. //
  4837. // Auditing is not enabled, continue
  4838. //
  4839. if( !AuditingEnabled ) {
  4840. continue;
  4841. }
  4842. Status = AuditChangeFn(
  4843. ( PUNICODE_STRING )&Entry->TrustedDomainName,
  4844. Entry->TrustedDomainSid,
  4845. &OperationId,
  4846. TlnEntry->Excluded ?
  4847. ForestTrustTopLevelNameEx :
  4848. ForestTrustTopLevelName,
  4849. TlnEntry->Flags(),
  4850. &TlnEntry->TlnKey->TopLevelName,
  4851. NULL,
  4852. NULL,
  4853. NULL
  4854. );
  4855. if ( !NT_SUCCESS( Status )) {
  4856. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%lx on entry %p\n (%s:%d)", Status, TlnEntry, __FILE__, __LINE__ ));
  4857. goto Cleanup;
  4858. }
  4859. }
  4860. //
  4861. // if Auditing is not enabled
  4862. // there is nothing left to do
  4863. // so goto cleanup
  4864. //
  4865. if ( !AuditingEnabled ) {
  4866. goto Cleanup;
  4867. }
  4868. for ( ListEntry = Entry->DomainInfoList.Flink;
  4869. ListEntry != &Entry->DomainInfoList;
  4870. ListEntry = ListEntry->Flink ) {
  4871. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  4872. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromTdoEntry( ListEntry );
  4873. Status = AuditChangeFn(
  4874. ( PUNICODE_STRING )&Entry->TrustedDomainName,
  4875. Entry->TrustedDomainSid,
  4876. &OperationId,
  4877. ForestTrustDomainInfo,
  4878. DomainInfoEntry->Flags(),
  4879. NULL,
  4880. &DomainInfoEntry->DnsKey->DnsName,
  4881. DomainInfoEntry->NetbiosKey ?
  4882. &DomainInfoEntry->NetbiosKey->NetbiosName :
  4883. NULL,
  4884. DomainInfoEntry->SidKey->DomainSid
  4885. );
  4886. if ( !NT_SUCCESS( Status )) {
  4887. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%lx on entry %p (%s:%d)\n", Status, DomainInfoEntry, __FILE__, __LINE__ ));
  4888. goto Cleanup;
  4889. }
  4890. }
  4891. for ( ListEntry = Entry->BinaryList.Flink;
  4892. ListEntry != &Entry->BinaryList;
  4893. ListEntry = ListEntry->Flink ) {
  4894. BINARY_ENTRY * BinaryEntry;
  4895. BinaryEntry = BINARY_ENTRY::EntryFromTdoEntry( ListEntry );
  4896. Status = AuditChangeFn(
  4897. ( PUNICODE_STRING )&Entry->TrustedDomainName,
  4898. Entry->TrustedDomainSid,
  4899. &OperationId,
  4900. BinaryEntry->Type,
  4901. BinaryEntry->Flags(),
  4902. NULL,
  4903. NULL,
  4904. NULL,
  4905. NULL
  4906. );
  4907. if ( !NT_SUCCESS( Status )) {
  4908. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%lx on entry %p (%s:%d)\n", Status, BinaryEntry, __FILE__, __LINE__ ));
  4909. goto Cleanup;
  4910. }
  4911. }
  4912. } else {
  4913. //
  4914. // Data is being modified
  4915. //
  4916. LIST_ENTRY * ListEntry;
  4917. const TDO_ENTRY * TdoEntry = TdoEntryNew; // have to pick one for auditing
  4918. ASSERT( RtlEqualUnicodeString(
  4919. &TdoEntryOld->TrustedDomainName,
  4920. &TdoEntryNew->TrustedDomainName,
  4921. TRUE ));
  4922. //
  4923. // Go through new TLN entries, see if they are present in the old list
  4924. // If not, they're additions
  4925. // If yes, check for modifications
  4926. //
  4927. for ( ListEntry = TdoEntryNew->TlnList.Flink;
  4928. ListEntry != &TdoEntryNew->TlnList;
  4929. ListEntry = ListEntry->Flink ) {
  4930. TLN_ENTRY * TlnEntryNew;
  4931. BOOLEAN Found = FALSE;
  4932. BOOLEAN Modified = FALSE;
  4933. TlnEntryNew = TLN_ENTRY::EntryFromTdoEntry( ListEntry );
  4934. //
  4935. // Skip over "pseudo" entries
  4936. //
  4937. if ( !( TlnEntryNew->Excluded ||
  4938. TlnEntryNew->SubordinateEntry == NULL )) {
  4939. continue;
  4940. }
  4941. for ( LIST_ENTRY * ListEntryAvl = TlnEntryNew->TlnKey->List.Flink;
  4942. ListEntryAvl != &TlnEntryNew->TlnKey->List;
  4943. ListEntryAvl = ListEntryAvl->Flink ) {
  4944. TLN_ENTRY * TlnEntryOld;
  4945. TlnEntryOld = TLN_ENTRY::EntryFromAvlEntry( ListEntryAvl );
  4946. //
  4947. // Specifically looking for old entries
  4948. //
  4949. if ( TlnEntryOld->TdoEntry != TdoEntryOld ) {
  4950. continue;
  4951. }
  4952. //
  4953. // Skip over "pseudo" entries
  4954. //
  4955. if ( !( TlnEntryOld->Excluded ||
  4956. TlnEntryOld->SubordinateEntry == NULL )) {
  4957. continue;
  4958. }
  4959. if ( TlnEntryNew->Excluded != TlnEntryOld->Excluded ) {
  4960. continue;
  4961. }
  4962. Found = TRUE;
  4963. //
  4964. // The only thing that can change on a top level name entry
  4965. // is its flags
  4966. //
  4967. if ( TlnEntryOld->Flags() != TlnEntryNew->Flags()) {
  4968. //
  4969. // Bug 494666: log disabled TLN entries
  4970. // regardless of auditing being enabled or not
  4971. //
  4972. if ( MustLogNewTLN( TlnEntryOld )) {
  4973. LogNewTLN(
  4974. &( TlnEntryNew->TlnKey->TopLevelName ),
  4975. &( TdoEntry->TrustedDomainName )
  4976. );
  4977. }
  4978. //
  4979. // if auditing is enabled
  4980. //
  4981. if ( AuditingEnabled ) {
  4982. Status = LsapAdtTrustedForestInfoEntryMod(
  4983. ( PUNICODE_STRING )&TdoEntry->TrustedDomainName,
  4984. TdoEntry->TrustedDomainSid,
  4985. &OperationId,
  4986. TlnEntryOld->Excluded ?
  4987. ForestTrustTopLevelNameEx :
  4988. ForestTrustTopLevelName,
  4989. TlnEntryOld->Flags(),
  4990. &TlnEntryOld->TlnKey->TopLevelName,
  4991. NULL,
  4992. NULL,
  4993. NULL,
  4994. TlnEntryNew->Flags(),
  4995. &TlnEntryNew->TlnKey->TopLevelName,
  4996. NULL,
  4997. NULL,
  4998. NULL
  4999. );
  5000. if ( !NT_SUCCESS( Status )) {
  5001. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%lx on entries %p (old) and %p (new) (%s:%d)\n", Status, TlnEntryOld, TlnEntryNew, __FILE__, __LINE__ ));
  5002. }
  5003. }
  5004. Modified = TRUE;
  5005. }
  5006. //
  5007. // The Index field of the entry is reused here to aid performance.
  5008. // Index contains the ordinal number the entry had in the original
  5009. // array of FTInfo entries. This is necessary in order to report
  5010. // conflict information during insertion, and the data is NOT
  5011. // used anywhere afterwards.
  5012. // We set this field to '-1' here. Later, when looking for
  5013. // old entries that are being removed, the algorithm is simply to
  5014. // pick those whose index field is not -1 and report them as removals.
  5015. //
  5016. ASSERT( TlnEntryOld->Index != 0xFFFFFFFF );
  5017. TlnEntryOld->Index = 0xFFFFFFFF;
  5018. break;
  5019. }
  5020. //
  5021. // If an entry wasn't a modification, it's an addition
  5022. //
  5023. if ( !Found && !Modified ) {
  5024. //
  5025. // Bug 494666: log disabled TLN entries (since they are new)
  5026. // regardless of auditing being enabled or not
  5027. //
  5028. if ( MustLogNewTLN( TlnEntryNew )) {
  5029. LogNewTLN(
  5030. &( TlnEntryNew->TlnKey->TopLevelName ),
  5031. &( TdoEntry->TrustedDomainName )
  5032. );
  5033. }
  5034. //
  5035. // if auditing is not enabled
  5036. // continue with the next TLN entry
  5037. //
  5038. if ( !AuditingEnabled ) {
  5039. continue;
  5040. }
  5041. Status = LsapAdtTrustedForestInfoEntryAdd(
  5042. ( PUNICODE_STRING )&TdoEntry->TrustedDomainName,
  5043. TdoEntry->TrustedDomainSid,
  5044. &OperationId,
  5045. TlnEntryNew->Excluded ?
  5046. ForestTrustTopLevelNameEx :
  5047. ForestTrustTopLevelName,
  5048. TlnEntryNew->Flags(),
  5049. &TlnEntryNew->TlnKey->TopLevelName,
  5050. NULL,
  5051. NULL,
  5052. NULL
  5053. );
  5054. if ( !NT_SUCCESS( Status )) {
  5055. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%lx on entry %p (%s:%d)\n", Status, TlnEntryNew, __FILE__, __LINE__ ));
  5056. }
  5057. }
  5058. }
  5059. //
  5060. // if Auditing is not enabled
  5061. // there is nothing left to do
  5062. // so goto cleanup
  5063. //
  5064. if ( !AuditingEnabled ) {
  5065. goto Cleanup;
  5066. }
  5067. //
  5068. // Go through old entries, see if they have been marked as
  5069. // found. If not, audit them as removals.
  5070. //
  5071. for ( ListEntry = TdoEntryOld->TlnList.Flink;
  5072. ListEntry != &TdoEntryOld->TlnList;
  5073. ListEntry = ListEntry->Flink ) {
  5074. TLN_ENTRY * TlnEntryOld;
  5075. TlnEntryOld = TLN_ENTRY::EntryFromTdoEntry( ListEntry );
  5076. //
  5077. // Skip over "pseudo" entries
  5078. //
  5079. if ( !( TlnEntryOld->Excluded ||
  5080. TlnEntryOld->SubordinateEntry == NULL )) {
  5081. continue;
  5082. }
  5083. //
  5084. // Entries marked with index of 0xFFFFFFFF have been
  5085. // found when looking for modifications. Skip over those here.
  5086. //
  5087. if ( TlnEntryOld->Index == 0xFFFFFFFF ) {
  5088. TlnEntryOld->Index = 0; // no need to keep the special value around
  5089. continue;
  5090. }
  5091. Status = LsapAdtTrustedForestInfoEntryRem(
  5092. ( PUNICODE_STRING )&TdoEntry->TrustedDomainName,
  5093. TdoEntry->TrustedDomainSid,
  5094. &OperationId,
  5095. TlnEntryOld->Excluded ?
  5096. ForestTrustTopLevelNameEx :
  5097. ForestTrustTopLevelName,
  5098. TlnEntryOld->Flags(),
  5099. &TlnEntryOld->TlnKey->TopLevelName,
  5100. NULL,
  5101. NULL,
  5102. NULL
  5103. );
  5104. if ( !NT_SUCCESS( Status )) {
  5105. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%x on entry %p (%s:%d)\n", Status, TlnEntryOld, __FILE__, __LINE__ ));
  5106. }
  5107. }
  5108. //
  5109. // Go through new domain info entries, see if they are present in the old list
  5110. // If not, they're additions
  5111. // If yes, check for modifications
  5112. //
  5113. for ( ListEntry = TdoEntryNew->DomainInfoList.Flink;
  5114. ListEntry != &TdoEntryNew->DomainInfoList;
  5115. ListEntry = ListEntry->Flink ) {
  5116. DOMAIN_INFO_ENTRY * DomainInfoEntryNew;
  5117. BOOLEAN Found = FALSE;
  5118. BOOLEAN Modified = FALSE;
  5119. DomainInfoEntryNew = DOMAIN_INFO_ENTRY::EntryFromTdoEntry( ListEntry );
  5120. //
  5121. // The invariant of any entry is its SID
  5122. // The assumption is that for a given SID, the DNS name and Netbios
  5123. // name may change, as well as flags
  5124. //
  5125. for ( LIST_ENTRY * ListEntrySid = DomainInfoEntryNew->SidKey->List.Flink;
  5126. ListEntrySid != &DomainInfoEntryNew->SidKey->List;
  5127. ListEntrySid = ListEntrySid->Flink ) {
  5128. DOMAIN_INFO_ENTRY * DomainInfoEntryOld;
  5129. DomainInfoEntryOld = DOMAIN_INFO_ENTRY::EntryFromSidEntry( ListEntrySid );
  5130. //
  5131. // Specifically looking for old entries
  5132. //
  5133. if ( DomainInfoEntryOld->TdoEntry != TdoEntryOld ) {
  5134. continue;
  5135. }
  5136. Found = TRUE;
  5137. if ( DomainInfoEntryOld->Flags() != DomainInfoEntryNew->Flags()) {
  5138. Modified = TRUE;
  5139. } else if ( !RtlEqualUnicodeString(
  5140. &DomainInfoEntryOld->DnsKey->DnsName,
  5141. &DomainInfoEntryNew->DnsKey->DnsName,
  5142. TRUE )) {
  5143. Modified = TRUE;
  5144. } else if ( XOR<NETBIOS_NAME_KEY*>(
  5145. DomainInfoEntryOld->NetbiosKey,
  5146. DomainInfoEntryNew->NetbiosKey )) {
  5147. Modified = TRUE;
  5148. } else if ( DomainInfoEntryOld->NetbiosKey &&
  5149. DomainInfoEntryNew->NetbiosKey &&
  5150. !RtlEqualUnicodeString(
  5151. &DomainInfoEntryOld->NetbiosKey->NetbiosName,
  5152. &DomainInfoEntryNew->NetbiosKey->NetbiosName,
  5153. TRUE )) {
  5154. Modified = TRUE;
  5155. }
  5156. if ( Modified ) {
  5157. Status = LsapAdtTrustedForestInfoEntryMod(
  5158. ( PUNICODE_STRING )&TdoEntry->TrustedDomainName,
  5159. TdoEntry->TrustedDomainSid,
  5160. &OperationId,
  5161. ForestTrustDomainInfo,
  5162. DomainInfoEntryOld->Flags(),
  5163. NULL,
  5164. &DomainInfoEntryOld->DnsKey->DnsName,
  5165. DomainInfoEntryOld->NetbiosKey ?
  5166. &DomainInfoEntryOld->NetbiosKey->NetbiosName :
  5167. NULL,
  5168. DomainInfoEntryOld->Sid,
  5169. DomainInfoEntryNew->Flags(),
  5170. NULL,
  5171. &DomainInfoEntryNew->DnsKey->DnsName,
  5172. DomainInfoEntryNew->NetbiosKey ?
  5173. &DomainInfoEntryNew->NetbiosKey->NetbiosName :
  5174. NULL,
  5175. DomainInfoEntryNew->Sid
  5176. );
  5177. if ( !NT_SUCCESS( Status )) {
  5178. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%lx on entries %p (old) and %p (new) (%s:%d)\n", Status, DomainInfoEntryOld, DomainInfoEntryNew, __FILE__, __LINE__ ));
  5179. }
  5180. }
  5181. //
  5182. // The Index field of the entry is reused here to aid performance.
  5183. // Index contains the ordinal number the entry had in the original
  5184. // array of FTInfo entries. This is necessary in order to report
  5185. // conflict information during insertion, and the data is NOT
  5186. // used anywhere afterwards.
  5187. // We set this field to '-1' here. Later, when looking for
  5188. // old entries that are being removed, the algorithm is simply to
  5189. // pick those whose index field is not -1 and report them as removals.
  5190. //
  5191. ASSERT( DomainInfoEntryOld->Index != 0xFFFFFFFF );
  5192. DomainInfoEntryOld->Index = 0xFFFFFFFF;
  5193. break;
  5194. }
  5195. //
  5196. // If an entry wasn't a modification, it's an addition
  5197. //
  5198. if ( !Found && !Modified ) {
  5199. Status = LsapAdtTrustedForestInfoEntryAdd(
  5200. ( PUNICODE_STRING )&TdoEntry->TrustedDomainName,
  5201. TdoEntry->TrustedDomainSid,
  5202. &OperationId,
  5203. ForestTrustDomainInfo,
  5204. DomainInfoEntryNew->Flags(),
  5205. NULL,
  5206. &DomainInfoEntryNew->DnsKey->DnsName,
  5207. DomainInfoEntryNew->NetbiosKey ?
  5208. &DomainInfoEntryNew->NetbiosKey->NetbiosName :
  5209. NULL,
  5210. DomainInfoEntryNew->Sid
  5211. );
  5212. if ( !NT_SUCCESS( Status )) {
  5213. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%lx on entry %p (%s:%d)\n", Status, DomainInfoEntryNew, __FILE__, __LINE__ ));
  5214. }
  5215. }
  5216. }
  5217. //
  5218. // Go through old entries, see if they have been marked as
  5219. // modified. If not, audit them as removals.
  5220. //
  5221. for ( ListEntry = TdoEntryOld->DomainInfoList.Flink;
  5222. ListEntry != &TdoEntryOld->DomainInfoList;
  5223. ListEntry = ListEntry->Flink ) {
  5224. DOMAIN_INFO_ENTRY * DomainInfoEntryOld;
  5225. DomainInfoEntryOld = DOMAIN_INFO_ENTRY::EntryFromTdoEntry( ListEntry );
  5226. //
  5227. // Entries marked with index of 0xFFFFFFFF have been
  5228. // found when looking for modifications. Skip over those here.
  5229. //
  5230. if ( DomainInfoEntryOld->Index == 0xFFFFFFFF ) {
  5231. DomainInfoEntryOld->Index = 0; // no need to keep the special value around
  5232. continue;
  5233. }
  5234. Status = LsapAdtTrustedForestInfoEntryRem(
  5235. ( PUNICODE_STRING )&TdoEntry->TrustedDomainName,
  5236. TdoEntry->TrustedDomainSid,
  5237. &OperationId,
  5238. ForestTrustDomainInfo,
  5239. DomainInfoEntryOld->Flags(),
  5240. NULL,
  5241. &DomainInfoEntryOld->DnsKey->DnsName,
  5242. DomainInfoEntryOld->NetbiosKey ?
  5243. &DomainInfoEntryOld->NetbiosKey->NetbiosName :
  5244. NULL,
  5245. DomainInfoEntryOld->Sid
  5246. );
  5247. if ( !NT_SUCCESS( Status )) {
  5248. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%lx on entry %p (%s:%d)\n", Status, TdoEntry, __FILE__, __LINE__ ));
  5249. }
  5250. }
  5251. //
  5252. // Binary entries are audited as replacements
  5253. //
  5254. for ( ListEntry = TdoEntryOld->BinaryList.Flink;
  5255. ListEntry != &TdoEntryOld->BinaryList;
  5256. ListEntry = ListEntry->Flink ) {
  5257. BINARY_ENTRY * BinaryEntry;
  5258. BinaryEntry = BINARY_ENTRY::EntryFromTdoEntry( ListEntry );
  5259. Status = LsapAdtTrustedForestInfoEntryRem(
  5260. ( PUNICODE_STRING )&TdoEntryOld->TrustedDomainName,
  5261. TdoEntryOld->TrustedDomainSid,
  5262. &OperationId,
  5263. BinaryEntry->Type,
  5264. BinaryEntry->Flags(),
  5265. NULL,
  5266. NULL,
  5267. NULL,
  5268. NULL
  5269. );
  5270. if ( !NT_SUCCESS( Status )) {
  5271. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%lx on entry %p (%s:%d)\n", Status, TdoEntryOld, __FILE__, __LINE__ ));
  5272. goto Cleanup;
  5273. }
  5274. }
  5275. for ( ListEntry = TdoEntryNew->BinaryList.Flink;
  5276. ListEntry != &TdoEntryNew->BinaryList;
  5277. ListEntry = ListEntry->Flink ) {
  5278. BINARY_ENTRY * BinaryEntry;
  5279. BinaryEntry = BINARY_ENTRY::EntryFromTdoEntry( ListEntry );
  5280. Status = LsapAdtTrustedForestInfoEntryAdd(
  5281. ( PUNICODE_STRING )&TdoEntryNew->TrustedDomainName,
  5282. TdoEntryNew->TrustedDomainSid,
  5283. &OperationId,
  5284. BinaryEntry->Type,
  5285. BinaryEntry->Flags(),
  5286. NULL,
  5287. NULL,
  5288. NULL,
  5289. NULL
  5290. );
  5291. if ( !NT_SUCCESS( Status )) {
  5292. LsapDsDebugOut(( DEB_FTINFO, "FTCache::AuditChanges: Auditing failure 0x%lx on entry %p (%s:%d)\n", Status, TdoEntryNew, __FILE__, __LINE__ ));
  5293. goto Cleanup;
  5294. }
  5295. }
  5296. }
  5297. Cleanup:
  5298. return;
  5299. }
  5300. void
  5301. FTCache::AuditCollisions(
  5302. IN CONFLICT_PAIR * ConflictPairs,
  5303. IN ULONG ConflictPairsTotal
  5304. )
  5305. /*++
  5306. Routine description:
  5307. Generates audits for collisions
  5308. Arguments:
  5309. ConflictPairs array of conflict pairs
  5310. ConflictPairsTotal number of elements in ConflictPairs
  5311. Returns:
  5312. Nothing
  5313. --*/
  5314. {
  5315. for ( ULONG i = 0 ; i < ConflictPairsTotal ; i++ ) {
  5316. NTSTATUS Status;
  5317. CONFLICT_PAIR& Pair = ConflictPairs[i];
  5318. TDO_ENTRY * TdoEntry1 = Pair.TdoEntry1();
  5319. TDO_ENTRY * TdoEntry2 = Pair.TdoEntry2();
  5320. LSA_FOREST_TRUST_COLLISION_RECORD_TYPE CollisionTargetType;
  5321. PUNICODE_STRING CollisionTargetName;
  5322. PUNICODE_STRING ForestRootDomainName;
  5323. PUNICODE_STRING TopLevelName;
  5324. PUNICODE_STRING DnsName;
  5325. PUNICODE_STRING NetbiosName;
  5326. PSID Sid;
  5327. ULONG NewFlags;
  5328. ASSERT( TdoEntry1 != NULL );
  5329. ASSERT( TdoEntry2 != NULL );
  5330. if ( TdoEntry1->LocalForestEntry ) {
  5331. CollisionTargetType = CollisionXref;
  5332. CollisionTargetName = &TdoEntry1->TrustedDomainName;
  5333. ForestRootDomainName = &TdoEntry2->TrustedDomainName;
  5334. TopLevelName = ( Pair.EntryType2 == ForestTrustTopLevelName ) ?
  5335. &Pair.TlnEntry2->TlnKey->TopLevelName : NULL;
  5336. DnsName = ( Pair.EntryType2 == ForestTrustDomainInfo ) ?
  5337. &Pair.DomainInfoEntry2->DnsKey->DnsName : NULL;
  5338. NetbiosName = ( Pair.EntryType2 == ForestTrustDomainInfo &&
  5339. Pair.DomainInfoEntry2->NetbiosKey ) ?
  5340. &Pair.DomainInfoEntry2->NetbiosKey->NetbiosName : NULL;
  5341. Sid = ( Pair.EntryType2 == ForestTrustDomainInfo ) ?
  5342. Pair.DomainInfoEntry2->SidKey->DomainSid : NULL;
  5343. NewFlags = Pair.Flag2;
  5344. } else if ( TdoEntry2->LocalForestEntry ) {
  5345. CollisionTargetType = CollisionXref;
  5346. CollisionTargetName = &TdoEntry2->TrustedDomainName;
  5347. ForestRootDomainName = &TdoEntry1->TrustedDomainName;
  5348. TopLevelName = ( Pair.EntryType1 == ForestTrustTopLevelName ) ?
  5349. &Pair.TlnEntry1->TlnKey->TopLevelName : NULL;
  5350. DnsName = ( Pair.EntryType1 == ForestTrustDomainInfo ) ?
  5351. &Pair.DomainInfoEntry1->DnsKey->DnsName : NULL;
  5352. NetbiosName = ( Pair.EntryType1 == ForestTrustDomainInfo &&
  5353. Pair.DomainInfoEntry1->NetbiosKey ) ?
  5354. &Pair.DomainInfoEntry1->NetbiosKey->NetbiosName : NULL;
  5355. Sid = ( Pair.EntryType1 == ForestTrustDomainInfo ) ?
  5356. Pair.DomainInfoEntry1->SidKey->DomainSid : NULL;
  5357. NewFlags = Pair.Flag1;
  5358. } else {
  5359. CollisionTargetType = CollisionTdo;
  5360. CollisionTargetName = &TdoEntry2->TrustedDomainName;
  5361. ForestRootDomainName = &TdoEntry1->TrustedDomainName;
  5362. TopLevelName = ( Pair.EntryType2 == ForestTrustTopLevelName ) ?
  5363. &Pair.TlnEntry2->TlnKey->TopLevelName : NULL;
  5364. DnsName = ( Pair.EntryType2 == ForestTrustDomainInfo ) ?
  5365. &Pair.DomainInfoEntry2->DnsKey->DnsName : NULL;
  5366. NetbiosName = ( Pair.EntryType2 == ForestTrustDomainInfo &&
  5367. Pair.DomainInfoEntry2->NetbiosKey ) ?
  5368. &Pair.DomainInfoEntry2->NetbiosKey->NetbiosName : NULL;
  5369. Sid = ( Pair.EntryType2 == ForestTrustDomainInfo ) ?
  5370. Pair.DomainInfoEntry2->SidKey->DomainSid : NULL;
  5371. NewFlags = Pair.Flag2;
  5372. }
  5373. Status = LsapAdtTrustedForestNamespaceCollision(
  5374. CollisionTargetType,
  5375. CollisionTargetName,
  5376. ForestRootDomainName,
  5377. TopLevelName,
  5378. DnsName,
  5379. NetbiosName,
  5380. Sid,
  5381. NewFlags
  5382. );
  5383. }
  5384. return;
  5385. }
  5386. ///////////////////////////////////////////////////////////////////////////////
  5387. //
  5388. // Marshaling routines
  5389. //
  5390. ///////////////////////////////////////////////////////////////////////////////
  5391. ULONG
  5392. LsapMarshalSid(
  5393. IN BYTE * Blob,
  5394. IN SID * Sid
  5395. )
  5396. /*++
  5397. Routine Description:
  5398. Writes the internal representation of a SID into the buffer
  5399. If buffer is NULL, returns the number of bytes needed
  5400. NOTE: The buffer, if not NULL, is assumed to be big enough!!!
  5401. Arguments:
  5402. Blob address of the target buffer
  5403. Sid SID to marshal
  5404. Returns:
  5405. if Blob != NULL, number of bytes written into the buffer
  5406. if Blob == NULL, number of bytes needed to represent the SID
  5407. --*/
  5408. {
  5409. ULONG Index = 0;
  5410. UCHAR i;
  5411. ASSERT( RtlValidSid( Sid ));
  5412. if ( Blob != NULL ) {
  5413. //
  5414. // Leave space for the length
  5415. //
  5416. Index += sizeof( ULONG );
  5417. Blob[Index] = Sid->Revision;
  5418. Index += sizeof( UCHAR );
  5419. Blob[Index] = Sid->SubAuthorityCount;
  5420. Index += sizeof( UCHAR );
  5421. ASSERT( sizeof( SID_IDENTIFIER_AUTHORITY ) == 6 );
  5422. RtlCopyMemory( &Blob[Index], Sid->IdentifierAuthority.Value, sizeof( SID_IDENTIFIER_AUTHORITY ));
  5423. Index += sizeof( SID_IDENTIFIER_AUTHORITY );
  5424. for ( i = 0 ; i < Sid->SubAuthorityCount ; i++ ) {
  5425. SmbPutUlong( &Blob[Index], Sid->SubAuthority[i] );
  5426. Index += sizeof( ULONG );
  5427. }
  5428. //
  5429. // Now that we know the length, prepend it at the beginning of the blob
  5430. //
  5431. SmbPutUlong( &Blob[0], Index - sizeof( ULONG ));
  5432. } else {
  5433. Index = sizeof( ULONG ) + // length of data that follows
  5434. sizeof( UCHAR ) + // revision
  5435. sizeof( UCHAR ) + // subauthority count
  5436. sizeof( SID_IDENTIFIER_AUTHORITY ) + // identifier authority
  5437. Sid->SubAuthorityCount * sizeof( ULONG ); // subauthority data
  5438. }
  5439. return Index;
  5440. }
  5441. ULONG
  5442. LsapUnmarshalSid(
  5443. IN BYTE * Blob,
  5444. OUT PISID * Sid
  5445. )
  5446. /*++
  5447. Routine Description:
  5448. Decodes the internal representation of a SID
  5449. Caller must use FtcFree to free the generated SID
  5450. Arguments:
  5451. Blob address of the buffer containing internal representation
  5452. of the SID
  5453. Sid used ot return the generated SID
  5454. Returns:
  5455. Number of bytes read from the blob
  5456. If memory could not be allocated or there was an error reading
  5457. data from the blob, raises an exception. The caller must be
  5458. prepared to handle this exception and use GetExceptionCode() to
  5459. obtain the reason for failure.
  5460. --*/
  5461. {
  5462. NTSTATUS Status;
  5463. ULONG Index = 0;
  5464. ULONG Length;
  5465. ASSERT( Blob );
  5466. ASSERT( Sid );
  5467. *Sid = NULL;
  5468. __try {
  5469. UCHAR Revision, SubAuthorityCount;
  5470. UCHAR i;
  5471. //
  5472. // Ignore the length field
  5473. //
  5474. Length = SmbGetUlong( &Blob[Index] );
  5475. Index += sizeof( ULONG );
  5476. Revision = ( UCHAR )Blob[Index];
  5477. Index += sizeof( BYTE );
  5478. SubAuthorityCount = ( UCHAR )Blob[Index];
  5479. Index += sizeof( BYTE );
  5480. *Sid = ( SID * )FtcAllocate(
  5481. sizeof( SID ) + SubAuthorityCount * sizeof( ULONG )
  5482. );
  5483. if ( *Sid == NULL ) {
  5484. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MatchSpn (%s:%d)\n", __FILE__, __LINE__ ));
  5485. Status = STATUS_INSUFFICIENT_RESOURCES;
  5486. goto Error;
  5487. }
  5488. (*Sid)->Revision = Revision;
  5489. (*Sid)->SubAuthorityCount = SubAuthorityCount;
  5490. ASSERT( sizeof( SID_IDENTIFIER_AUTHORITY ) == 6 );
  5491. RtlCopyMemory( (*Sid)->IdentifierAuthority.Value, &Blob[Index], sizeof( SID_IDENTIFIER_AUTHORITY ));
  5492. Index += sizeof( SID_IDENTIFIER_AUTHORITY );
  5493. for ( i = 0 ; i < SubAuthorityCount ; i++ ) {
  5494. (*Sid)->SubAuthority[i] = SmbGetUlong( &Blob[Index] );
  5495. Index += sizeof( ULONG );
  5496. }
  5497. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  5498. ASSERT( FALSE );
  5499. Status = GetExceptionCode();
  5500. goto Error;
  5501. }
  5502. //
  5503. // Verify the correctness of the length field
  5504. //
  5505. ASSERT( Length == Index - sizeof( ULONG ));
  5506. return Index;
  5507. Error:
  5508. FtcFree( *Sid );
  5509. *Sid = NULL;
  5510. RaiseException( Status, 0, 0, NULL );
  5511. return 0; // so the compiler doesn't complain
  5512. }
  5513. ULONG
  5514. LsapMarshalString(
  5515. IN BYTE * Blob,
  5516. IN UNICODE_STRING * String
  5517. )
  5518. /*++
  5519. Routine Description:
  5520. Writes an internal representation of a Unicode string into the buffer
  5521. If buffer is NULL, returns the number of bytes needed
  5522. NOTE: The buffer, if not NULL, is assumed to be big enough!!!
  5523. Arguments:
  5524. Blob address of the target buffer
  5525. String address of a UNICODE_STRING structure to marshal
  5526. Returns:
  5527. if Blob != NULL, number of bytes written into the buffer
  5528. if Blob == NULL, number of bytes needed to represent the string
  5529. If conversion to internal representation fails, will raise an
  5530. exception. Caller should be prepared to handle this exception and
  5531. use GetExceptionCode() to obtain the reason for failure.
  5532. --*/
  5533. {
  5534. ULONG Index = 0;
  5535. ULONG Length;
  5536. ASSERT( String );
  5537. //
  5538. // Leave space for the length
  5539. //
  5540. Index += sizeof( ULONG );
  5541. Length = WideCharToMultiByte(
  5542. CP_UTF8,
  5543. 0,
  5544. String->Buffer,
  5545. String->Length / sizeof( WCHAR ),
  5546. Blob ? ( LPSTR )&Blob[Index] : NULL,
  5547. Blob ? MAXLONG : 0,
  5548. NULL,
  5549. NULL
  5550. );
  5551. if ( Length == 0 && String->Length > 0 ) {
  5552. RaiseException( GetLastError(), 0, 0, NULL );
  5553. }
  5554. //
  5555. // Now that we know the length, prepend it at the beginning of the blob
  5556. //
  5557. if ( Blob != NULL ) {
  5558. SmbPutUlong( &Blob[0], Length );
  5559. }
  5560. Index += Length;
  5561. return Index;
  5562. }
  5563. ULONG
  5564. LsapUnmarshalString(
  5565. IN BYTE * Blob,
  5566. OUT UNICODE_STRING * String
  5567. )
  5568. /*++
  5569. Routine Description:
  5570. Decodes the internal representation of a Unicode string
  5571. Caller must use FtcFree to free the generated string
  5572. Arguments:
  5573. Blob address of the buffer containing internal representation
  5574. of the Unicode string
  5575. String used to return the generated string
  5576. Returns:
  5577. Number of bytes read from the blob
  5578. If memory could not be allocated or there was an error during
  5579. conversion, raises an exception. The caller must be
  5580. prepared to handle this exception and use GetExceptionCode() to
  5581. obtain the reason for failure.
  5582. --*/
  5583. {
  5584. NTSTATUS Status;
  5585. ULONG Index = 0;
  5586. ASSERT( Blob );
  5587. ASSERT( String );
  5588. String->Buffer = NULL;
  5589. __try {
  5590. ULONG Length;
  5591. //
  5592. // Obtain the length of the UTF-8 encoded unicode string
  5593. //
  5594. Length = SmbGetUlong( &Blob[Index] );
  5595. Index += sizeof( ULONG );
  5596. //
  5597. // See how big the buffer should be for the decoded string
  5598. //
  5599. if ( Length > 0 ) {
  5600. String->Length = ( USHORT )MultiByteToWideChar(
  5601. CP_UTF8,
  5602. 0,
  5603. ( LPSTR )&Blob[Index],
  5604. Length,
  5605. NULL,
  5606. 0
  5607. ) * sizeof( WCHAR );
  5608. if ( String->Length == 0 ) {
  5609. Status = GetLastError();
  5610. LsapDsDebugOut(( DEB_FTINFO, "LsapUnmarshalString: MultiByteToWideChar returned 0x%x\n", Status ));
  5611. goto Error;
  5612. }
  5613. } else {
  5614. String->Length = 0;
  5615. }
  5616. //
  5617. // Prepare to have the string NULL-terminated
  5618. //
  5619. String->MaximumLength = String->Length + sizeof( WCHAR );
  5620. String->Buffer = ( PWSTR )FtcAllocate( String->MaximumLength );
  5621. if ( String->Buffer == NULL ) {
  5622. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapUnmarshalString (%s:%d)\n", __FILE__, __LINE__ ));
  5623. Status = STATUS_INSUFFICIENT_RESOURCES;
  5624. goto Error;
  5625. }
  5626. //
  5627. // Now perform the actual conversion. Note that we don't care
  5628. // what the return value is anymore, as long as it's non-zero
  5629. //
  5630. if ( Length > 0 ) {
  5631. if (0 == MultiByteToWideChar(
  5632. CP_UTF8,
  5633. 0,
  5634. ( LPSTR )&Blob[Index],
  5635. Length,
  5636. String->Buffer,
  5637. String->Length / sizeof( WCHAR ))) {
  5638. Status = GetLastError();
  5639. ASSERT( FALSE ); // certainly not expecting this to fail (it just succeeded, above)
  5640. goto Error;
  5641. }
  5642. Index += Length;
  5643. }
  5644. //
  5645. // NULL-terminate the string for future convenience
  5646. //
  5647. (String->Buffer)[String->Length / sizeof( WCHAR )] = L'\0';
  5648. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  5649. ASSERT( FALSE );
  5650. Status = GetExceptionCode();
  5651. goto Error;
  5652. }
  5653. return Index;
  5654. Error:
  5655. FtcFree( String->Buffer );
  5656. String->Buffer = NULL;
  5657. RaiseException( Status, 0, 0, NULL );
  5658. return 0; // so the compiler doesn't complain
  5659. }
  5660. ULONG
  5661. LsapUnmarshalData(
  5662. IN BYTE * Blob,
  5663. OUT LSA_FOREST_TRUST_BINARY_DATA * Data
  5664. )
  5665. /*++
  5666. Routine Description:
  5667. Decodes the internal representation of a binary data blob
  5668. Caller must use FtcFree to free the generated structure
  5669. Arguments:
  5670. Blob address of the buffer containing internal representation
  5671. of the binary blob
  5672. Data used to return the generated blob
  5673. Returns:
  5674. Number of bytes read from the blob
  5675. If memory could not be allocated, raises an exception.
  5676. The caller must be prepared to handle this exception and use
  5677. GetExceptionCode() to obtain the reason for failure.
  5678. --*/
  5679. {
  5680. NTSTATUS Status;
  5681. ULONG Index = 0;
  5682. ASSERT( Blob );
  5683. ASSERT( Data );
  5684. Data->Buffer = NULL;
  5685. __try {
  5686. //
  5687. // Obtain the length
  5688. //
  5689. Data->Length = SmbGetUlong( &Blob[Index] );
  5690. Index += sizeof( ULONG );
  5691. if ( Data->Length > 0 ) {
  5692. Data->Buffer = ( BYTE * )FtcAllocate( Data->Length );
  5693. if ( Data->Buffer == NULL ) {
  5694. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapUnmarshalData (%s:%d)\n", __FILE__, __LINE__ ));
  5695. Status = STATUS_INSUFFICIENT_RESOURCES;
  5696. goto Error;
  5697. }
  5698. RtlCopyMemory( Data->Buffer, &Blob[Index], Data->Length );
  5699. Index += Data->Length;
  5700. }
  5701. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  5702. Status = GetExceptionCode();
  5703. ASSERT( FALSE );
  5704. goto Error;
  5705. }
  5706. return Index;
  5707. Error:
  5708. FtcFree( Data->Buffer );
  5709. Data->Buffer = NULL;
  5710. RaiseException( Status, 0, 0, NULL );
  5711. return 0; // so the compiler doesn't complain
  5712. }
  5713. NTSTATUS
  5714. FTCache::MarshalBlob(
  5715. IN TDO_ENTRY * TdoEntry,
  5716. OUT ULONG * MarshaledSize,
  5717. OUT PBYTE * MarshaledBlob
  5718. )
  5719. /*++
  5720. Routine Description:
  5721. Marshals the given ForestTrustInfo structure into a string of bytes
  5722. Arguments:
  5723. TdoEntry Entry in the cache containing data to marshal
  5724. MarshaledSize Used to return the number of bytes in MarshaledBlob
  5725. MarshaledBlob Used to return the marshaled data
  5726. Returns:
  5727. STATUS_SUCCESS
  5728. STATUS_INVALID_PARAMETER
  5729. STATUS_INSUFFICIENT_RESOURCES
  5730. --*/
  5731. {
  5732. NTSTATUS Status = STATUS_SUCCESS;
  5733. ULONG Length = 0;
  5734. BYTE * Blob = NULL;
  5735. ULONG Index;
  5736. ULONG Records = 0;
  5737. LIST_ENTRY * ListEntry;
  5738. if ( TdoEntry == NULL ||
  5739. MarshaledSize == NULL ||
  5740. MarshaledBlob == NULL ) {
  5741. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in FTCache::MarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  5742. return STATUS_INVALID_PARAMETER;
  5743. }
  5744. //
  5745. // First figure out how big the blob is going to be
  5746. //
  5747. //
  5748. // Version number is at the beginning of every blob
  5749. //
  5750. Length = sizeof( ULONG );
  5751. //
  5752. // Number of entries follows the version # of the blob
  5753. //
  5754. Length += sizeof( ULONG );
  5755. //
  5756. // Every record has certain common elements. Count them here.
  5757. //
  5758. Length += TdoEntry->RecordCount * (
  5759. //
  5760. // Length of the record
  5761. //
  5762. sizeof( ULONG ) +
  5763. //
  5764. // "Flags"
  5765. //
  5766. sizeof( ULONG ) +
  5767. //
  5768. // Timestamp
  5769. //
  5770. 2 * sizeof( ULONG ) +
  5771. //
  5772. // Record type (no more tha 256 different values allowed)
  5773. //
  5774. sizeof( BYTE )
  5775. );
  5776. //
  5777. // Iterate over top level name entries
  5778. //
  5779. for ( ListEntry = TdoEntry->TlnList.Flink;
  5780. ListEntry != &TdoEntry->TlnList;
  5781. ListEntry = ListEntry->Flink ) {
  5782. TLN_ENTRY * TlnEntry;
  5783. TlnEntry = TLN_ENTRY::EntryFromTdoEntry( ListEntry );
  5784. //
  5785. // Ignore artifically inserted "pseudo" entries
  5786. //
  5787. if ( !( TlnEntry->Excluded ||
  5788. TlnEntry->SubordinateEntry == NULL )) {
  5789. continue;
  5790. }
  5791. ASSERT( Records < TdoEntry->RecordCount );
  5792. Records += 1;
  5793. __try {
  5794. Length += LsapMarshalString( NULL, &TlnEntry->TlnKey->TopLevelName );
  5795. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  5796. Status = GetExceptionCode();
  5797. break;
  5798. }
  5799. }
  5800. if ( !NT_SUCCESS( Status )) {
  5801. goto Error;
  5802. }
  5803. //
  5804. // Iterate over domain info entries
  5805. //
  5806. for ( ListEntry = TdoEntry->DomainInfoList.Flink;
  5807. ListEntry != &TdoEntry->DomainInfoList;
  5808. ListEntry = ListEntry->Flink ) {
  5809. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  5810. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromTdoEntry( ListEntry );
  5811. ASSERT( Records < TdoEntry->RecordCount );
  5812. Records += 1;
  5813. __try {
  5814. Length += LsapMarshalSid( NULL, DomainInfoEntry->Sid );
  5815. Length += LsapMarshalString( NULL, &DomainInfoEntry->DnsKey->DnsName );
  5816. if ( DomainInfoEntry->NetbiosKey ) {
  5817. Length += LsapMarshalString( NULL, &DomainInfoEntry->NetbiosKey->NetbiosName );
  5818. } else {
  5819. UNICODE_STRING EmptyString = { 0, 0, NULL };
  5820. Length += LsapMarshalString( NULL, &EmptyString );
  5821. }
  5822. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  5823. Status = GetExceptionCode();
  5824. break;
  5825. }
  5826. }
  5827. if ( !NT_SUCCESS( Status )) {
  5828. goto Error;
  5829. }
  5830. //
  5831. // Iterate over binary entries
  5832. //
  5833. for ( ListEntry = TdoEntry->BinaryList.Flink;
  5834. ListEntry != &TdoEntry->BinaryList;
  5835. ListEntry = ListEntry->Flink ) {
  5836. BINARY_ENTRY * BinaryEntry;
  5837. BinaryEntry = BINARY_ENTRY::EntryFromTdoEntry( ListEntry );
  5838. ASSERT( Records < TdoEntry->RecordCount );
  5839. Records += 1;
  5840. //
  5841. // Space for the length
  5842. //
  5843. Length += sizeof( ULONG );
  5844. //
  5845. // Space for the data
  5846. //
  5847. Length += BinaryEntry->Data.Length;
  5848. }
  5849. ASSERT( NT_SUCCESS( Status ));
  5850. ASSERT( Records == TdoEntry->RecordCount );
  5851. //
  5852. // Now, allocate space and populate it
  5853. //
  5854. ASSERT( Length > 0 );
  5855. Blob = ( BYTE * )FtcAllocate( Length );
  5856. if ( Blob == NULL ) {
  5857. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in FTCache::MarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  5858. Status = STATUS_INSUFFICIENT_RESOURCES;
  5859. goto Error;
  5860. }
  5861. //
  5862. // Start with the version # of the blob
  5863. //
  5864. Index = 0;
  5865. SmbPutUlong( &Blob[Index], LSAP_FOREST_TRUST_BLOB_VERSION );
  5866. Index += sizeof( ULONG );
  5867. ASSERT( Index <= Length );
  5868. //
  5869. // Number of entries follows the version # of the blob
  5870. //
  5871. SmbPutUlong( &Blob[Index], TdoEntry->RecordCount );
  5872. Index += sizeof( ULONG );
  5873. ASSERT( Index <= Length );
  5874. //
  5875. // Iterate over top level name entries
  5876. //
  5877. for ( ListEntry = TdoEntry->TlnList.Flink;
  5878. ListEntry != &TdoEntry->TlnList;
  5879. ListEntry = ListEntry->Flink ) {
  5880. TLN_ENTRY * TlnEntry;
  5881. ULONG StartingIndex;
  5882. TlnEntry = TLN_ENTRY::EntryFromTdoEntry( ListEntry );
  5883. //
  5884. // Ignore artifically inserted "pseudo" entries
  5885. //
  5886. if ( !( TlnEntry->Excluded ||
  5887. TlnEntry->SubordinateEntry == NULL )) {
  5888. continue;
  5889. }
  5890. //
  5891. // Reserve space for the length
  5892. //
  5893. StartingIndex = Index;
  5894. Index += sizeof( ULONG );
  5895. //
  5896. // "Flags"
  5897. //
  5898. SmbPutUlong( &Blob[Index], TlnEntry->Flags());
  5899. Index += sizeof( ULONG );
  5900. ASSERT( Index <= Length );
  5901. //
  5902. // Timestamp
  5903. //
  5904. SmbPutUlong( &Blob[Index], TlnEntry->Time.HighPart );
  5905. Index += sizeof( ULONG );
  5906. ASSERT( Index <= Length );
  5907. SmbPutUlong( &Blob[Index], TlnEntry->Time.LowPart );
  5908. Index += sizeof( ULONG );
  5909. ASSERT( Index <= Length );
  5910. //
  5911. // Record type
  5912. //
  5913. Blob[Index] = ( BYTE )( TlnEntry->Excluded ?
  5914. ForestTrustTopLevelNameEx :
  5915. ForestTrustTopLevelName );
  5916. Index += sizeof( BYTE );
  5917. ASSERT( Index <= Length );
  5918. __try {
  5919. Index += LsapMarshalString( &Blob[Index], &TlnEntry->TlnKey->TopLevelName );
  5920. ASSERT( Index <= Length );
  5921. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  5922. Status = GetExceptionCode();
  5923. break;
  5924. }
  5925. //
  5926. // Remember the length
  5927. //
  5928. SmbPutUlong( &Blob[StartingIndex], Index - ( StartingIndex + sizeof( ULONG )));
  5929. }
  5930. if ( !NT_SUCCESS( Status )) {
  5931. goto Error;
  5932. }
  5933. //
  5934. // Iterate over domain info entries
  5935. //
  5936. for ( ListEntry = TdoEntry->DomainInfoList.Flink;
  5937. ListEntry != &TdoEntry->DomainInfoList;
  5938. ListEntry = ListEntry->Flink ) {
  5939. DOMAIN_INFO_ENTRY * DomainInfoEntry;
  5940. ULONG StartingIndex;
  5941. DomainInfoEntry = DOMAIN_INFO_ENTRY::EntryFromTdoEntry( ListEntry );
  5942. //
  5943. // Reserve space for the length
  5944. //
  5945. StartingIndex = Index;
  5946. Index += sizeof( ULONG );
  5947. //
  5948. // "Flags"
  5949. //
  5950. SmbPutUlong( &Blob[Index], DomainInfoEntry->Flags());
  5951. Index += sizeof( ULONG );
  5952. ASSERT( Index <= Length );
  5953. //
  5954. // Timestamp
  5955. //
  5956. SmbPutUlong( &Blob[Index], DomainInfoEntry->Time.HighPart );
  5957. Index += sizeof( ULONG );
  5958. ASSERT( Index <= Length );
  5959. SmbPutUlong( &Blob[Index], DomainInfoEntry->Time.LowPart );
  5960. Index += sizeof( ULONG );
  5961. ASSERT( Index <= Length );
  5962. //
  5963. // Record type
  5964. //
  5965. Blob[Index] = ( BYTE )( ForestTrustDomainInfo );
  5966. Index += sizeof( BYTE );
  5967. ASSERT( Index <= Length );
  5968. __try {
  5969. Index += LsapMarshalSid( &Blob[Index], DomainInfoEntry->Sid );
  5970. ASSERT( Index <= Length );
  5971. Index += LsapMarshalString( &Blob[Index], &DomainInfoEntry->DnsKey->DnsName );
  5972. ASSERT( Index <= Length );
  5973. if ( DomainInfoEntry->NetbiosKey ) {
  5974. Index += LsapMarshalString( &Blob[Index], &DomainInfoEntry->NetbiosKey->NetbiosName );
  5975. ASSERT( Index <= Length );
  5976. } else {
  5977. UNICODE_STRING EmptyString = { 0, 0, NULL };
  5978. Index += LsapMarshalString( &Blob[Index], &EmptyString );
  5979. ASSERT( Index <= Length );
  5980. }
  5981. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  5982. Status = GetExceptionCode();
  5983. break;
  5984. }
  5985. //
  5986. // Remember the length
  5987. //
  5988. SmbPutUlong( &Blob[StartingIndex], Index - ( StartingIndex + sizeof( ULONG )));
  5989. }
  5990. if ( !NT_SUCCESS( Status )) {
  5991. goto Error;
  5992. }
  5993. //
  5994. // Iterate over binary entries
  5995. //
  5996. for ( ListEntry = TdoEntry->BinaryList.Flink;
  5997. ListEntry != &TdoEntry->BinaryList;
  5998. ListEntry = ListEntry->Flink ) {
  5999. BINARY_ENTRY * BinaryEntry;
  6000. ULONG StartingIndex;
  6001. BinaryEntry = BINARY_ENTRY::EntryFromTdoEntry( ListEntry );
  6002. //
  6003. // Reserve space for the length
  6004. //
  6005. StartingIndex = Index;
  6006. Index += sizeof( ULONG );
  6007. //
  6008. // "Flags"
  6009. //
  6010. SmbPutUlong( &Blob[Index], BinaryEntry->Flags());
  6011. Index += sizeof( ULONG );
  6012. ASSERT( Index <= Length );
  6013. //
  6014. // Timestamp
  6015. //
  6016. SmbPutUlong( &Blob[Index], BinaryEntry->Time.HighPart );
  6017. Index += sizeof( ULONG );
  6018. ASSERT( Index <= Length );
  6019. SmbPutUlong( &Blob[Index], BinaryEntry->Time.LowPart );
  6020. Index += sizeof( ULONG );
  6021. ASSERT( Index <= Length );
  6022. //
  6023. // Record type
  6024. //
  6025. Blob[Index] = ( BYTE )( BinaryEntry->Type );
  6026. Index += sizeof( BYTE );
  6027. ASSERT( Index <= Length );
  6028. //
  6029. // Blob length
  6030. //
  6031. SmbPutUlong( &Blob[Index], BinaryEntry->Data.Length );
  6032. Index += sizeof( ULONG );
  6033. ASSERT( Index <= Length );
  6034. //
  6035. // Blob data
  6036. //
  6037. RtlCopyMemory( &Blob[Index], BinaryEntry->Data.Buffer, BinaryEntry->Data.Length );
  6038. Index += BinaryEntry->Data.Length;
  6039. ASSERT( Index <= Length );
  6040. //
  6041. // Remember the record length
  6042. //
  6043. SmbPutUlong( &Blob[StartingIndex], Index - ( StartingIndex + sizeof( ULONG )));
  6044. }
  6045. ASSERT( Status == STATUS_SUCCESS );
  6046. Cleanup:
  6047. *MarshaledSize = Length;
  6048. *MarshaledBlob = Blob;
  6049. return Status;
  6050. Error:
  6051. ASSERT( !NT_SUCCESS( Status ));
  6052. FtcFree( Blob );
  6053. Blob = NULL;
  6054. Length = 0;
  6055. goto Cleanup;
  6056. }
  6057. NTSTATUS
  6058. LsapForestTrustUnmarshalBlob(
  6059. IN ULONG Length,
  6060. IN BYTE * Blob,
  6061. IN LSA_FOREST_TRUST_RECORD_TYPE HighestRecordType,
  6062. OUT LSA_FOREST_TRUST_INFORMATION * ForestTrustInfo
  6063. )
  6064. /*++
  6065. Routine Description:
  6066. Takes a marshalled blob and makes sense of it by extracting a coherent
  6067. forest trust information structure
  6068. Arguments:
  6069. Length Length of the buffer pointed to by Blob
  6070. Blob Marshaled data
  6071. HighestRecordType Highest record type the client understands
  6072. ForestTrustInfo Used to return the unmarshaled information
  6073. Returns:
  6074. STATUS_SUCCESS
  6075. STATUS_INVALID_PARAMETER
  6076. STATUS_INSUFFICIENT_RESOURCES
  6077. STATUS_UNKNOWN_REVISION The forest trust blob's version is unrecognized
  6078. --*/
  6079. {
  6080. NTSTATUS Status;
  6081. ULONG Index = 0;
  6082. ULONG i = 0;
  6083. //
  6084. // ISSUE-2000/07/21-markpu
  6085. // highest record type is as yet unused
  6086. //
  6087. UNREFERENCED_PARAMETER( HighestRecordType );
  6088. if ( Blob == NULL ||
  6089. ForestTrustInfo == NULL ) {
  6090. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6091. return STATUS_INVALID_PARAMETER;
  6092. }
  6093. ForestTrustInfo->RecordCount = 0;
  6094. ForestTrustInfo->Entries = NULL;
  6095. __try {
  6096. ULONG Version;
  6097. //
  6098. // Retrieve and check the version # of the blob
  6099. //
  6100. Version = SmbGetUlong( &Blob[Index] );
  6101. Index += sizeof( ULONG );
  6102. if ( Index > Length ) {
  6103. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6104. Status = STATUS_INVALID_PARAMETER;
  6105. ASSERT( FALSE );
  6106. goto Error;
  6107. }
  6108. if ( Version != LSAP_FOREST_TRUST_BLOB_VERSION ) {
  6109. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6110. Status = STATUS_UNKNOWN_REVISION;
  6111. goto Error;
  6112. }
  6113. //
  6114. // Retrieve the number of entries and allocate space for the array
  6115. //
  6116. ForestTrustInfo->RecordCount = SmbGetUlong( &Blob[Index] );
  6117. Index += sizeof( ULONG );
  6118. ASSERT( Index <= Length );
  6119. if ( Index > Length ) {
  6120. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6121. Status = STATUS_INVALID_PARAMETER;
  6122. ASSERT( FALSE );
  6123. goto Error;
  6124. }
  6125. if ( ForestTrustInfo->RecordCount > 0 ) {
  6126. ForestTrustInfo->Entries = ( LSA_FOREST_TRUST_RECORD * * )FtcAllocate(
  6127. ForestTrustInfo->RecordCount *
  6128. sizeof( LSA_FOREST_TRUST_RECORD * )
  6129. );
  6130. if ( ForestTrustInfo->Entries == NULL ) {
  6131. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6132. Status = STATUS_INSUFFICIENT_RESOURCES;
  6133. goto Error;
  6134. }
  6135. }
  6136. for ( i = 0 ; i < ForestTrustInfo->RecordCount ; i++ ) {
  6137. LSA_FOREST_TRUST_RECORD * Record;
  6138. ULONG RecordLength;
  6139. ULONG StartingIndex;
  6140. Record = ForestTrustInfo->Entries[i] = ( LSA_FOREST_TRUST_RECORD * )FtcAllocate(
  6141. sizeof( LSA_FOREST_TRUST_RECORD )
  6142. );
  6143. if ( Record == NULL ) {
  6144. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6145. Status = STATUS_INSUFFICIENT_RESOURCES;
  6146. goto Error;
  6147. }
  6148. StartingIndex = Index;
  6149. RecordLength = SmbGetUlong( &Blob[Index] );
  6150. Index += sizeof( ULONG );
  6151. if ( Index > Length ) {
  6152. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6153. Status = STATUS_INVALID_PARAMETER;
  6154. ASSERT( FALSE );
  6155. goto Error;
  6156. }
  6157. Record->Flags = SmbGetUlong( &Blob[Index] );
  6158. Index += sizeof( ULONG );
  6159. if ( Index > Length ) {
  6160. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6161. Status = STATUS_INVALID_PARAMETER;
  6162. ASSERT( FALSE );
  6163. goto Error;
  6164. }
  6165. Record->Time.HighPart = SmbGetUlong( &Blob[Index] );
  6166. Index += sizeof( ULONG );
  6167. if ( Index > Length ) {
  6168. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6169. Status = STATUS_INVALID_PARAMETER;
  6170. ASSERT( FALSE );
  6171. goto Error;
  6172. }
  6173. Record->Time.LowPart = SmbGetUlong( &Blob[Index] );
  6174. Index += sizeof( ULONG );
  6175. if ( Index > Length ) {
  6176. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6177. Status = STATUS_INVALID_PARAMETER;
  6178. ASSERT( FALSE );
  6179. goto Error;
  6180. }
  6181. Record->ForestTrustType = ( LSA_FOREST_TRUST_RECORD_TYPE )Blob[Index];
  6182. Index += sizeof( BYTE );
  6183. if ( Index > Length ) {
  6184. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6185. Status = STATUS_INVALID_PARAMETER;
  6186. ASSERT( FALSE );
  6187. goto Error;
  6188. }
  6189. switch ( Record->ForestTrustType ) {
  6190. case ForestTrustTopLevelName:
  6191. case ForestTrustTopLevelNameEx:
  6192. Index += LsapUnmarshalString( &Blob[Index], &Record->ForestTrustData.TopLevelName );
  6193. if ( Index > Length ) {
  6194. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6195. Status = STATUS_INVALID_PARAMETER;
  6196. ASSERT( FALSE );
  6197. goto Error;
  6198. }
  6199. break;
  6200. case ForestTrustDomainInfo:
  6201. Index += LsapUnmarshalSid( &Blob[Index], ( PISID * )&Record->ForestTrustData.DomainInfo.Sid );
  6202. if ( Index > Length ) {
  6203. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6204. Status = STATUS_INVALID_PARAMETER;
  6205. ASSERT( FALSE );
  6206. goto Error;
  6207. }
  6208. Index += LsapUnmarshalString( &Blob[Index], &Record->ForestTrustData.DomainInfo.DnsName );
  6209. if ( Index > Length ) {
  6210. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6211. Status = STATUS_INVALID_PARAMETER;
  6212. ASSERT( FALSE );
  6213. goto Error;
  6214. }
  6215. Index += LsapUnmarshalString( &Blob[Index], &Record->ForestTrustData.DomainInfo.NetbiosName );
  6216. if ( Index > Length ) {
  6217. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6218. Status = STATUS_INVALID_PARAMETER;
  6219. ASSERT( FALSE );
  6220. goto Error;
  6221. }
  6222. break;
  6223. default:
  6224. Index += LsapUnmarshalData(
  6225. &Blob[Index],
  6226. &Record->ForestTrustData.Data
  6227. );
  6228. if ( Index > Length ) {
  6229. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6230. Status = STATUS_INVALID_PARAMETER;
  6231. ASSERT( FALSE );
  6232. goto Error;
  6233. }
  6234. break;
  6235. }
  6236. //
  6237. // Cross-check the reported record length
  6238. //
  6239. ASSERT( RecordLength == Index - ( StartingIndex + sizeof( ULONG )));
  6240. }
  6241. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  6242. Status = GetExceptionCode();
  6243. if ( Status == STATUS_ACCESS_VIOLATION ) {
  6244. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  6245. Status = STATUS_INVALID_PARAMETER;
  6246. ASSERT( FALSE ); // this indicates a bug
  6247. }
  6248. goto Error;
  6249. }
  6250. Status = STATUS_SUCCESS;
  6251. Cleanup:
  6252. return Status;
  6253. Error:
  6254. ASSERT( !NT_SUCCESS( Status ));
  6255. if ( ForestTrustInfo != NULL ) {
  6256. ForestTrustInfo->RecordCount = i;
  6257. LsapFreeForestTrustInfo( ForestTrustInfo );
  6258. }
  6259. goto Cleanup;
  6260. }
  6261. ///////////////////////////////////////////////////////////////////////////////
  6262. //
  6263. // Routines for manipulating local forest information
  6264. //
  6265. ///////////////////////////////////////////////////////////////////////////////
  6266. NTSTATUS
  6267. LsapAddTreeTrustInfo(
  6268. IN OUT PNL_FTINFO_CONTEXT Context,
  6269. IN PLSAPR_TREE_TRUST_INFO Tti
  6270. )
  6271. /*++
  6272. Routine Description:
  6273. Adds information about the subtree described by 'Tti' to the given context
  6274. Calls itself recursively for child trees of 'Tti'
  6275. Arguments:
  6276. Context context to add to
  6277. Tti structure describing a domain subtree
  6278. Returns:
  6279. STATUS_SUCCESS
  6280. STATUS_INSUFFICIENT_RESOURCES
  6281. --*/
  6282. {
  6283. NTSTATUS Status;
  6284. ULONG i;
  6285. ASSERT( Context );
  6286. ASSERT( Tti );
  6287. //
  6288. // Add a TLN entry.
  6289. // Subordinate TLN entries are expunged as necessary
  6290. //
  6291. if ( FALSE == NetpAddTlnFtinfoEntry(
  6292. Context,
  6293. &Tti->DnsDomainName )) {
  6294. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapAddTreeTrustInfo (%s:%d)\n", __FILE__, __LINE__ ));
  6295. Status = STATUS_INSUFFICIENT_RESOURCES;
  6296. goto Error;
  6297. }
  6298. //
  6299. // Add a domain entry
  6300. //
  6301. if ( Tti->DomainSid == NULL ) {
  6302. //
  6303. // "Young" X-Ref objects might exist without a SID (because a new
  6304. // child domain X-Ref is created without a SID, a SID is added later.
  6305. // Domain info entries without SIDs are not considered valid, so for
  6306. // the time being, do not insert the domain info entry for this X-Ref.
  6307. // Later, the X-Ref will have the SID added to it, at which point
  6308. // replication will take care of inserting the proper information into
  6309. // the tree.
  6310. //
  6311. LsapDsDebugOut(( DEB_FTINFO, "LsapAddTreeTrustInfo: skipping domain info entry for %wZ\n", &Tti->DnsDomainName, __FILE__, __LINE__ ));
  6312. } else if ( FALSE == NetpAllocFtinfoEntry(
  6313. Context,
  6314. ForestTrustDomainInfo,
  6315. &Tti->DnsDomainName,
  6316. Tti->DomainSid,
  6317. &Tti->FlatName )) {
  6318. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapAddTreeTrustInfo (%s:%d)\n", __FILE__, __LINE__ ));
  6319. Status = STATUS_INSUFFICIENT_RESOURCES;
  6320. goto Error;
  6321. }
  6322. //
  6323. // Call ourselves recursively for every child domain
  6324. //
  6325. for ( i = 0 ; i < Tti->Children ; i++ ) {
  6326. Status = LsapAddTreeTrustInfo(
  6327. Context,
  6328. &Tti->ChildDomains[i]
  6329. );
  6330. if ( !NT_SUCCESS( Status )) {
  6331. LsapDsDebugOut(( DEB_FTINFO, "LsapAddTreeTrustInfo: LslapAddTreeTrustInfo returned 0x%x\n", Status ));
  6332. goto Error;
  6333. }
  6334. }
  6335. Status = STATUS_SUCCESS;
  6336. Cleanup:
  6337. return Status;
  6338. Error:
  6339. ASSERT( !NT_SUCCESS( Status ));
  6340. goto Cleanup;
  6341. }
  6342. NTSTATUS
  6343. LsapGetForestTrustInformation(
  6344. IN BOOLEAN RootOnly,
  6345. OUT PLSA_FOREST_TRUST_INFORMATION *ForestTrustInfo
  6346. )
  6347. /*++
  6348. Routine Description:
  6349. Worker routine to get the ForestTrustInformation array for the local domain.
  6350. Arguments:
  6351. RootOnly - if TRUE, operation is only allowed in the root domain of the forest
  6352. ForestTrustInfo - Returns a pointer to a structure containing a count and an
  6353. array of FTInfo records describing the namespaces claimed by the
  6354. domain specified by TrustedDomainName. The Accepted field and Time
  6355. field of all returned records will be zero. The buffer should be freed
  6356. by calling MIDL_user_free.
  6357. Return Value:
  6358. STATUS_SUCCESS
  6359. STATUS_INSUFFICIENT_RESOURCES out of memory
  6360. STATUS_INVALID_DOMAIN_STATE must be called on a DC in a root domain
  6361. --*/
  6362. {
  6363. NTSTATUS Status;
  6364. ULONG i;
  6365. PLSAP_UPN_SUFFIXES UpnSuffixes = NULL;
  6366. PLSAPR_FOREST_TRUST_INFO Fti = NULL;
  6367. NL_FTINFO_CONTEXT Context;
  6368. //
  6369. // Initialization
  6370. //
  6371. *ForestTrustInfo = NULL;
  6372. NetpInitFtinfoContext( &Context );
  6373. //
  6374. // First get a list of all the domains in the forest.
  6375. //
  6376. Status = LsaIQueryForestTrustInfo(
  6377. LsapPolicyHandle,
  6378. &Fti
  6379. );
  6380. if ( !NT_SUCCESS( Status )) {
  6381. LsapDsDebugOut(( DEB_FTINFO, "LsapGetForestTrustInformation: LsaIQueryForestTrustInfo returned 0x%x\n", Status ));
  6382. goto Error;
  6383. }
  6384. if ( Fti->ParentDomainReference != NULL && RootOnly ) {
  6385. //
  6386. // Operation only allowed on the root domain of the forest
  6387. // If parent domain reference exists, we are not the root domain
  6388. //
  6389. Status = STATUS_INVALID_DOMAIN_STATE;
  6390. goto Error;
  6391. }
  6392. //
  6393. // Add TLN entries and domain info entries from the forest
  6394. //
  6395. Status = LsapAddTreeTrustInfo(
  6396. &Context,
  6397. &Fti->RootTrust
  6398. );
  6399. if ( !NT_SUCCESS( Status )) {
  6400. LsapDsDebugOut(( DEB_FTINFO, "LsapGetForestTrustInformation: LsapAddTreeTrustInfo returned 0x%x\n", Status ));
  6401. goto Error;
  6402. }
  6403. //
  6404. // Get the list of UPN and SPN suffixes
  6405. //
  6406. Status = LsaIQueryUpnSuffixes( &UpnSuffixes );
  6407. if ( !NT_SUCCESS(Status )) {
  6408. LsapDsDebugOut(( DEB_FTINFO, "LsapGetForestTrustInformation: LsaIQueryUpnSuffixes returned 0x%x\n", Status ));
  6409. goto Error;
  6410. }
  6411. //
  6412. // Add each UPN/SPN suffix as a TLN
  6413. //
  6414. for ( i = 0 ; i < UpnSuffixes->SuffixCount ; i++ ) {
  6415. UNICODE_STRING * UpnSuffix = &UpnSuffixes->Suffixes[i];
  6416. BOOLEAN Valid;
  6417. //
  6418. // All sorts of strings can claim to be UPN suffixes.
  6419. // Only allow those that pass our validation checking.
  6420. //
  6421. LsapValidateDnsName( UpnSuffix, &Valid );
  6422. if ( !Valid ) {
  6423. continue;
  6424. }
  6425. if ( !NetpAddTlnFtinfoEntry(
  6426. &Context,
  6427. UpnSuffix )) {
  6428. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapGetForestTrustInformation (%s:%d)\n", __FILE__, __LINE__ ));
  6429. Status = STATUS_INSUFFICIENT_RESOURCES;
  6430. goto Error;
  6431. }
  6432. }
  6433. //
  6434. // Return the collected entries to the caller.
  6435. //
  6436. *ForestTrustInfo = NetpCopyFtinfoContext( &Context );
  6437. if ( *ForestTrustInfo == NULL ) {
  6438. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapGetForestTrustInformation (%s:%d)\n", __FILE__, __LINE__ ));
  6439. Status = STATUS_INSUFFICIENT_RESOURCES;
  6440. goto Error;
  6441. } else if ( !LsapValidateForestTrustInfo( *ForestTrustInfo )) {
  6442. LsapDsDebugOut(( DEB_FTINFO, "LsapGetForestTrustInformation: Generated forest trust information internally inconsistent\n" ));
  6443. Status = STATUS_INTERNAL_DB_ERROR;
  6444. goto Error;
  6445. }
  6446. Cleanup:
  6447. NetpCleanFtinfoContext( &Context );
  6448. LsaIFree_LSAP_UPN_SUFFIXES( UpnSuffixes );
  6449. return Status;
  6450. Error:
  6451. ASSERT( !NT_SUCCESS( Status ));
  6452. goto Cleanup;
  6453. }
  6454. NTSTATUS
  6455. LsaIGetForestTrustInformation(
  6456. OUT PLSA_FOREST_TRUST_INFORMATION *ForestTrustInfo
  6457. )
  6458. /*++
  6459. Routine Description:
  6460. Worker routine to get the ForestTrustInformation array for the local domain.
  6461. Arguments:
  6462. ForestTrustInfo - Returns a pointer to a structure containing a count and an
  6463. array of FTInfo records describing the namespaces claimed by the
  6464. domain specified by TrustedDomainName. The Accepted field and Time
  6465. field of all returned records will be zero. The buffer should be freed
  6466. by calling MIDL_user_free.
  6467. Return Value:
  6468. STATUS_SUCCESS
  6469. STATUS_INSUFFICIENT_RESOURCES out of memory
  6470. STATUS_INVALID_DOMAIN_STATE must be called on a DC in a root domain
  6471. --*/
  6472. {
  6473. return LsapGetForestTrustInformation( TRUE, ForestTrustInfo );
  6474. }
  6475. NTSTATUS
  6476. LsaIUpdateForestTrustInformation(
  6477. IN LSAPR_HANDLE PolicyHandle,
  6478. IN UNICODE_STRING * TrustedDomainName,
  6479. IN PLSA_FOREST_TRUST_INFORMATION NewForestTrustInfo
  6480. )
  6481. /*++
  6482. Routine Description:
  6483. This function write the specified NewForestTrustInfo onto the named TDO.
  6484. The NewForestTrustInfo is merged with the exsiting information using the following algorithm:
  6485. The FTinfo records written are described in the NetpMergeFTinfo routine.
  6486. Arguments:
  6487. PolicyHandle - open policy handle
  6488. TrustedDomainName - Trusted domain that is to be updated. This domain must have the
  6489. TRUST_ATTRIBUTE_FOREST_TRANSITIVE bit set.
  6490. NewForestTrustInfo - Specified the new array of FTinfo records as returned from the
  6491. trusted domain.
  6492. Return Value:
  6493. STATUS_SUCCESS: Success.
  6494. STATUS_INVALID_PARAMETER NewForestTrustInfo passed in is incorrect
  6495. --*/
  6496. {
  6497. NTSTATUS Status;
  6498. PLSA_FOREST_TRUST_INFORMATION OldForestTrustInfo = NULL;
  6499. PLSA_FOREST_TRUST_INFORMATION MergedForestTrustInfo = NULL;
  6500. PLSA_FOREST_TRUST_COLLISION_INFORMATION CollisionInfo = NULL;
  6501. if ( !LsapValidateForestTrustInfo( NewForestTrustInfo )) {
  6502. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsaIUpdateForestTrustInformation (%s:%d)\n", __FILE__, __LINE__ ));
  6503. Status = STATUS_INVALID_PARAMETER;
  6504. goto Error;
  6505. }
  6506. Status = LsarQueryForestTrustInformation(
  6507. PolicyHandle,
  6508. TrustedDomainName,
  6509. ForestTrustRecordTypeLast,
  6510. &OldForestTrustInfo
  6511. );
  6512. if ( Status == STATUS_NOT_FOUND ) {
  6513. //
  6514. // If there's no FTinfo on the TDO,
  6515. // that's OK.
  6516. //
  6517. OldForestTrustInfo = NULL;
  6518. Status = STATUS_SUCCESS;
  6519. } else if ( !NT_SUCCESS( Status )) {
  6520. LsapDsDebugOut(( DEB_FTINFO, "LsaIUpdateForestTrustInformation: %wZ: LsarQueryForestTrustInformation returned 0x%lx\n", TrustedDomainName, Status));
  6521. goto Error;
  6522. }
  6523. //
  6524. // Compute the merged FTINFO
  6525. //
  6526. Status = NetpMergeFtinfo(
  6527. TrustedDomainName,
  6528. NewForestTrustInfo,
  6529. OldForestTrustInfo,
  6530. &MergedForestTrustInfo
  6531. );
  6532. if ( !NT_SUCCESS(Status) ) {
  6533. LsapDsDebugOut(( DEB_FTINFO, "LsaIUpdateForestTrustInformation: %wZ: NetpMergeTrustInformation returned 0x%lx\n", TrustedDomainName, Status));
  6534. goto Error;
  6535. }
  6536. ASSERT( LsapValidateForestTrustInfo( MergedForestTrustInfo ));
  6537. //
  6538. // Write the merge FTINFO back to the LSA
  6539. //
  6540. Status = LsarSetForestTrustInformation(
  6541. PolicyHandle,
  6542. TrustedDomainName,
  6543. ForestTrustRecordTypeLast,
  6544. MergedForestTrustInfo,
  6545. FALSE, // This is not a read-only call - write updated data out
  6546. &CollisionInfo
  6547. );
  6548. if ( !NT_SUCCESS( Status )) {
  6549. LsapDsDebugOut(( DEB_FTINFO, "LsaIUpdateForestTrustInformation: %wZ: LsarSetForestTrustInformation returned 0x%lx\n", TrustedDomainName, Status));
  6550. goto Error;
  6551. }
  6552. Cleanup:
  6553. LsaIFree_LSA_FOREST_TRUST_INFORMATION( &OldForestTrustInfo );
  6554. LsaIFree_LSA_FOREST_TRUST_COLLISION_INFORMATION( &CollisionInfo );
  6555. MIDL_user_free( MergedForestTrustInfo );
  6556. return Status;
  6557. Error:
  6558. ASSERT( !NT_SUCCESS( Status ));
  6559. goto Cleanup;
  6560. }
  6561. NTSTATUS NTAPI
  6562. LsaIForestTrustFindMatch(
  6563. IN LSA_ROUTING_MATCH_TYPE Type,
  6564. IN PVOID Data,
  6565. OUT PLSA_UNICODE_STRING Match
  6566. )
  6567. /*++
  6568. Routine Description:
  6569. Finds match for given data in the cache
  6570. Arguments:
  6571. Type Type of Data parameter
  6572. Data Data to match
  6573. Match Used to return the match, if found.
  6574. Caller must use LsaIFree_LSAPR_UNICODE_STRING_BUFFER
  6575. Returns:
  6576. STATUS_SUCCESS Match was found
  6577. STATUS_NO_MATCH Match was not found
  6578. STATUS_INVALID_DOMAIN_STATE Machine must be a GC or a DC in the root domain
  6579. STATUS_INVALID_PARAMETER Check the inputs
  6580. STATUS_INTERNAL_ERROR Cache is internally inconsistent
  6581. STATUS_INSUFFICIENT_RESOURCES Out of memory
  6582. --*/
  6583. {
  6584. if ( !LsapDbDcInRootDomain()) {
  6585. //
  6586. // Bummer. This domain controller is not part of the root DC.
  6587. // We can only perform matching if this DC is also a GC
  6588. //
  6589. if ( !SamIAmIGC()) {
  6590. return STATUS_INVALID_DOMAIN_STATE;
  6591. }
  6592. }
  6593. return LsapForestTrustFindMatch( Type, Data, FALSE, Match, NULL );
  6594. }
  6595. NTSTATUS
  6596. LsapForestTrustInsertLocalInfo(
  6597. )
  6598. /*++
  6599. Routine Description:
  6600. Inserts information about the local forest into the cache
  6601. Arguments:
  6602. None
  6603. Returns:
  6604. NTSTATUS - Standard Nt Result Code
  6605. --*/
  6606. {
  6607. NTSTATUS Status;
  6608. PLSA_FOREST_TRUST_INFORMATION LocalForestTrustInfo = NULL;
  6609. PPOLICY_DNS_DOMAIN_INFO PolicyDnsDomainInfo = NULL;
  6610. //
  6611. // Insert the data for the local forest into the cache
  6612. //
  6613. Status = LsapGetForestTrustInformation(
  6614. FALSE,
  6615. &LocalForestTrustInfo
  6616. );
  6617. if ( !NT_SUCCESS( Status )) {
  6618. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustInsertLocalInfo: LsapGetForestTrustInformation returned 0x%x\n", Status ));
  6619. goto Error;
  6620. }
  6621. //
  6622. // Need the local domain SID and DNS domain name
  6623. //
  6624. Status = LsapDbQueryInformationPolicy(
  6625. LsapPolicyHandle,
  6626. PolicyDnsDomainInformation,
  6627. ( PLSAPR_POLICY_INFORMATION *)&PolicyDnsDomainInfo
  6628. );
  6629. if ( !NT_SUCCESS( Status )) {
  6630. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustInsertLocalInfo: LsapDbQueryInformationPolicy returned 0x%x\n", Status ));
  6631. goto Error;
  6632. }
  6633. Status = LsapForestTrustCacheInsert(
  6634. &PolicyDnsDomainInfo->DnsDomainName,
  6635. PolicyDnsDomainInfo->Sid,
  6636. LocalForestTrustInfo,
  6637. TRUE
  6638. );
  6639. if ( !NT_SUCCESS( Status )) {
  6640. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustInsertLocalInfo: LsapForestTrustCacheInsert returned 0x%x\n", Status ));
  6641. goto Error;
  6642. }
  6643. LsapForestTrustCacheSetLocalValid();
  6644. Cleanup:
  6645. LsaIFree_LSAPR_POLICY_INFORMATION(
  6646. PolicyDnsDomainInformation,
  6647. ( PLSAPR_POLICY_INFORMATION )PolicyDnsDomainInfo
  6648. );
  6649. MIDL_user_free( LocalForestTrustInfo );
  6650. return Status;
  6651. Error:
  6652. ASSERT( !NT_SUCCESS( Status ));
  6653. goto Cleanup;
  6654. }
  6655. ///////////////////////////////////////////////////////////////////////////////
  6656. //
  6657. // Exported set/query/match routines
  6658. //
  6659. ///////////////////////////////////////////////////////////////////////////////
  6660. BOOLEAN
  6661. LsapHavingForestTrustMakesSense(
  6662. IN ULONG TrustDirection,
  6663. IN ULONG TrustType,
  6664. IN ULONG TrustAttributes
  6665. )
  6666. /*++
  6667. Routine Description:
  6668. Determines whether the TDO is of the kind that may contain
  6669. forest trust information
  6670. Arguments:
  6671. TrustDirection
  6672. TrustType
  6673. TrustAttributes
  6674. Returns:
  6675. TRUE/FALSE
  6676. --*/
  6677. {
  6678. UNREFERENCED_PARAMETER( TrustDirection );
  6679. UNREFERENCED_PARAMETER( TrustType );
  6680. if ( !LsapDbNoMoreWin2KForest()) {
  6681. //
  6682. // If we are not in .NET forest mode, behave as if the forest transitive
  6683. // bit did not exist
  6684. //
  6685. TrustAttributes &= ~TRUST_ATTRIBUTE_FOREST_TRANSITIVE;
  6686. }
  6687. return ( 0 != ( TrustAttributes & TRUST_ATTRIBUTE_FOREST_TRANSITIVE ));
  6688. }
  6689. NTSTATUS
  6690. LsarQueryForestTrustInformation(
  6691. IN LSAPR_HANDLE PolicyHandle,
  6692. IN LSA_UNICODE_STRING * TrustedDomainName,
  6693. IN LSA_FOREST_TRUST_RECORD_TYPE HighestRecordType,
  6694. OUT PLSA_FOREST_TRUST_INFORMATION * ForestTrustInfo
  6695. )
  6696. /*++
  6697. Routine Description
  6698. The LsarQueryForestTrustInformation API returns forest trust information
  6699. for the given trusted domain object.
  6700. Arguments:
  6701. PolicyHandle - An open handle to a Policy object
  6702. TrustedDomainName - Name of the trusted domain object
  6703. HighestRecordType - Highest enum value recognized by the client
  6704. ForestTrustInfo - Used to return forest trust information
  6705. Returns:
  6706. NTSTATUS - Standard Nt Result Code
  6707. STATUS_SUCCESS
  6708. STATUS_INVALID_PARAMETER Parameters were somehow invalid
  6709. Most likely, the TRUST_ATTRIBUTE_FOREST_TRANSITIVE
  6710. trust attribute bit is not set on the TDO
  6711. STATUS_NOT_FOUND Forest trust information does not exist for this TDO
  6712. STATUS_NO_SUCH_DOMAIN The specified TDO does not exist
  6713. STATUS_INSUFFICIENT_RESOURCES Ran out of memory
  6714. STATUS_INVALID_DOMAIN_STATE Operation is only legal on domain controllers in root domain
  6715. --*/
  6716. {
  6717. NTSTATUS Status;
  6718. LSAP_DB_OBJECT_INFORMATION ObjInfo;
  6719. LSAPR_HANDLE TrustedDomainHandle = NULL;
  6720. BOOLEAN CacheLocked = FALSE;
  6721. BOOLEAN ObjectReferenced = FALSE;
  6722. BOOLEAN TrustedDomainListLocked = FALSE;
  6723. LSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY * TrustInfoForName;
  6724. LsarpReturnCheckSetup();
  6725. LsapEnterFunc( "LsarQueryForestTrustInformation" );
  6726. LsapTraceEvent( EVENT_TRACE_TYPE_START, LsaTraceEvent_QueryForestTrustInformation );
  6727. //
  6728. // Validate the input buffer
  6729. //
  6730. if ( ForestTrustInfo == NULL ||
  6731. !LsapValidateLsaUnicodeString( TrustedDomainName )) {
  6732. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsarQueryForestTrustInformation (%s:%d)\n", __FILE__, __LINE__ ));
  6733. Status = STATUS_INVALID_PARAMETER;
  6734. goto Error;
  6735. }
  6736. *ForestTrustInfo = NULL;
  6737. //
  6738. // Under current design, only domains in the root domain of the forest
  6739. // can have forest trust information
  6740. //
  6741. if ( !LsapDbDcInRootDomain()) {
  6742. LsapDsDebugOut(( DEB_FTINFO, "LsarQueryForestTrustInformation: must be a DC in the root domain\n" ));
  6743. Status = STATUS_INVALID_DOMAIN_STATE;
  6744. goto Error;
  6745. }
  6746. //
  6747. // Cross-forest trust will not work until all domain controllerss
  6748. // in the forest have been upgraded to Whistler
  6749. //
  6750. if ( !LsapDbNoMoreWin2KForest()) {
  6751. LsapDsDebugOut(( DEB_FTINFO, "LsarQueryForestTrustInformation: must have an all-Whistler forest\n" ));
  6752. Status = STATUS_INVALID_DOMAIN_STATE;
  6753. goto Error;
  6754. }
  6755. Status = LsapDbReferenceObject(
  6756. PolicyHandle,
  6757. 0,
  6758. PolicyObject,
  6759. TrustedDomainObject,
  6760. LSAP_DB_LOCK |
  6761. LSAP_DB_READ_ONLY_TRANSACTION |
  6762. LSAP_DB_DS_OP_TRANSACTION
  6763. );
  6764. if ( !NT_SUCCESS( Status )) {
  6765. LsapDsDebugOut(( DEB_FTINFO, "LsarQueryForestTrustInformation: LsapDbReferenceObject returned 0x%x\n", Status ));
  6766. goto Error;
  6767. }
  6768. ObjectReferenced = TRUE;
  6769. //
  6770. // Get the right name. Entries in the forest trust cache
  6771. // are located by full name name, NOT flat name
  6772. //
  6773. Status = LsapDbAcquireReadLockTrustedDomainList();
  6774. if ( !NT_SUCCESS( Status )) {
  6775. LsapDsDebugOut(( DEB_FTINFO, "LsarQueryForestTrustInformation: LsapDbAcquireReadLockTrustedDomainList returned 0x%x\n", Status ));
  6776. goto Error;
  6777. }
  6778. TrustedDomainListLocked = TRUE;
  6779. //
  6780. // Get the right name
  6781. //
  6782. Status = LsapDbLookupNameTrustedDomainListEx(
  6783. ( LSAPR_UNICODE_STRING * )TrustedDomainName,
  6784. &TrustInfoForName
  6785. );
  6786. if ( !NT_SUCCESS( Status )) {
  6787. LsapDsDebugOut(( DEB_FTINFO, "LsarQueryForestTrustInformation: No trust entry found for %wZ: 0x%lx\n", ( UNICODE_STRING * )TrustedDomainName, Status ));
  6788. goto Error;
  6789. }
  6790. if ( !LsapHavingForestTrustMakesSense(
  6791. TrustInfoForName->TrustInfoEx.TrustDirection,
  6792. TrustInfoForName->TrustInfoEx.TrustType,
  6793. TrustInfoForName->TrustInfoEx.TrustAttributes )) {
  6794. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsarQueryForestTrustInformation (%s:%d)\n", __FILE__, __LINE__ ));
  6795. Status = STATUS_INVALID_PARAMETER;
  6796. goto Error;
  6797. }
  6798. //
  6799. // Build a temporary handle
  6800. //
  6801. // ISSUE-2000/07/27-markpu
  6802. // do we need to open the object?
  6803. // we don't use the handle for anything
  6804. // except verifying access (TRUSTED_QUERY_AUTH)
  6805. //
  6806. //
  6807. // For purposes of forest trust, entries are identified by full name only
  6808. //
  6809. RtlZeroMemory( &ObjInfo, sizeof( ObjInfo ));
  6810. ObjInfo.ObjectTypeId = TrustedDomainObject;
  6811. ObjInfo.ContainerTypeId = NullObject;
  6812. ObjInfo.Sid = NULL;
  6813. ObjInfo.DesiredObjectAccess = TRUSTED_QUERY_AUTH;
  6814. InitializeObjectAttributes(
  6815. &ObjInfo.ObjectAttributes,
  6816. ( UNICODE_STRING * )&TrustInfoForName->TrustInfoEx.Name,
  6817. 0L,
  6818. PolicyHandle,
  6819. NULL
  6820. );
  6821. //
  6822. // Get a handle to the TDO
  6823. //
  6824. Status = LsapDbOpenObject(
  6825. &ObjInfo,
  6826. TRUSTED_QUERY_AUTH,
  6827. 0,
  6828. &TrustedDomainHandle
  6829. );
  6830. if ( !NT_SUCCESS( Status )) {
  6831. LsapDsDebugOut(( DEB_FTINFO, "LsarQueryForestTrustInformation: LsapDbOpenObject returned 0x%x\n", Status ));
  6832. goto Error;
  6833. }
  6834. Status = LsapForestTrustCacheRetrieve(
  6835. ( UNICODE_STRING * )&TrustInfoForName->TrustInfoEx.Name,
  6836. ForestTrustInfo
  6837. );
  6838. if ( !NT_SUCCESS( Status )) {
  6839. LsapDsDebugOut(( DEB_FTINFO, "LsarQueryForestTrustInformation: LsapForestTrustCacheRetrieve returned 0x%x\n", Status ));
  6840. goto Error;
  6841. }
  6842. ASSERT( LsapValidateForestTrustInfo( *ForestTrustInfo ));
  6843. Cleanup:
  6844. if ( TrustedDomainHandle != NULL ) {
  6845. LsapDbCloseObject(
  6846. &TrustedDomainHandle,
  6847. 0,
  6848. Status
  6849. );
  6850. }
  6851. if ( TrustedDomainListLocked ) {
  6852. LsapDbReleaseLockTrustedDomainList();
  6853. }
  6854. //
  6855. // Dereference the object
  6856. //
  6857. if ( ObjectReferenced ) {
  6858. Status = LsapDbDereferenceObject(
  6859. &PolicyHandle,
  6860. PolicyObject,
  6861. TrustedDomainObject,
  6862. LSAP_DB_LOCK |
  6863. LSAP_DB_READ_ONLY_TRANSACTION |
  6864. LSAP_DB_DS_OP_TRANSACTION,
  6865. (SECURITY_DB_DELTA_TYPE) 0,
  6866. Status
  6867. );
  6868. }
  6869. LsapTraceEvent( EVENT_TRACE_TYPE_END, LsaTraceEvent_QueryForestTrustInformation );
  6870. LsapExitFunc( "LsarQueryForestTrustInformation", Status );
  6871. LsarpReturnPrologue();
  6872. return Status;
  6873. Error:
  6874. ASSERT( !NT_SUCCESS( Status ));
  6875. goto Cleanup;
  6876. }
  6877. NTSTATUS
  6878. LsarSetForestTrustInformation(
  6879. IN LSAPR_HANDLE PolicyHandle,
  6880. IN LSA_UNICODE_STRING * TrustedDomainName,
  6881. IN LSA_FOREST_TRUST_RECORD_TYPE HighestRecordType,
  6882. IN LSA_FOREST_TRUST_INFORMATION * ForestTrustInfo,
  6883. IN BOOLEAN CheckOnly,
  6884. OUT PLSA_FOREST_TRUST_COLLISION_INFORMATION * CollisionInfo
  6885. )
  6886. /*++
  6887. Routine Description
  6888. The LsarSetForestTrustInformation API sets forest trust information
  6889. on the given trusted domain object.
  6890. In case if it fails the operation due to a collision, it will return
  6891. the list of entries that conflicted.
  6892. Arguments:
  6893. PolicyHandle - An open handle to a Policy object
  6894. TrustedDomainName - Name of the trusted domain object
  6895. HighestRecordType - Highest enum value recognized by the client
  6896. ForestTrustInfo - Contains forest trust information to set
  6897. If RecordCount is 0, current forest trust information
  6898. will be deleted
  6899. CheckOnly - if TRUE, perform collision detection only without actually
  6900. committing anything to permanent storage
  6901. CollisionInfo - In case of collision error, used to return collision info
  6902. Returns:
  6903. STATUS_SUCCESS
  6904. STATUS_INVALID_PARAMETER Parameters were somehow invalid
  6905. STATUS_INSUFFICIENT_RESOURCES Ran out of memory
  6906. STATUS_INVALID_DOMAIN_STATE Operation is only legal on domain controllers in root domain
  6907. STATUS_INVALID_DOMAIN_ROLE Operation is only legal on the primary domain controller
  6908. STATUS_INVALID_SERVER_STATE The server is shutting down and can not
  6909. process the request
  6910. STATUS_PARAMETER_QUOTA_EXCEEDED Too many FTInfo entries
  6911. --*/
  6912. {
  6913. NTSTATUS Status;
  6914. LSAP_DB_OBJECT_INFORMATION ObjInfo;
  6915. LSAPR_HANDLE TrustedDomainHandle = NULL;
  6916. BOOLEAN ObjectReferenced = FALSE;
  6917. BOOLEAN TrustedDomainListLocked = FALSE;
  6918. LSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY * TrustInfoForName = NULL;
  6919. LSAP_DB_ATTRIBUTE Attributes[LSAP_DB_ATTRS_INFO_CLASS_DOMAIN];
  6920. LSAP_DB_ATTRIBUTE * NextAttribute;
  6921. ULONG AttributeCount = 0;
  6922. ULONG BlobLength = 0;
  6923. BYTE * BlobData = NULL;
  6924. FTCache::TDO_ENTRY TdoEntryOld = {0};
  6925. FTCache::TDO_ENTRY * TdoEntryNew = NULL;
  6926. FTCache::CONFLICT_PAIR * ConflictPairs = NULL;
  6927. ULONG ConflictPairsTotal = 0;
  6928. DOMAIN_SERVER_ROLE ServerRole;
  6929. LsarpReturnCheckSetup();
  6930. LsapEnterFunc( "LsarSetForestTrustInformation" );
  6931. LsapTraceEvent( EVENT_TRACE_TYPE_START, LsaTraceEvent_SetForestTrustInformation );
  6932. //
  6933. // Top level pointers defer to [ref] and can not be NULL
  6934. //
  6935. ASSERT( ForestTrustInfo != NULL );
  6936. ASSERT( CollisionInfo != NULL );
  6937. //
  6938. // Prevent forest trust blobs over MAX_RECORDS_IN_FOREST_TRUST_INFO
  6939. // records
  6940. //
  6941. if ( ForestTrustInfo->RecordCount > MAX_RECORDS_IN_FOREST_TRUST_INFO ) {
  6942. LsapDsDebugOut(( DEB_FTINFO, "Too many entries in LsarSetForestTrustInformation (%s:%d)\n", __FILE__, __LINE__ ));
  6943. Status = STATUS_PARAMETER_QUOTA_EXCEEDED;
  6944. goto Error;
  6945. }
  6946. //
  6947. // Validate the input data
  6948. //
  6949. if ( !LsapValidateLsaUnicodeString( TrustedDomainName ) ||
  6950. !LsapValidateForestTrustInfo( ForestTrustInfo )) {
  6951. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsarSetForestTrustInformation (%s:%d)\n", __FILE__, __LINE__ ));
  6952. Status = STATUS_INVALID_PARAMETER;
  6953. goto Error;
  6954. }
  6955. *CollisionInfo = NULL;
  6956. //
  6957. // Under current design, only domains in the root domain of the forest
  6958. // can have forest trust information set on them.
  6959. //
  6960. if ( !LsapDbDcInRootDomain()) {
  6961. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: must be a DC in the root domain\n" ));
  6962. Status = STATUS_INVALID_DOMAIN_STATE;
  6963. goto Error;
  6964. }
  6965. //
  6966. // Furthermore, forest trust information can only be set on the primary
  6967. // domain controller
  6968. //
  6969. ASSERT( LsapAccountDomainHandle );
  6970. Status = SamIQueryServerRole(
  6971. LsapAccountDomainHandle,
  6972. &ServerRole
  6973. );
  6974. if ( !NT_SUCCESS(Status)) {
  6975. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: SamIQueryServerRole returned 0x%x\n", Status ));
  6976. goto Error;
  6977. } else if ( ServerRole != DomainServerRolePrimary ) {
  6978. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: must be a PDC in the root domain\n" ));
  6979. Status = STATUS_INVALID_DOMAIN_ROLE;
  6980. goto Error;
  6981. }
  6982. //
  6983. // Cross-forest trust will not work until all domain controllers
  6984. // in the forest have been upgraded to Whistler
  6985. //
  6986. if ( !LsapDbNoMoreWin2KForest()) {
  6987. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: must have an all-Whistler forest\n" ));
  6988. Status = STATUS_INVALID_DOMAIN_STATE;
  6989. goto Error;
  6990. }
  6991. //
  6992. // The client should not understand more than we do:
  6993. // the RPC interface should've stopped them
  6994. //
  6995. ASSERT( HighestRecordType <= ForestTrustRecordTypeLast );
  6996. Status = LsapDbReferenceObject(
  6997. PolicyHandle,
  6998. 0,
  6999. PolicyObject,
  7000. TrustedDomainObject,
  7001. LSAP_DB_LOCK
  7002. );
  7003. if ( !NT_SUCCESS( Status )) {
  7004. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: LsapDbReferenceObject returned 0x%x\n", Status ));
  7005. goto Error;
  7006. }
  7007. ObjectReferenced = TRUE;
  7008. //
  7009. // Lock the Trusted Domain List for the duration of the operation,
  7010. // since we'll be making changes to it here
  7011. //
  7012. Status = LsapDbAcquireWriteLockTrustedDomainList();
  7013. if ( !NT_SUCCESS( Status )) {
  7014. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: LsapDbAcquireWriteLockTrustedDomainList returned 0x%x\n", Status ));
  7015. goto Error;
  7016. }
  7017. TrustedDomainListLocked = TRUE;
  7018. //
  7019. // Get the right name
  7020. //
  7021. Status = LsapDbLookupNameTrustedDomainListEx(
  7022. ( LSAPR_UNICODE_STRING * )TrustedDomainName,
  7023. &TrustInfoForName
  7024. );
  7025. if ( !NT_SUCCESS( Status )) {
  7026. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: No trust entry found for %wZ: 0x%lx\n", ( UNICODE_STRING * )TrustedDomainName, Status ));
  7027. goto Error;
  7028. }
  7029. //
  7030. // Build a temporary handle
  7031. //
  7032. RtlZeroMemory( &ObjInfo, sizeof( ObjInfo ));
  7033. ObjInfo.ObjectTypeId = TrustedDomainObject;
  7034. ObjInfo.ContainerTypeId = NullObject;
  7035. ObjInfo.Sid = NULL;
  7036. ObjInfo.DesiredObjectAccess = TRUSTED_SET_AUTH;
  7037. InitializeObjectAttributes(
  7038. &ObjInfo.ObjectAttributes,
  7039. ( UNICODE_STRING * )&TrustInfoForName->TrustInfoEx.Name,
  7040. 0L,
  7041. PolicyHandle,
  7042. NULL
  7043. );
  7044. //
  7045. // Get a handle to the TDO
  7046. //
  7047. Status = LsapDbOpenObject(
  7048. &ObjInfo,
  7049. TRUSTED_SET_AUTH,
  7050. 0,
  7051. &TrustedDomainHandle
  7052. );
  7053. if ( !NT_SUCCESS( Status )) {
  7054. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: LsapDbOpenObject returned 0x%x\n", Status ));
  7055. goto Error;
  7056. }
  7057. if ( ForestTrustInfo->RecordCount > 0 ) {
  7058. if ( !LsapHavingForestTrustMakesSense(
  7059. TrustInfoForName->TrustInfoEx.TrustDirection,
  7060. TrustInfoForName->TrustInfoEx.TrustType,
  7061. TrustInfoForName->TrustInfoEx.TrustAttributes )) {
  7062. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsarSetForestTrustInformation (%s:%d)\n", __FILE__, __LINE__ ));
  7063. Status = STATUS_INVALID_PARAMETER;
  7064. goto Error;
  7065. }
  7066. //
  7067. // Insert the entry into the cache.
  7068. // This is the first part of the insert operation:
  7069. // -- conflicts are not resolved
  7070. // -- old copy of the data is preserved in case
  7071. // the operation needs to be rolled back later
  7072. //
  7073. Status = g_FTCache->Insert(
  7074. ( UNICODE_STRING * )&TrustInfoForName->TrustInfoEx.Name,
  7075. ( PSID )TrustInfoForName->TrustInfoEx.Sid,
  7076. ForestTrustInfo,
  7077. FALSE,
  7078. &TdoEntryOld,
  7079. &TdoEntryNew,
  7080. &ConflictPairs,
  7081. &ConflictPairsTotal
  7082. );
  7083. if ( !NT_SUCCESS( Status )) {
  7084. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: FTCache::Insert returned 0x%x\n", Status ));
  7085. goto Error;
  7086. }
  7087. ASSERT( TdoEntryNew );
  7088. //
  7089. // The client wants to know what the deal is with conflicts
  7090. //
  7091. if ( ConflictPairs != NULL ) {
  7092. Status = FTCache::GenerateConflictInfo(
  7093. ConflictPairs,
  7094. ConflictPairsTotal,
  7095. TdoEntryNew,
  7096. CollisionInfo
  7097. );
  7098. if ( !NT_SUCCESS( Status )) {
  7099. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: FTCache::GenerateConflictInfo returned 0x%x\n", Status ));
  7100. goto Error;
  7101. }
  7102. }
  7103. //
  7104. // Don't waste cycles marking entries as disabled or
  7105. // marshalling the blob if we are not going to write it
  7106. //
  7107. if ( !CheckOnly ) {
  7108. if ( ConflictPairs != NULL ) {
  7109. FTCache::ReconcileConflictPairs(
  7110. TdoEntryNew,
  7111. ConflictPairs,
  7112. ConflictPairsTotal
  7113. );
  7114. }
  7115. //
  7116. // Marshal the data in preparation for writing it to the DS
  7117. //
  7118. Status = FTCache::MarshalBlob(
  7119. TdoEntryNew,
  7120. &BlobLength,
  7121. &BlobData
  7122. );
  7123. if ( !NT_SUCCESS( Status )) {
  7124. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: FTCache::MarshalBlob returned 0x%x\n", Status ));
  7125. goto Error;
  7126. }
  7127. }
  7128. }
  7129. //
  7130. // if only a collision check was requested, bail here
  7131. //
  7132. if ( CheckOnly ) {
  7133. //
  7134. // Rollback the changes made to the forest trust cache
  7135. //
  7136. if ( TdoEntryNew ) {
  7137. g_FTCache->RollbackChanges( TdoEntryNew, &TdoEntryOld );
  7138. TdoEntryNew = NULL;
  7139. }
  7140. goto Cleanup;
  7141. }
  7142. NextAttribute = Attributes;
  7143. LsapDbInitializeAttributeDs(
  7144. NextAttribute,
  7145. TrDmForT,
  7146. BlobData,
  7147. BlobLength,
  7148. FALSE
  7149. );
  7150. AttributeCount++;
  7151. ASSERT( AttributeCount <= LSAP_DB_ATTRS_INFO_CLASS_DOMAIN );
  7152. //
  7153. // Write the attributes to the DS.
  7154. //
  7155. Status = LsapDbWriteAttributesObject(
  7156. TrustedDomainHandle,
  7157. Attributes,
  7158. AttributeCount
  7159. );
  7160. if ( !NT_SUCCESS( Status )) {
  7161. LsapDsDebugOut(( DEB_FTINFO, "LsarSetForestTrustInformation: LsapDbWriteAttributesObject returned 0x%x\n", Status ));
  7162. goto Error;
  7163. }
  7164. #if DBG
  7165. //
  7166. // In debug builds only, display the array of conflict pairs
  7167. //
  7168. if ( *CollisionInfo != 0 ) {
  7169. LsapDsDebugOut((
  7170. DEB_FTINFO,
  7171. "\n********** Collisions were detected **********\n\n"
  7172. ));
  7173. for ( ULONG Current = 0 ; Current < ( *CollisionInfo )->RecordCount ; Current++ ) {
  7174. LsapDsDebugOut((
  7175. DEB_FTINFO,
  7176. "%d. Index: %d, Type: %s, Flags: %d, Name: %wZ\n",
  7177. Current,
  7178. ( *CollisionInfo )->Entries[Current]->Index,
  7179. ( *CollisionInfo )->Entries[Current]->Type == 0 ? "TDO" : "XRef",
  7180. ( *CollisionInfo )->Entries[Current]->Flags,
  7181. &( *CollisionInfo )->Entries[Current]->Name
  7182. ));
  7183. }
  7184. }
  7185. #endif
  7186. Status = STATUS_SUCCESS;
  7187. Cleanup:
  7188. //
  7189. // DS write was successful - can now complete the cache transaction
  7190. // While at it, if this wasn't a probing (CheckOnly) call, audit the changes
  7191. //
  7192. if ( NT_SUCCESS( Status ) && !CheckOnly) {
  7193. if ( TdoEntryNew != NULL ) {
  7194. ASSERT( ForestTrustInfo->RecordCount > 0 );
  7195. g_FTCache->AuditChanges(
  7196. TdoEntryOld.RecordCount > 0 ?
  7197. &TdoEntryOld : NULL,
  7198. TdoEntryNew
  7199. );
  7200. //
  7201. // Do not audit the collisions -- the collisions here only affect
  7202. // the information passed in by the caller, and the caller is being
  7203. // informed of them.
  7204. //
  7205. } else if ( ForestTrustInfo->RecordCount == 0 ) {
  7206. FTCache::TDO_ENTRY * TdoEntry;
  7207. //
  7208. // ForestTrustInfo->RecordCount == 0 indicates a request for removal
  7209. //
  7210. TdoEntry = ( FTCache::TDO_ENTRY * )RtlLookupElementGenericTableAvl(
  7211. &g_FTCache->m_TdoTable,
  7212. ( UNICODE_STRING * )&TrustInfoForName->TrustInfoEx.Name
  7213. );
  7214. if ( TdoEntry != NULL ) {
  7215. g_FTCache->AuditChanges( TdoEntry, NULL );
  7216. }
  7217. Status = g_FTCache->Remove(( UNICODE_STRING * )&TrustInfoForName->TrustInfoEx.Name );
  7218. if ( Status == STATUS_NOT_FOUND ) {
  7219. //
  7220. // Not sure if this can even happen, but if it's not in the
  7221. // cache, that's what I wanted in the first place
  7222. //
  7223. Status = STATUS_SUCCESS;
  7224. }
  7225. //
  7226. // Only a bug in the code would cause a deletion to fail
  7227. //
  7228. ASSERT( NT_SUCCESS( Status ));
  7229. }
  7230. }
  7231. if ( TrustedDomainHandle != NULL ) {
  7232. LsapDbCloseObject(
  7233. &TrustedDomainHandle,
  7234. 0,
  7235. Status
  7236. );
  7237. }
  7238. FtcFree( BlobData );
  7239. FtcFree( ConflictPairs );
  7240. if ( TdoEntryOld.RecordCount > 0 ) {
  7241. g_FTCache->PurgeTdoEntry( &TdoEntryOld );
  7242. }
  7243. if ( TrustedDomainListLocked ) {
  7244. LsapDbReleaseLockTrustedDomainList();
  7245. }
  7246. if ( ObjectReferenced ) {
  7247. Status = LsapDbDereferenceObject(
  7248. &PolicyHandle,
  7249. PolicyObject,
  7250. TrustedDomainObject,
  7251. LSAP_DB_LOCK |
  7252. LSAP_DB_OMIT_REPLICATOR_NOTIFICATION,
  7253. (SECURITY_DB_DELTA_TYPE) 0,
  7254. Status
  7255. );
  7256. }
  7257. LsapTraceEvent( EVENT_TRACE_TYPE_END, LsaTraceEvent_SetForestTrustInformation );
  7258. LsapExitFunc( "LsarSetForestTrustInformation", Status );
  7259. LsarpReturnPrologue();
  7260. return Status;
  7261. Error:
  7262. ASSERT( !NT_SUCCESS( Status ));
  7263. LsapFreeCollisionInfo( CollisionInfo );
  7264. ASSERT( *CollisionInfo == NULL );
  7265. //
  7266. // Rollback the changes made to the forest trust cache
  7267. //
  7268. if ( TdoEntryNew ) {
  7269. g_FTCache->RollbackChanges( TdoEntryNew, &TdoEntryOld );
  7270. TdoEntryNew = NULL;
  7271. }
  7272. goto Cleanup;
  7273. }
  7274. NTSTATUS
  7275. LsapForestTrustFindMatch(
  7276. IN LSA_ROUTING_MATCH_TYPE Type,
  7277. IN PVOID Data,
  7278. IN BOOLEAN SearchLocal,
  7279. OUT OPTIONAL PLSA_UNICODE_STRING MatchName,
  7280. OUT OPTIONAL PSID * MatchSid
  7281. )
  7282. /*++
  7283. Routine Description:
  7284. Finds match for given data in the cache
  7285. Arguments:
  7286. Type Type of Data parameter
  7287. Data Data to match
  7288. SearchLocal Search local information only,
  7289. when FALSE, local information will be skipped
  7290. MatchName Used to return the match, if found.
  7291. Caller must use LsaIFree_LSAPR_UNICODE_STRING_BUFFER
  7292. MatchSid Used to return the SID of the matching domain, if found
  7293. Caller must use MIDL_user_free
  7294. Returns:
  7295. STATUS_SUCCESS Match was found
  7296. STATUS_NO_MATCH Match was not found
  7297. STATUS_INVALID_PARAMETER Check the inputs
  7298. STATUS_INTERNAL_ERROR Cache is internally inconsistent
  7299. STATUS_INSUFFICIENT_RESOURCES Out of memory
  7300. --*/
  7301. {
  7302. if ( g_FTCache == NULL ) {
  7303. return STATUS_INTERNAL_ERROR;
  7304. }
  7305. return g_FTCache->Match( Type, Data, SearchLocal, ( UNICODE_STRING * )MatchName, MatchSid );
  7306. }
  7307. ///////////////////////////////////////////////////////////////////////////////
  7308. //
  7309. // Code required when running on a GC outside of the root domain
  7310. //
  7311. ///////////////////////////////////////////////////////////////////////////////
  7312. NTSTATUS
  7313. LsapForestTrustCacheInsertEntInf(
  7314. IN ENTINF * EntInf
  7315. )
  7316. /*++
  7317. Routine Description:
  7318. Checks the trusted domain object corresponding to the given EntInf structure
  7319. and. if appropriate, inserts the forest trust data into the forest trust cache
  7320. Arguments:
  7321. EntInf result of a DS search
  7322. Returns:
  7323. STATUS_SUCCESS entry added OK
  7324. STATUS_INTERNAL_ERROR should never see this, really
  7325. STATUS_INSUFFICIENT_RESOURCES out of memory
  7326. STATUS_NOT_FOUND not all required attributes present
  7327. --*/
  7328. {
  7329. NTSTATUS Status;
  7330. UNICODE_STRING TrustedDomainName = {0};
  7331. PSID TrustedDomainSid = NULL;
  7332. ULONG TrustAttributes = 0, TrustDirection = 0, TrustType = 0;
  7333. ULONG ForestTrustLength = 0;
  7334. PBYTE ForestTrustData = NULL;
  7335. LSA_FOREST_TRUST_INFORMATION ForestTrustInfo = {0};
  7336. const USHORT TotalRequiredAttributes = 0x1 | 0x2 | 0x4 | 0x8;
  7337. USHORT FoundRequiredAttributes = 0;
  7338. BOOL IsDeleted = FALSE;
  7339. BOOL ForestTrustDataPresent = FALSE;
  7340. ASSERT( EntInf );
  7341. ASSERT( LsapDbIsLockedTrustedDomainList());
  7342. if ( g_FTCache == NULL ) {
  7343. ASSERT( FALSE );
  7344. return STATUS_INTERNAL_ERROR;
  7345. }
  7346. for ( ULONG i = 0 ; i < EntInf->AttrBlock.attrCount ; i++ ) {
  7347. switch ( EntInf->AttrBlock.pAttr[i].attrTyp ) {
  7348. case ATT_TRUST_PARTNER:
  7349. FoundRequiredAttributes |= 0x1;
  7350. TrustedDomainName.Buffer = LSAP_DS_GET_DS_ATTRIBUTE_AS_PWSTR( &EntInf->AttrBlock.pAttr[i] );
  7351. TrustedDomainName.Length = ( USHORT) LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &EntInf->AttrBlock.pAttr[i] );
  7352. TrustedDomainName.MaximumLength = TrustedDomainName.Length;
  7353. break;
  7354. case ATT_SECURITY_IDENTIFIER: // optional
  7355. TrustedDomainSid = ( PSID )LSAP_DS_GET_DS_ATTRIBUTE_AS_PWSTR( &EntInf->AttrBlock.pAttr[i] );
  7356. break;
  7357. case ATT_TRUST_ATTRIBUTES:
  7358. FoundRequiredAttributes |= 0x2;
  7359. TrustAttributes = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &EntInf->AttrBlock.pAttr[i] );
  7360. break;
  7361. case ATT_TRUST_DIRECTION:
  7362. FoundRequiredAttributes |= 0x4;
  7363. TrustDirection = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &EntInf->AttrBlock.pAttr[i] );
  7364. break;
  7365. case ATT_TRUST_TYPE:
  7366. FoundRequiredAttributes |= 0x8;
  7367. TrustType = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &EntInf->AttrBlock.pAttr[i] );
  7368. break;
  7369. case ATT_MS_DS_TRUST_FOREST_TRUST_INFO: // optional
  7370. ForestTrustLength = ( ULONG )LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &EntInf->AttrBlock.pAttr[i] );
  7371. ForestTrustData = LSAP_DS_GET_DS_ATTRIBUTE_AS_PBYTE( &EntInf->AttrBlock.pAttr[i] );
  7372. ForestTrustDataPresent = ( ForestTrustLength > 0 && ForestTrustData != NULL );
  7373. break;
  7374. case ATT_IS_DELETED: // optional
  7375. IsDeleted = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &EntInf->AttrBlock.pAttr[i] );
  7376. break;
  7377. default:
  7378. LsapDsDebugOut(( DEB_FTINFO, "Invalid parameter in LsapForestTrustUnmarshalBlob (%s:%d)\n", __FILE__, __LINE__ ));
  7379. Status = STATUS_INVALID_PARAMETER;
  7380. ASSERT( FALSE );
  7381. goto Error;
  7382. }
  7383. }
  7384. if ( FoundRequiredAttributes != TotalRequiredAttributes ) {
  7385. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsertEntInf: not all required parameters found 0x%lx (%s:%d)\n", FoundRequiredAttributes, __FILE__, __LINE__ ));
  7386. Status = STATUS_NOT_FOUND;
  7387. goto Error;
  7388. }
  7389. if ( IsDeleted || !ForestTrustDataPresent ) {
  7390. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsertEntInf: removing an entry for %wZ\n", &TrustedDomainName ));
  7391. Status = LsapForestTrustCacheRemove( &TrustedDomainName );
  7392. if ( Status == STATUS_NOT_FOUND ) {
  7393. Status = STATUS_SUCCESS;
  7394. }
  7395. ASSERT( Status == STATUS_SUCCESS );
  7396. } else if ( ForestTrustDataPresent &&
  7397. LsapHavingForestTrustMakesSense(
  7398. TrustDirection,
  7399. TrustType,
  7400. TrustAttributes )) {
  7401. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsertEntInf: adding an entry for %wZ\n", &TrustedDomainName ));
  7402. Status = LsapForestTrustUnmarshalBlob(
  7403. ForestTrustLength,
  7404. ForestTrustData,
  7405. ForestTrustRecordTypeLast,
  7406. &ForestTrustInfo
  7407. );
  7408. if ( !NT_SUCCESS( Status )) {
  7409. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsertEntInf: LsapForestTrustUnmarshalBlob returned 0x%x\n", Status ));
  7410. goto Error;
  7411. }
  7412. Status = LsapForestTrustCacheInsert(
  7413. &TrustedDomainName,
  7414. TrustedDomainSid,
  7415. &ForestTrustInfo,
  7416. FALSE
  7417. );
  7418. LsapFreeForestTrustInfo( &ForestTrustInfo );
  7419. if ( !NT_SUCCESS( Status )) {
  7420. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsertEntInf: LsapForestTrustCacheInsert returned 0x%x\n", Status ));
  7421. goto Error;
  7422. }
  7423. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustCacheInsertEntInf: the entry for %wZ successfully added\n", &TrustedDomainName ));
  7424. }
  7425. Status = STATUS_SUCCESS;
  7426. Cleanup:
  7427. return Status;
  7428. Error:
  7429. ASSERT( !NT_SUCCESS( Status ));
  7430. goto Cleanup;
  7431. }
  7432. BOOL
  7433. LsapNotifyPrepareToImpersonate(
  7434. ULONG Client,
  7435. ULONG Server,
  7436. VOID **ImpersonateData
  7437. )
  7438. /*++
  7439. Routine Description:
  7440. Called before DS notification fires.
  7441. Arguments:
  7442. Client, Server, ImpersonateData -- forwarded to DirPrepareForImpersonate
  7443. Returns:
  7444. TRUE if everything went fine,
  7445. FALSE if ran out of memory allocating resources
  7446. --*/
  7447. {
  7448. return DirPrepareForImpersonate(
  7449. Client,
  7450. Server,
  7451. ImpersonateData
  7452. );
  7453. }
  7454. VOID
  7455. LsapForestTrustTransmitDataXrefChange(
  7456. ULONG hClient,
  7457. ULONG hServer,
  7458. ENTINF *EntInf
  7459. )
  7460. /*++
  7461. Routine Description:
  7462. Notification callback for changes to trusted domain objects
  7463. Arguments:
  7464. hClient ignored
  7465. hServer ignored
  7466. EntInf <fill in>
  7467. Returns:
  7468. Nothing
  7469. --*/
  7470. {
  7471. NTSTATUS Status;
  7472. UNREFERENCED_PARAMETER( hClient );
  7473. UNREFERENCED_PARAMETER( hServer );
  7474. LsapDbAcquireWriteLockTrustedDomainList();
  7475. if ( g_FTCache == NULL ) {
  7476. ASSERT( FALSE ); // how is this possible???
  7477. LsapDbReleaseLockTrustedDomainList();
  7478. return;
  7479. }
  7480. Status = LsapForestTrustCacheInsertEntInf( EntInf );
  7481. if ( Status == STATUS_NOT_FOUND ) {
  7482. Status = STATUS_SUCCESS;
  7483. } else if ( !NT_SUCCESS( Status )) {
  7484. LsapDsDebugOut(( DEB_FTINFO, "LsapForestTrustOnGcTransmitData: LsapForestTrustCacheInsertEntInf returned 0x%x\n", Status ));
  7485. LsapForestTrustCacheSetInvalid();
  7486. }
  7487. LsapDbReleaseLockTrustedDomainList();
  7488. return;
  7489. }
  7490. VOID
  7491. LsapForestTrustTransmitDataUpnSuffixChange(
  7492. ULONG hClient,
  7493. ULONG hServer,
  7494. ENTINF *EntInf
  7495. )
  7496. /*++
  7497. Routine Description:
  7498. Notification callback for changes to trusted domain objects
  7499. Arguments:
  7500. hClient ignored
  7501. hServer ignored
  7502. EntInf <fill in>
  7503. Returns:
  7504. Nothing
  7505. --*/
  7506. {
  7507. NTSTATUS Status;
  7508. UNREFERENCED_PARAMETER( hClient );
  7509. UNREFERENCED_PARAMETER( hServer );
  7510. UNREFERENCED_PARAMETER( EntInf );
  7511. LsapDbAcquireWriteLockTrustedDomainList();
  7512. if ( g_FTCache == NULL ) {
  7513. ASSERT( FALSE ); // how is this possible???
  7514. LsapDbReleaseLockTrustedDomainList();
  7515. return;
  7516. } else if ( !g_FTCache->IsLocalValid()) {
  7517. LsapDbReleaseLockTrustedDomainList();
  7518. return;
  7519. }
  7520. Status = LsapForestTrustInsertLocalInfo();
  7521. if ( !NT_SUCCESS( Status )) {
  7522. //
  7523. // Had trouble inserting forest trust info into the cache!!!
  7524. // Mark the trusted domain list as invalid so it can get rebuilt.
  7525. //
  7526. LsapDbPurgeTrustedDomainCache();
  7527. }
  7528. LsapDbReleaseLockTrustedDomainList();
  7529. return;
  7530. }
  7531. VOID
  7532. LsapNotifyStopImpersonating(
  7533. ULONG Client,
  7534. ULONG Server,
  7535. VOID *ImpersonateData
  7536. )
  7537. /*++
  7538. Routine Description:
  7539. Called after DS notification fires.
  7540. Arguments:
  7541. Client, Server, ImpersonateData - forwarded to DirStopImpersonating
  7542. Returns:
  7543. Nothing
  7544. --*/
  7545. {
  7546. DirStopImpersonating(
  7547. Client,
  7548. Server,
  7549. ImpersonateData
  7550. );
  7551. }
  7552. NTSTATUS
  7553. LsapRebuildFtCacheGC()
  7554. /*++
  7555. Routine Description:
  7556. Rebuilds the forest trust cache on a global catalog server
  7557. which is outside the root domain of the forest
  7558. Arguments:
  7559. None
  7560. Returns:
  7561. STATUS_SUCCESS OK
  7562. STATUS_INTERNAL_ERROR no forest trust cache object
  7563. STATUS_INVALID_DOMAIN_STATE must be a GC outside of the root domain
  7564. STATUS_INSUFFICIENT_RESOURCES out of memory
  7565. --*/
  7566. {
  7567. NTSTATUS Status;
  7568. ULONG DirResult;
  7569. ULONG NameLen, RootLen, SystemLen;
  7570. PDSNAME RootName = NULL, SystemName = NULL;
  7571. FILTER Filter = {0};
  7572. ENTINFSEL Selection = {0};
  7573. SEARCHARG SearchArg = {0};
  7574. NOTIFYARG NotifyArg = {0};
  7575. NOTIFYRES * NotifyRes = NULL;
  7576. SEARCHRES * SearchRes = NULL;
  7577. BOOLEAN CloseTransaction = FALSE;
  7578. //
  7579. // List of attributes we care about for forest trust.
  7580. // If you change this list, change the switch statement
  7581. // inside LsapForestTrustCacheInsertEntInf.
  7582. //
  7583. ATTR AttrArray[] = {
  7584. { ATT_TRUST_PARTNER, { 0, NULL }},
  7585. { ATT_SECURITY_IDENTIFIER, { 0, NULL }},
  7586. { ATT_TRUST_ATTRIBUTES, { 0, NULL }},
  7587. { ATT_TRUST_DIRECTION, { 0, NULL }},
  7588. { ATT_TRUST_TYPE, { 0, NULL }},
  7589. { ATT_MS_DS_TRUST_FOREST_TRUST_INFO, { 0, NULL }},
  7590. { ATT_IS_DELETED, { 0, NULL }}};
  7591. LsapDsDebugOut(( DEB_FTINFO, "Rebuilding forest trust cache on the GC (%s:%d)\n", __FILE__, __LINE__ ));
  7592. LsapDbAcquireWriteLockTrustedDomainList();
  7593. if ( g_FTCache == NULL ) {
  7594. ASSERT( FALSE ); // how is this possible???
  7595. Status = STATUS_INTERNAL_ERROR;
  7596. LsapDbReleaseLockTrustedDomainList();
  7597. LsapDsDebugOut(( DEB_FTINFO, "LsapRebuildFtCacheGC: Error 0x%lx (%s:%d)\n", Status, __FILE__, __LINE__ ));
  7598. return Status;
  7599. }
  7600. if ( LsapDbDcInRootDomain() || !SamIAmIGC()) {
  7601. LsapDbReleaseLockTrustedDomainList();
  7602. LsapDsDebugOut(( DEB_FTINFO, "LsapRebuildFtCacheGC: Must be called on a GC outside of root domain\n" ));
  7603. Status = STATUS_INVALID_DOMAIN_STATE;
  7604. return Status;
  7605. }
  7606. if ( g_FTCache->IsExternalValid()) {
  7607. LsapDbReleaseLockTrustedDomainList();
  7608. LsapDsDebugOut(( DEB_FTINFO, "LsapRebuildFtCacheGC: No need to rebuild, returning OK (%s:%d)\n", __FILE__, __LINE__ ));
  7609. return STATUS_SUCCESS;
  7610. }
  7611. //
  7612. // See if we already have a transaction going and open one if necessary
  7613. //
  7614. Status = LsapDsInitAllocAsNeededEx(
  7615. LSAP_DB_READ_ONLY_TRANSACTION |
  7616. LSAP_DB_DS_OP_TRANSACTION,
  7617. NullObject,
  7618. &CloseTransaction
  7619. );
  7620. if ( !NT_SUCCESS( Status )) {
  7621. LsapDbReleaseLockTrustedDomainList();
  7622. LsapDsDebugOut(( DEB_FTINFO, "LsapRebuildFtCacheGC: LsapDsOpenTransaction returned 0x%x\n", Status ));
  7623. return Status;
  7624. }
  7625. //
  7626. // Find the name of the root NC
  7627. //
  7628. RootLen = 0;
  7629. Status = GetConfigurationName(
  7630. DSCONFIGNAME_ROOT_DOMAIN,
  7631. &RootLen,
  7632. NULL
  7633. );
  7634. ASSERT( Status == STATUS_BUFFER_TOO_SMALL );
  7635. RootName = ( PDSNAME )LsapAllocateLsaHeap( RootLen );
  7636. if ( RootName == NULL ) {
  7637. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapRebuildFtCacheGC (%s:%d)\n", __FILE__, __LINE__ ));
  7638. Status = STATUS_INSUFFICIENT_RESOURCES;
  7639. goto Error;
  7640. }
  7641. Status = GetConfigurationName(
  7642. DSCONFIGNAME_ROOT_DOMAIN,
  7643. &RootLen,
  7644. RootName
  7645. );
  7646. if ( !NT_SUCCESS( Status )) {
  7647. LsapDsDebugOut(( DEB_FTINFO, "LsapRebuildFtCacheGC: GetConfigurationName returned 0x%x\n", Status ));
  7648. goto Error;
  7649. }
  7650. //
  7651. // Construct the SYSTEM container name
  7652. //
  7653. NameLen = 10 + // wcslen( L"CN=System," )
  7654. wcslen( RootName->StringName );
  7655. SystemLen = DSNameSizeFromLen( NameLen );
  7656. SystemName = ( PDSNAME )LsapAllocateLsaHeap( SystemLen );
  7657. if ( SystemName == NULL ) {
  7658. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapRebuildFtCacheGC (%s:%d)\n", __FILE__, __LINE__ ));
  7659. Status = STATUS_INSUFFICIENT_RESOURCES;
  7660. goto Error;
  7661. }
  7662. SystemName->structLen = SystemLen;
  7663. SystemName->NameLen = NameLen;
  7664. swprintf(
  7665. SystemName->StringName,
  7666. L"CN=System,%ws",
  7667. RootName->StringName
  7668. );
  7669. //
  7670. // Register for notifications on the system container
  7671. // Sadly, filters can not be applied to notifications
  7672. //
  7673. Filter.choice = FILTER_CHOICE_ITEM;
  7674. Filter.FilterTypes.Item.choice = FI_CHOICE_TRUE;
  7675. Selection.attSel = EN_ATTSET_LIST;
  7676. Selection.AttrTypBlock.attrCount = sizeof( AttrArray ) / sizeof( AttrArray[0] );
  7677. Selection.AttrTypBlock.pAttr = AttrArray;
  7678. Selection.infoTypes = EN_INFOTYPES_TYPES_VALS;
  7679. SearchArg.pObject = SystemName;
  7680. SearchArg.choice = SE_CHOICE_IMMED_CHLDRN;
  7681. SearchArg.bOneNC = TRUE;
  7682. SearchArg.pFilter = &Filter;
  7683. SearchArg.searchAliases = FALSE;
  7684. SearchArg.pSelection = &Selection;
  7685. SearchArg.pSelectionRange = NULL;
  7686. SearchArg.fPutResultsInSortedTable = FALSE;
  7687. InitCommarg( &SearchArg.CommArg );
  7688. SearchArg.pResObj = NULL;
  7689. NotifyArg.pfPrepareForImpersonate = LsapNotifyPrepareToImpersonate;
  7690. NotifyArg.pfTransmitData = LsapForestTrustTransmitDataXrefChange;
  7691. NotifyArg.pfStopImpersonating = LsapNotifyStopImpersonating;
  7692. NotifyArg.hClient = 0;
  7693. DirResult = DirNotifyRegister(
  7694. &SearchArg,
  7695. &NotifyArg,
  7696. &NotifyRes
  7697. );
  7698. if ( NotifyRes ) {
  7699. Status = LsapDsMapDsReturnToStatusEx( &( NotifyRes->CommRes ));
  7700. } else {
  7701. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapRebuildFtCacheGC (%s:%d)\n", __FILE__, __LINE__ ));
  7702. Status = STATUS_INSUFFICIENT_RESOURCES;
  7703. }
  7704. if ( !NT_SUCCESS( Status )) {
  7705. LsapDsDebugOut(( DEB_FTINFO, "LsapRebuildFtCacheGC: DirNotifyRegister returned 0x%x\n", Status ));
  7706. goto Error;
  7707. }
  7708. //
  7709. // Continue the transaction
  7710. //
  7711. LsapDsContinueTransaction();
  7712. //
  7713. // Remember the notification handle
  7714. //
  7715. ASSERT( XrefNotificationHandle == NULL );
  7716. XrefNotificationHandle = NotifyRes->hServer;
  7717. //
  7718. // One schema per forest means that the name of the TDO object category
  7719. // will be the same as in the root NC, so it's safe to use LsaDsStateInfo.
  7720. //
  7721. ASSERT( NULL != LsaDsStateInfo.SystemContainerItems.TrustedDomainObject );
  7722. //
  7723. // Unlike notifications, searches support filters. So use them.
  7724. //
  7725. RtlZeroMemory( &Filter, sizeof( Filter ));
  7726. Filter.choice = FILTER_CHOICE_ITEM;
  7727. Filter.FilterTypes.Item.choice = FI_CHOICE_EQUALITY;
  7728. Filter.FilterTypes.Item.FilTypes.ava.type = ATT_OBJECT_CATEGORY;
  7729. Filter.FilterTypes.Item.FilTypes.ava.Value.valLen = LsaDsStateInfo.SystemContainerItems.TrustedDomainObject->structLen;
  7730. Filter.FilterTypes.Item.FilTypes.ava.Value.pVal = ( BYTE * ) LsaDsStateInfo.SystemContainerItems.TrustedDomainObject;
  7731. RtlZeroMemory( &Selection, sizeof( Selection ));
  7732. Selection.attSel = EN_ATTSET_LIST;
  7733. Selection.AttrTypBlock.attrCount = sizeof( AttrArray ) / sizeof( AttrArray[0] );
  7734. Selection.AttrTypBlock.pAttr = AttrArray;
  7735. Selection.infoTypes = EN_INFOTYPES_TYPES_VALS;
  7736. RtlZeroMemory( &SearchArg, sizeof( SearchArg ));
  7737. SearchArg.pObject = SystemName;
  7738. SearchArg.choice = SE_CHOICE_IMMED_CHLDRN;
  7739. SearchArg.bOneNC = TRUE;
  7740. SearchArg.pFilter = &Filter;
  7741. SearchArg.searchAliases = FALSE;
  7742. SearchArg.pSelection = &Selection;
  7743. SearchArg.pSelectionRange = NULL;
  7744. SearchArg.fPutResultsInSortedTable = FALSE;
  7745. InitCommarg( &SearchArg.CommArg );
  7746. SearchArg.pResObj = NULL;
  7747. //
  7748. // Now that we're registered for notifications,
  7749. // read out the trusted domain objects
  7750. //
  7751. DirResult = DirSearch(
  7752. &SearchArg,
  7753. &SearchRes
  7754. );
  7755. if ( SearchRes ) {
  7756. Status = LsapDsMapDsReturnToStatusEx( &( SearchRes->CommRes ));
  7757. } else {
  7758. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapRebuildFtCacheGC (%s:%d)\n", __FILE__, __LINE__ ));
  7759. Status = STATUS_INSUFFICIENT_RESOURCES;
  7760. }
  7761. if ( !NT_SUCCESS( Status )) {
  7762. LsapDsDebugOut(( DEB_FTINFO, "LsapRebuildFtCacheGC: DirSearch returned 0x%x\n", Status ));
  7763. goto Error;
  7764. }
  7765. //
  7766. // Voila! All that's left is to take those search results
  7767. // and populate our cache with them
  7768. //
  7769. if ( SearchRes->count > 0 ) {
  7770. for ( ENTINFLIST * Current = &( SearchRes->FirstEntInf );
  7771. Current != NULL;
  7772. Current = Current->pNextEntInf ) {
  7773. Status = LsapForestTrustCacheInsertEntInf( &Current->Entinf );
  7774. if ( Status == STATUS_NOT_FOUND ) {
  7775. Status = STATUS_SUCCESS;
  7776. } else if ( !NT_SUCCESS( Status )) {
  7777. LsapDsDebugOut(( DEB_FTINFO, "LsapRebuildFtCacheGC: LsapForestTrustCacheInsertEntInf returned 0x%x\n", Status ));
  7778. goto Error;
  7779. }
  7780. }
  7781. }
  7782. //
  7783. // Cache has been successfully rebuilt
  7784. //
  7785. LsapForestTrustCacheSetExternalValid();
  7786. Status = STATUS_SUCCESS;
  7787. LsapDsDebugOut(( DEB_FTINFO, "LsapRebuildFtCacheGC: Cache rebuilt OK (%s:%d)\n", __FILE__, __LINE__ ));
  7788. Cleanup:
  7789. LsapDsDeleteAllocAsNeededEx(
  7790. LSAP_DB_READ_ONLY_TRANSACTION |
  7791. LSAP_DB_DS_OP_TRANSACTION,
  7792. NullObject,
  7793. CloseTransaction
  7794. );
  7795. LsapDbReleaseLockTrustedDomainList();
  7796. LsapFreeLsaHeap( RootName );
  7797. LsapFreeLsaHeap( SystemName );
  7798. return Status;
  7799. Error:
  7800. ASSERT( !NT_SUCCESS( Status ));
  7801. //
  7802. // Undo everything we've accomplished,
  7803. // unregister notifications, etc.
  7804. //
  7805. LsapForestTrustCacheSetInvalid();
  7806. goto Cleanup;
  7807. }
  7808. NTSTATUS
  7809. LsapRegisterForUpnListNotifications()
  7810. /*++
  7811. Routine Description:
  7812. Registers for notifications on the Partitions container to learn of changes
  7813. to the UpnSuffixes attribute.
  7814. Arguments:
  7815. None
  7816. Returns:
  7817. STATUS_SUCCESS OK
  7818. STATUS_INSUFFICIENT_RESOURCES out of memory
  7819. --*/
  7820. {
  7821. NTSTATUS Status;
  7822. ULONG DirResult;
  7823. ULONG PartitionsLen;
  7824. PDSNAME PartitionsName = NULL;
  7825. FILTER Filter = {0};
  7826. ENTINFSEL Selection = {0};
  7827. SEARCHARG SearchArg = {0};
  7828. NOTIFYARG NotifyArg = {0};
  7829. NOTIFYRES * NotifyRes = NULL;
  7830. ATTR AttrArray[] = {{ ATT_UPN_SUFFIXES, { 0, NULL }}};
  7831. BOOLEAN CloseTransaction;
  7832. LsapDsDebugOut(( DEB_FTINFO, "Registering for notificaitons on the UPN list\n" ));
  7833. //
  7834. // See if we already have a transaction going and open one if necessary
  7835. //
  7836. Status = LsapDsInitAllocAsNeededEx(
  7837. LSAP_DB_READ_ONLY_TRANSACTION |
  7838. LSAP_DB_DS_OP_TRANSACTION,
  7839. NullObject,
  7840. &CloseTransaction
  7841. );
  7842. if ( !NT_SUCCESS( Status )) {
  7843. LsapDsDebugOut(( DEB_FTINFO, "LsapRegisterForUpnListNotifications: LsapDsOpenTransaction returned 0x%x\n", Status ));
  7844. return Status;
  7845. }
  7846. //
  7847. // Find the name of the root NC
  7848. //
  7849. PartitionsLen = 0;
  7850. Status = GetConfigurationName(
  7851. DSCONFIGNAME_PARTITIONS,
  7852. &PartitionsLen,
  7853. NULL
  7854. );
  7855. ASSERT( Status == STATUS_BUFFER_TOO_SMALL );
  7856. PartitionsName = ( PDSNAME )LsapAllocateLsaHeap( PartitionsLen );
  7857. if ( PartitionsName == NULL ) {
  7858. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapRegisterForUpnListNotifications (%s:%d)\n", __FILE__, __LINE__ ));
  7859. Status = STATUS_INSUFFICIENT_RESOURCES;
  7860. goto Error;
  7861. }
  7862. Status = GetConfigurationName(
  7863. DSCONFIGNAME_PARTITIONS,
  7864. &PartitionsLen,
  7865. PartitionsName
  7866. );
  7867. if ( !NT_SUCCESS( Status )) {
  7868. LsapDsDebugOut(( DEB_FTINFO, "LsapRegisterForUpnListNotifications: GetConfigurationName returned 0x%x\n", Status ));
  7869. goto Error;
  7870. }
  7871. //
  7872. // Register for notifications on the partitions container
  7873. // Sadly, filters can not be applied to notifications
  7874. //
  7875. Filter.choice = FILTER_CHOICE_ITEM;
  7876. Filter.FilterTypes.Item.choice = FI_CHOICE_TRUE;
  7877. Selection.attSel = EN_ATTSET_LIST;
  7878. Selection.AttrTypBlock.attrCount = sizeof( AttrArray ) / sizeof( AttrArray[0] );
  7879. Selection.AttrTypBlock.pAttr = AttrArray;
  7880. Selection.infoTypes = EN_INFOTYPES_TYPES_ONLY;
  7881. SearchArg.pObject = PartitionsName;
  7882. SearchArg.choice = SE_CHOICE_BASE_ONLY;
  7883. SearchArg.bOneNC = TRUE;
  7884. SearchArg.pFilter = &Filter;
  7885. SearchArg.searchAliases = FALSE;
  7886. SearchArg.pSelection = &Selection;
  7887. SearchArg.pSelectionRange = NULL;
  7888. SearchArg.fPutResultsInSortedTable = FALSE;
  7889. InitCommarg( &SearchArg.CommArg );
  7890. SearchArg.pResObj = NULL;
  7891. NotifyArg.pfPrepareForImpersonate = LsapNotifyPrepareToImpersonate;
  7892. NotifyArg.pfTransmitData = LsapForestTrustTransmitDataUpnSuffixChange;
  7893. NotifyArg.pfStopImpersonating = LsapNotifyStopImpersonating;
  7894. NotifyArg.hClient = 0;
  7895. DirResult = DirNotifyRegister(
  7896. &SearchArg,
  7897. &NotifyArg,
  7898. &NotifyRes
  7899. );
  7900. if ( NotifyRes ) {
  7901. Status = LsapDsMapDsReturnToStatusEx( &( NotifyRes->CommRes ));
  7902. } else {
  7903. LsapDsDebugOut(( DEB_FTINFO, "Out of memory in LsapRegisterForUpnListNotifications (%s:%d)\n", __FILE__, __LINE__ ));
  7904. Status = STATUS_INSUFFICIENT_RESOURCES;
  7905. }
  7906. if ( !NT_SUCCESS( Status )) {
  7907. LsapDsDebugOut(( DEB_FTINFO, "LsapRegisterForUpnListNotifications: DirNotifyRegister returned 0x%x\n", Status ));
  7908. goto Error;
  7909. }
  7910. //
  7911. // Remember the notification handle
  7912. //
  7913. ASSERT( UpnSuffixNotificationHandle == NULL );
  7914. UpnSuffixNotificationHandle = NotifyRes->hServer;
  7915. Status = STATUS_SUCCESS;
  7916. LsapDsDebugOut(( DEB_FTINFO, "LsapRegisterForUpnListNotifications: UPN notifications registered OK\n" ));
  7917. Cleanup:
  7918. LsapDsDeleteAllocAsNeededEx(
  7919. LSAP_DB_READ_ONLY_TRANSACTION |
  7920. LSAP_DB_DS_OP_TRANSACTION,
  7921. NullObject,
  7922. CloseTransaction
  7923. );
  7924. LsapFreeLsaHeap( PartitionsName );
  7925. return Status;
  7926. Error:
  7927. ASSERT( !NT_SUCCESS( Status ));
  7928. ASSERT( UpnSuffixNotificationHandle == NULL );
  7929. goto Cleanup;
  7930. }
  7931. void
  7932. LsaINotifyGCStatusChange(
  7933. IN BOOLEAN PromotingToGC
  7934. )
  7935. /*++
  7936. Routine Description:
  7937. Gets called whenever the GC state of the machine changes.
  7938. Currently the only use of this information is to figure out that
  7939. this is a DC outside of the root domain and no longer a GC
  7940. and throw away the forest trust cache information
  7941. Arguments:
  7942. PromotingToGC - flag to decide whether promoting to GC or
  7943. demoting from GC
  7944. Returns:
  7945. Nothing
  7946. --*/
  7947. {
  7948. if ( !LsapDbDcInRootDomain() && !PromotingToGC ) {
  7949. LsapDbAcquireReadLockTrustedDomainList();
  7950. if ( LsapForestTrustCacheIsExternalValid()) {
  7951. //
  7952. // This machine is no longer a GC -- throw away the cache
  7953. //
  7954. LsapDbConvertReadLockTrustedDomainListToExclusive();
  7955. LsapForestTrustCacheSetInvalid();
  7956. }
  7957. LsapDbReleaseLockTrustedDomainList();
  7958. }
  7959. }