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.

2727 lines
78 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. dsfixup.c
  5. Abstract:
  6. Implementation of a variety of fixup routines for the Lsa/Ds interaction.
  7. Author:
  8. Mac McLain (MacM) Jan 17, 1997
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include <lsapch2.h>
  14. #include <dbp.h>
  15. #include <lmcons.h>
  16. #include <lmaccess.h>
  17. #include <alloca.h>
  18. //
  19. // List entry that maintains information on notifications
  20. //
  21. typedef struct _LSAP_DSFU_NOTIFICATION_NODE {
  22. LIST_ENTRY List ;
  23. LUID AuthenticationId;
  24. PSID UserSid;
  25. PDSNAME ObjectPath;
  26. ULONG Class;
  27. SECURITY_DB_DELTA_TYPE DeltaType;
  28. ULONG OldTrustDirection;
  29. ULONG OldTrustType;
  30. BOOLEAN ReplicatedInChange;
  31. BOOLEAN ChangeOriginatedInLSA;
  32. } LSAP_DSFU_NOTIFICATION_NODE, *PLSAP_DSFU_NOTIFICATION_NODE;
  33. LIST_ENTRY LsapFixupList ;
  34. SAFE_CRITICAL_SECTION LsapFixupLock ;
  35. BOOLEAN LsapFixupThreadActive ;
  36. //
  37. // Packages that need to be called when trust changes. Right now, it's only Kerberos. If
  38. // that changes, this will have to be changed into a list and processed.
  39. //
  40. pfLsaTrustChangeNotificationCallback LsapKerberosTrustNotificationFunction = NULL;
  41. //
  42. // Local prototypes
  43. //
  44. #define LSAP_DS_FULL_FIXUP TRUE
  45. #define LSAP_DS_NOTIFY_FIXUP FALSE
  46. NTSTATUS
  47. LsapDsFixupTrustedDomainObject(
  48. IN PDSNAME TrustObject,
  49. IN BOOLEAN Startup,
  50. IN ULONG SamCount,
  51. IN PSAMPR_RID_ENUMERATION SamAccountList
  52. );
  53. NTSTATUS
  54. LsapDsTrustRenameObject(
  55. IN PDSNAME TrustObject,
  56. IN PUNICODE_STRING NewDns,
  57. OUT PDSNAME *NewObjectName
  58. );
  59. DWORD
  60. WINAPI LsapDsFixupCallback(
  61. LPVOID ParameterBlock
  62. );
  63. VOID
  64. LsapFreeNotificationNode(
  65. IN PLSAP_DSFU_NOTIFICATION_NODE NotificationNode
  66. );
  67. NTSTATUS
  68. LsapDsFixupTrustByInfo(
  69. IN PDSNAME ObjectPath,
  70. IN PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX2 TrustInfo2,
  71. IN ULONG PosixOffset,
  72. IN SECURITY_DB_DELTA_TYPE DeltaType,
  73. IN PSID UserSid,
  74. IN LUID AuthenticationId,
  75. IN BOOLEAN ReplicatedInChange,
  76. IN BOOLEAN ChangeOriginatedInLSA
  77. );
  78. NTSTATUS
  79. LsapDsTrustFixInterdomainTrustAccount(
  80. IN PDSNAME ObjectPath,
  81. IN SECURITY_DB_DELTA_TYPE DeltaType,
  82. IN ULONG Options,
  83. IN PSID UserSid,
  84. IN LUID AuthenticationId
  85. );
  86. BOOL
  87. LsapDsQueueFixupRequest(
  88. PLSAP_DSFU_NOTIFICATION_NODE Node
  89. );
  90. NTSTATUS
  91. LsapDsFixupTrustForXrefChange(
  92. IN PDSNAME ObjectPath,
  93. IN BOOLEAN TransactionActive
  94. );
  95. NTSTATUS
  96. LsapDsFixupTrustedDomainOnRestartCallback(IN PVOID Parameter)
  97. {
  98. return(LsapDsFixupTrustedDomainObjectOnRestart());
  99. }
  100. NTSTATUS
  101. LsapDsFixupTrustedDomainObjectOnRestart(
  102. VOID
  103. )
  104. /*++
  105. Routine Description:
  106. This routine will go through and ensure that all of the trusted domain objects
  107. are up to date. This includes:
  108. Ensuring that the parent x-ref pointer is set
  109. There is not new authentication information on the object
  110. That the domain name has not changed
  111. That a domain x-ref object doesn't exist for a downlevel domain.
  112. If one does, the domain will be updated to an uplevel domain.
  113. Arguments:
  114. VOID
  115. Return Values:
  116. STATUS_SUCCESS -- Success
  117. --*/
  118. {
  119. NTSTATUS Status = STATUS_SUCCESS;
  120. PDSNAME *DsNames = NULL;
  121. ULONG Items=0, i;
  122. BOOLEAN CloseTransaction = FALSE;
  123. SAM_ENUMERATE_HANDLE SamEnum = 0;
  124. PSAMPR_ENUMERATION_BUFFER RidEnum = NULL;
  125. ULONG SamCount = 0;
  126. DOMAIN_SERVER_ROLE ServerRole = DomainServerRolePrimary;
  127. BOOLEAN RollbackTransaction = FALSE;
  128. BOOLEAN FixupFailed = FALSE;
  129. //
  130. // Begin a DS transaction.
  131. //
  132. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_DS_OP_TRANSACTION,
  133. TrustedDomainObject,
  134. &CloseTransaction );
  135. if ( !NT_SUCCESS( Status ) ) {
  136. return( Status );
  137. }
  138. Status = LsapDsGetListOfSystemContainerItems( CLASS_TRUSTED_DOMAIN,
  139. &Items,
  140. &DsNames );
  141. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  142. Items = 0;
  143. Status = STATUS_SUCCESS;
  144. }
  145. ASSERT(SampExistsDsTransaction());
  146. ASSERT(THVerifyCount(1));
  147. if ( NT_SUCCESS( Status ) ) {
  148. LsapSaveDsThreadState();
  149. Status = LsapOpenSam();
  150. if ( !NT_SUCCESS( Status ) ) {
  151. LsapDsDebugOut(( DEB_ERROR,
  152. "LsapDsFixupTrustedDomainObjectOnRestart: Sam not opened\n"));
  153. } else {
  154. //
  155. // Query the server role, PDC/BDC
  156. //
  157. Status = SamIQueryServerRole(
  158. LsapAccountDomainHandle,
  159. &ServerRole
  160. );
  161. if ((NT_SUCCESS(Status)) && (DomainServerRolePrimary==ServerRole))
  162. {
  163. //
  164. // Enumerate all of the SAM Interdomain trust accounts
  165. //
  166. Status = SamrEnumerateUsersInDomain( LsapAccountDomainHandle,
  167. &SamEnum,
  168. USER_INTERDOMAIN_TRUST_ACCOUNT,
  169. &RidEnum,
  170. 0xFFFFFFFF,
  171. &SamCount );
  172. if ( !NT_SUCCESS( Status ) ) {
  173. LsapDsDebugOut(( DEB_FIXUP,
  174. "SamEnumerateUsersInDomain failed with 0x%lx\n",
  175. Status ));
  176. } else {
  177. LsapDsDebugOut(( DEB_FIXUP,
  178. "SamEnumerateUsersInDomain returned %lu accounts\n",
  179. SamCount ));
  180. }
  181. }
  182. }
  183. LsapRestoreDsThreadState();
  184. }
  185. ASSERT(SampExistsDsTransaction());
  186. ASSERT(THVerifyCount(1));
  187. //
  188. // Perform fixup only on PDC
  189. //
  190. if (( NT_SUCCESS( Status ) ) && (DomainServerRolePrimary==ServerRole)) {
  191. for ( i = 0; i < Items; i++ ) {
  192. ASSERT(SampExistsDsTransaction());
  193. ASSERT(THVerifyCount(1));
  194. Status = LsapDsFixupTrustedDomainObject( DsNames[ i ], LSAP_DS_FULL_FIXUP,
  195. SamCount, (NULL!=RidEnum)?RidEnum->Buffer:NULL );
  196. if (!NT_SUCCESS(Status))
  197. {
  198. FixupFailed = TRUE;
  199. }
  200. }
  201. } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  202. Status = STATUS_SUCCESS;
  203. }
  204. if ( RidEnum ) {
  205. SamFreeMemory( RidEnum );
  206. }
  207. ASSERT(SampExistsDsTransaction());
  208. ASSERT(THVerifyCount(1));
  209. if (!NT_SUCCESS(Status))
  210. {
  211. RollbackTransaction = TRUE;
  212. }
  213. //
  214. // Close the transacation
  215. //
  216. LsapDsDeleteAllocAsNeededEx2( LSAP_DB_DS_OP_TRANSACTION,
  217. TrustedDomainObject,
  218. CloseTransaction,
  219. RollbackTransaction
  220. );
  221. ASSERT(!SampExistsDsTransaction());
  222. ASSERT(THVerifyCount(0));
  223. //
  224. // If failed then queue for a second try
  225. //
  226. if ((!NT_SUCCESS(Status)) || (FixupFailed))
  227. {
  228. LsaIRegisterNotification(
  229. LsapDsFixupTrustedDomainOnRestartCallback,
  230. NULL,
  231. NOTIFIER_TYPE_INTERVAL,
  232. 0, // no class
  233. NOTIFIER_FLAG_ONE_SHOT,
  234. 600, // wait for another 10 mins
  235. NULL // no handle
  236. );
  237. }
  238. return( STATUS_SUCCESS );
  239. }
  240. NTSTATUS
  241. LsapDsFixupTrustForXrefChange(
  242. IN PDSNAME ObjectPath,
  243. IN BOOLEAN TransactionActive
  244. )
  245. /*++
  246. This routine does the appropriate changes to the TDO to make it uplevel, when the
  247. cross ref replicates in
  248. Parameters
  249. ObjectPath -- The path to the Xref ( ie the DSNAME of the Xref )
  250. TransactionActive -- Indicates that a transaction is active and the trusted domain lock
  251. is held. Therefore these 2 operations need not be done
  252. Return Values
  253. STATUS_SUCCESS
  254. Other Error codes
  255. --*/
  256. {
  257. ATTRBLOCK Read, Results;
  258. PDSNAME NcName = NULL;
  259. PSID TrustedDomainSid=NULL;
  260. UNICODE_STRING DnsName;
  261. UNICODE_STRING FlatName;
  262. UNICODE_STRING TruncatedName;
  263. BOOLEAN NcNameFound = FALSE;
  264. BOOLEAN DnsNameFound = FALSE;
  265. BOOLEAN FlatNameFound = FALSE;
  266. LSAPR_HANDLE TrustedDomain=0;
  267. NTSTATUS Status = STATUS_SUCCESS;
  268. DSNAME *TrustedDomainDsName = NULL;
  269. DSNAME *NewObjectName = NULL;
  270. ULONG j;
  271. ULONG TrustType=0,TrustDirection=0,TrustAttributes=0;
  272. ULONG ForestTrustLength = 0;
  273. PBYTE ForestTrustInfo = NULL;
  274. BOOLEAN CloseTransaction=FALSE;
  275. BOOLEAN ActiveThreadState = FALSE;
  276. BOOLEAN TrustChanged = FALSE;
  277. BOOLEAN FoundCorrespondingTDO = FALSE;
  278. RtlZeroMemory(&DnsName, sizeof(UNICODE_STRING));
  279. RtlZeroMemory(&FlatName, sizeof(UNICODE_STRING));
  280. RtlZeroMemory(&TruncatedName, sizeof(UNICODE_STRING));
  281. if (!TransactionActive)
  282. {
  283. //
  284. // Begin a Transaction
  285. //
  286. Status = LsapDsInitAllocAsNeededEx(
  287. 0,
  288. TrustedDomainObject,
  289. &CloseTransaction
  290. );
  291. if (!NT_SUCCESS(Status))
  292. goto Error;
  293. ActiveThreadState = TRUE;
  294. }
  295. //
  296. // Read the fixup information we need. This includes:
  297. // Attributes
  298. // Trust partner
  299. // Crossref info
  300. // Type
  301. // Initial incoming auth info
  302. // Initial outgoing auth info
  303. //
  304. Read.attrCount = LsapDsTrustedDomainFixupXRefCount;
  305. Read.pAttr = LsapDsTrustedDomainFixupXRefAttributes;
  306. Status = LsapDsReadByDsName( ObjectPath,
  307. 0,
  308. &Read,
  309. &Results );
  310. if (!NT_SUCCESS(Status))
  311. {
  312. goto Error;
  313. }
  314. ASSERT(SampExistsDsTransaction());
  315. ASSERT(THVerifyCount(1));
  316. for ( j = 0; j < Results.attrCount; j++ ) {
  317. switch ( Results.pAttr[ j ].attrTyp ) {
  318. case ATT_NC_NAME:
  319. NcName = (DSNAME *) LSAP_DS_GET_DS_ATTRIBUTE_AS_DSNAME(&Results.pAttr[ j ] );
  320. if (NcName->SidLen>0)
  321. {
  322. TrustedDomainSid = LsapAllocateLsaHeap(NcName->SidLen);
  323. if ( NULL==TrustedDomainSid)
  324. {
  325. Status = STATUS_NO_MEMORY;
  326. goto Error;
  327. }
  328. RtlCopyMemory(TrustedDomainSid,&NcName->Sid,NcName->SidLen) ;
  329. }
  330. NcNameFound = TRUE;
  331. break;
  332. case ATT_DNS_ROOT:
  333. DnsName.Length = ( USHORT) LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &Results.pAttr[ j ] );
  334. DnsName.MaximumLength = DnsName.Length;
  335. //
  336. // Allocate the buffer off of the process heap, so that we can use it even after the thread state
  337. // has been killed.
  338. //
  339. DnsName.Buffer = LsapAllocateLsaHeap(DnsName.MaximumLength);
  340. if (NULL==DnsName.Buffer)
  341. {
  342. Status = STATUS_NO_MEMORY;
  343. goto Error;
  344. }
  345. RtlCopyMemory(
  346. DnsName.Buffer,
  347. LSAP_DS_GET_DS_ATTRIBUTE_AS_PWSTR( &Results.pAttr[ j ] ),
  348. DnsName.Length
  349. );
  350. DnsNameFound = TRUE;
  351. break;
  352. case ATT_NETBIOS_NAME:
  353. FlatName.Length = ( USHORT) LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &Results.pAttr[ j ] );
  354. FlatName.MaximumLength = FlatName.Length;
  355. //
  356. // Allocate the buffer off of the process heap, so that we can use it even after the thread state
  357. // has been killed.
  358. //
  359. FlatName.Buffer = LsapAllocateLsaHeap(FlatName.MaximumLength);
  360. if (NULL==FlatName.Buffer)
  361. {
  362. Status = STATUS_NO_MEMORY;
  363. goto Error;
  364. }
  365. RtlCopyMemory(
  366. FlatName.Buffer,
  367. LSAP_DS_GET_DS_ATTRIBUTE_AS_PWSTR( &Results.pAttr[ j ] ),
  368. FlatName.Length
  369. );
  370. FlatNameFound = TRUE;
  371. break;
  372. }
  373. }
  374. //
  375. // Patch up the TDO ( if required ) after finding it by the corresponding SID
  376. //
  377. if ((NcNameFound) && (NcName->SidLen>0))
  378. {
  379. //
  380. // Case of an instantiated NC
  381. //
  382. PDSNAME CategoryName = LsaDsStateInfo.SystemContainerItems.TrustedDomainObject;
  383. ATTRVAL TDOAttVals[] = {
  384. { CategoryName->structLen, (PUCHAR)CategoryName },
  385. { RtlLengthSid(TrustedDomainSid), (PUCHAR)TrustedDomainSid }
  386. };
  387. ATTR TDOAttrs[] = {
  388. { ATT_OBJECT_CATEGORY, {1, &TDOAttVals[0] } },
  389. { ATT_SECURITY_IDENTIFIER, {1, &TDOAttVals[1] } }
  390. };
  391. ASSERT(NULL!=TrustedDomainSid);
  392. Status = LsapDsSearchUnique(
  393. 0,
  394. LsaDsStateInfo.DsSystemContainer,
  395. TDOAttrs,
  396. sizeof( TDOAttrs ) / sizeof( ATTR ),
  397. &TrustedDomainDsName
  398. );
  399. if ((STATUS_OBJECT_NAME_NOT_FOUND==Status)
  400. && (FlatNameFound))
  401. {
  402. ATTRVAL TDOFlatNameAttVals[] = {
  403. { CategoryName->structLen, (PUCHAR)CategoryName },
  404. { FlatName.Length, (PUCHAR)FlatName.Buffer}
  405. };
  406. ATTR TDOFlatNameAttrs[] = {
  407. { ATT_OBJECT_CATEGORY, {1, &TDOFlatNameAttVals[0] } },
  408. { ATT_TRUST_PARTNER, {1, &TDOFlatNameAttVals[1] } }
  409. };
  410. //
  411. // We could not find the TDO by SID. Maybe this is a case of an inbount only
  412. // trust . Try to find by the flat name
  413. //
  414. Status = LsapDsSearchUnique(
  415. 0,
  416. LsaDsStateInfo.DsSystemContainer,
  417. TDOFlatNameAttrs,
  418. sizeof( TDOFlatNameAttrs ) / sizeof( ATTR ),
  419. &TrustedDomainDsName
  420. );
  421. }
  422. //
  423. // Bail if we could not find the corresponding TDO
  424. //
  425. if (!NT_SUCCESS(Status))
  426. {
  427. //
  428. // Failure to find the TDO is not an error. It just means that
  429. // a direct trust to that domain does not exist. Therefore
  430. // reset the error code before bailing
  431. //
  432. if (STATUS_OBJECT_NAME_NOT_FOUND==Status)
  433. {
  434. Status = STATUS_SUCCESS;
  435. }
  436. goto Error;
  437. }
  438. FoundCorrespondingTDO = TRUE;
  439. //
  440. // Read and Modify the trust type attribue
  441. //
  442. //
  443. // Read the fixup information we need. This includes:
  444. // Attributes
  445. // Trust partner
  446. // Crossref info
  447. // Type
  448. // Initial incoming auth info
  449. // Initial outgoing auth info
  450. //
  451. Read.attrCount = LsapDsTrustedDomainFixupAttributeCount;
  452. Read.pAttr = LsapDsTrustedDomainFixupAttributes;
  453. Status = LsapDsReadByDsName( TrustedDomainDsName,
  454. 0,
  455. &Read,
  456. &Results );
  457. if (!NT_SUCCESS(Status))
  458. {
  459. //
  460. // Failure to find a matching TDO is not an error. It simply means that we
  461. // do not have a direct trust to the domain described by the cross ref. Reset
  462. // error codes to success and bail
  463. //
  464. if (STATUS_OBJECT_NAME_NOT_FOUND == Status)
  465. {
  466. Status = STATUS_SUCCESS;
  467. }
  468. goto Error;
  469. }
  470. for ( j = 0; j < Results.attrCount; j++ ) {
  471. switch ( Results.pAttr[ j ].attrTyp ) {
  472. case ATT_TRUST_TYPE:
  473. TrustType = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &Results.pAttr[ j ] );
  474. break;
  475. case ATT_TRUST_DIRECTION:
  476. TrustDirection = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &Results.pAttr[ j ] );
  477. break;
  478. case ATT_TRUST_ATTRIBUTES:
  479. TrustAttributes = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &Results.pAttr[ j ] );
  480. break;
  481. case ATT_MS_DS_TRUST_FOREST_TRUST_INFO:
  482. ForestTrustLength = ( ULONG )LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &Results.pAttr[ j ] );
  483. ForestTrustInfo = LSAP_DS_GET_DS_ATTRIBUTE_AS_PBYTE( &Results.pAttr[ j ] );
  484. break;
  485. }
  486. }
  487. if ((TrustType & TRUST_TYPE_DOWNLEVEL ) && (DnsNameFound))
  488. {
  489. //
  490. // If the trust type is marked as downlevel, we need to change this to an uplevel trust
  491. //
  492. //
  493. // Setup the Attrblock structure for the DS
  494. //
  495. ATTRVAL TDOWriteAttVals[] = {
  496. { sizeof(ULONG), (PUCHAR)&TrustType},
  497. { ObjectPath->structLen, (PUCHAR)ObjectPath},
  498. { DnsName.Length, (PUCHAR)DnsName.Buffer}
  499. };
  500. ATTR TDOWriteAttrs[] = {
  501. { ATT_TRUST_TYPE, {1, &TDOWriteAttVals[0] } },
  502. { ATT_DOMAIN_CROSS_REF, {1, &TDOWriteAttVals[1] } },
  503. { ATT_TRUST_PARTNER, {1, &TDOWriteAttVals[2] } }
  504. };
  505. ATTRBLOCK TDOWriteAttrBlock = {sizeof(TDOWriteAttrs)/sizeof(TDOWriteAttrs[0]),TDOWriteAttrs};
  506. //
  507. // Change trust type to uplevel
  508. //
  509. TrustType &= ~((ULONG) TRUST_TYPE_DOWNLEVEL);
  510. TrustType |=TRUST_TYPE_UPLEVEL;
  511. //
  512. // Set the attributes on the TDO
  513. //
  514. Status = LsapDsWriteByDsName(
  515. TrustedDomainDsName,
  516. LSAPDS_REPLACE_ATTRIBUTE,
  517. &TDOWriteAttrBlock
  518. );
  519. if (!NT_SUCCESS(Status))
  520. goto Error;
  521. //
  522. // O.K now rename the object ( sets the DNS domain name )
  523. //
  524. Status = LsapDsTruncateNameToFitCN(
  525. &DnsName,
  526. &TruncatedName
  527. );
  528. if (!NT_SUCCESS(Status))
  529. goto Error;
  530. Status = LsapDsTrustRenameObject(
  531. TrustedDomainDsName,
  532. &TruncatedName,
  533. &NewObjectName
  534. );
  535. if (!NT_SUCCESS(Status))
  536. goto Error;
  537. TrustChanged = TRUE;
  538. }
  539. }
  540. Error:
  541. //
  542. // Update the LSA in memory list regarding the Trust change
  543. // Note this update is done after the commit, except in the case
  544. // where the caller has the transaction open which occurs during an
  545. // upgrade from NT4 where notifications to the in memory trust list
  546. // are not processed anyway.
  547. //
  548. if ((NT_SUCCESS(Status)) && (TrustChanged))
  549. {
  550. LSAPR_TRUSTED_DOMAIN_INFORMATION_EX2 NewTrustInfo;
  551. RtlZeroMemory(&NewTrustInfo, sizeof(NewTrustInfo));
  552. ASSERT(DnsNameFound);
  553. if (DnsNameFound)
  554. {
  555. RtlCopyMemory(&NewTrustInfo.Name,&DnsName, sizeof(UNICODE_STRING));
  556. }
  557. if (FlatNameFound)
  558. {
  559. RtlCopyMemory(&NewTrustInfo.FlatName,&FlatName,sizeof(UNICODE_STRING));
  560. }
  561. ASSERT(NcName->SidLen >0);
  562. NewTrustInfo.Sid = TrustedDomainSid;
  563. NewTrustInfo.TrustType = TrustType;
  564. NewTrustInfo.TrustDirection = TrustDirection;
  565. NewTrustInfo.TrustAttributes = TrustAttributes;
  566. NewTrustInfo.ForestTrustLength = ForestTrustLength;
  567. NewTrustInfo.ForestTrustInfo = ForestTrustInfo;
  568. LsapDbFixupTrustedDomainListEntry(
  569. NewTrustInfo.Sid,
  570. &NewTrustInfo.Name,
  571. &NewTrustInfo.FlatName,
  572. &NewTrustInfo,
  573. NULL
  574. );
  575. }
  576. //
  577. // Commit / Rollback the transaction if necessary
  578. //
  579. if (ActiveThreadState)
  580. {
  581. BOOLEAN RollbackTransaction = (NT_SUCCESS(Status))?FALSE:TRUE;
  582. LsapDsDeleteAllocAsNeededEx2(
  583. 0,
  584. TrustedDomainObject,
  585. CloseTransaction,
  586. RollbackTransaction // rollback transaction
  587. );
  588. ASSERT(!SampExistsDsTransaction());
  589. ASSERT(THVerifyCount(0));
  590. }
  591. if ((!NT_SUCCESS(Status)) && FoundCorrespondingTDO)
  592. {
  593. //
  594. // If we could not update the Corresponding CrossRef then event log
  595. //
  596. //
  597. // Event log the error
  598. //
  599. if (DnsNameFound)
  600. {
  601. SpmpReportEventU(
  602. EVENTLOG_ERROR_TYPE,
  603. LSA_TRUST_UPGRADE_ERROR,
  604. 0,
  605. sizeof( ULONG ),
  606. &Status,
  607. 1,
  608. &DnsName
  609. );
  610. }
  611. else if (FlatNameFound)
  612. {
  613. SpmpReportEventU(
  614. EVENTLOG_ERROR_TYPE,
  615. LSA_TRUST_UPGRADE_ERROR,
  616. 0,
  617. sizeof( ULONG ),
  618. &Status,
  619. 1,
  620. &FlatName
  621. );
  622. }
  623. //
  624. // We do not event log the failure if no name is found, but then
  625. // it is an extremely wierd case indeed.
  626. //
  627. }
  628. if (TrustedDomainDsName)
  629. LsapFreeLsaHeap(TrustedDomainDsName);
  630. if (NewObjectName)
  631. LsapFreeLsaHeap(NewObjectName);
  632. if (DnsName.Buffer)
  633. LsapFreeLsaHeap(DnsName.Buffer);
  634. if (FlatName.Buffer)
  635. LsapFreeLsaHeap(FlatName.Buffer);
  636. if (TrustedDomainSid)
  637. LsapFreeLsaHeap(TrustedDomainSid);
  638. if (TruncatedName.Buffer)
  639. LsapFreeLsaHeap(TruncatedName.Buffer);
  640. return(Status);
  641. }
  642. NTSTATUS
  643. LsapDsFixupTrustedDomainObject(
  644. IN PDSNAME TrustObject,
  645. IN BOOLEAN Startup,
  646. IN ULONG SamCount,
  647. IN PSAMPR_RID_ENUMERATION SamAccountList
  648. )
  649. /*++
  650. Routine Description:
  651. This routine will fixup an individual trusted domain object
  652. Arguments:
  653. TrustObject -- Trusted domain object to fix up
  654. Startup -- If TRUE, this is startup fixup, so do the full set. Otherwise, it's notification
  655. fixup, so a limited set is done.
  656. Return Values:
  657. STATUS_SUCCESS -- Success
  658. --*/
  659. {
  660. NTSTATUS Status = STATUS_SUCCESS;
  661. PDSNAME NewTrust = NULL;
  662. ULONG Items, i, j;
  663. ATTRBLOCK Read, Results, XRefResults, Write;
  664. ATTR WriteAttrs[ 4 ];
  665. ATTRVAL WriteAttrVal[ sizeof( WriteAttrs ) / sizeof( ATTR ) ];
  666. ULONG Attributes, Type, XRefAttr, Direction = 0;
  667. PUNICODE_STRING InitialIncoming = NULL, InitialOutgoing = NULL, Partner = NULL, Flat = NULL;
  668. UNICODE_STRING Initial, UnicodePartner, UnicodeIncoming, UnicodeOutgoing, XRefDns, FlatName = { 0 };
  669. BOOLEAN CloseTransaction, WriteXRef, WritePartner, WriteAttribute, WriteType;
  670. BOOLEAN RenameRequired = FALSE, RemoveIncoming = FALSE, RemoveOutgoing = FALSE;
  671. BOOLEAN RemoveObject = FALSE;
  672. PSAMPR_RID_ENUMERATION CurrentAccount = NULL;
  673. TRUSTED_DOMAIN_INFORMATION_EX UpdateInfoEx;
  674. ULONG Size = 0;
  675. //
  676. // A DS transaction should already exist at this point.
  677. //
  678. ASSERT(SampExistsDsTransaction());
  679. ASSERT(THVerifyCount(1));
  680. RtlZeroMemory( &Write, sizeof( ATTRBLOCK ) );
  681. WriteXRef = FALSE;
  682. WritePartner = FALSE;
  683. WriteAttribute = FALSE;
  684. WriteType = FALSE;
  685. LsapDsDebugOut(( DEB_FIXUP,
  686. "Processing %ws\n",
  687. LsapDsNameFromDsName( TrustObject ) ));
  688. //
  689. // Read the fixup information we need. This includes:
  690. // Attributes
  691. // Trust partner
  692. // Crossref info
  693. // Type
  694. // Initial incoming auth info
  695. // Initial outgoing auth info
  696. //
  697. Read.attrCount = LsapDsTrustedDomainFixupAttributeCount;
  698. Read.pAttr = LsapDsTrustedDomainFixupAttributes;
  699. Status = LsapDsReadByDsName( TrustObject,
  700. 0,
  701. &Read,
  702. &Results );
  703. if ( NT_SUCCESS( Status ) ) {
  704. for ( j = 0; j < Results.attrCount; j++ ) {
  705. switch ( Results.pAttr[ j ].attrTyp ) {
  706. case ATT_TRUST_PARTNER:
  707. UnicodePartner.Length = ( USHORT) LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &Results.pAttr[ j ] );
  708. UnicodePartner.MaximumLength = UnicodePartner.Length;
  709. UnicodePartner.Buffer = LSAP_DS_GET_DS_ATTRIBUTE_AS_PWSTR( &Results.pAttr[ j ] );
  710. Partner = &UnicodePartner;
  711. break;
  712. case ATT_FLAT_NAME:
  713. FlatName.Length = ( USHORT) LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &Results.pAttr[ j ] );
  714. FlatName.MaximumLength = FlatName.Length;
  715. FlatName.Buffer = LSAP_DS_GET_DS_ATTRIBUTE_AS_PWSTR( &Results.pAttr[ j ] );
  716. Flat = &FlatName;
  717. break;
  718. case ATT_TRUST_ATTRIBUTES:
  719. Attributes = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &Results.pAttr[ j ] );
  720. break;
  721. case ATT_TRUST_DIRECTION:
  722. Direction = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &Results.pAttr[ j ] );
  723. break;
  724. case ATT_TRUST_TYPE:
  725. Type = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &Results.pAttr[ j ] );
  726. break;
  727. case ATT_INITIAL_AUTH_INCOMING:
  728. UnicodeIncoming.Length = ( USHORT) LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &Results.pAttr[ j ] );
  729. UnicodeIncoming.MaximumLength = UnicodeIncoming.Length;
  730. UnicodeIncoming.Buffer = LSAP_DS_GET_DS_ATTRIBUTE_AS_PWSTR( &Results.pAttr[ j ] );
  731. InitialIncoming = &UnicodeIncoming;
  732. break;
  733. case ATT_INITIAL_AUTH_OUTGOING:
  734. UnicodeOutgoing.Length = ( USHORT) LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &Results.pAttr[ j ] );
  735. UnicodeOutgoing.MaximumLength = UnicodeOutgoing.Length;
  736. UnicodeOutgoing.Buffer = LSAP_DS_GET_DS_ATTRIBUTE_AS_PWSTR( &Results.pAttr[ j ] );
  737. InitialOutgoing = &UnicodeOutgoing;
  738. break;
  739. default:
  740. //
  741. // If other attributes that we do not necessarily want came back, then do nothing.
  742. //
  743. break;
  744. }
  745. }
  746. }
  747. //
  748. // See if we have the proper interdomain trust account set
  749. //
  750. if ( NT_SUCCESS( Status ) && Startup && FLAG_ON( Direction, TRUST_DIRECTION_INBOUND ) ) {
  751. //
  752. // Find the interdomain trust account that matches
  753. //
  754. for ( Items = 0; Items < SamCount; Items++ ) {
  755. if ( FlatName.Length + sizeof( WCHAR ) == SamAccountList[ Items ].Name.Length &&
  756. RtlPrefixUnicodeString( &FlatName,
  757. ( PUNICODE_STRING )&SamAccountList[ Items ].Name,
  758. TRUE ) ) {
  759. CurrentAccount = &SamAccountList[ Items ];
  760. break;
  761. }
  762. }
  763. //
  764. // We have no account, so we had better create one
  765. //
  766. if ( CurrentAccount == NULL ) {
  767. Status = LsapDsCreateInterdomainTrustAccountByDsName( TrustObject,
  768. &FlatName );
  769. if ( !NT_SUCCESS( Status ) ) {
  770. SpmpReportEventU(
  771. EVENTLOG_WARNING_TYPE,
  772. LSAEVENT_ITA_FOR_TRUST_NOT_CREATED,
  773. 0,
  774. sizeof( ULONG ),
  775. &Status,
  776. 1,
  777. Partner ? Partner : &FlatName
  778. );
  779. }
  780. } else {
  781. if ( RemoveObject ) {
  782. LsapDsDebugOut(( DEB_FIXUP,
  783. "InterdomainTrustAccount %wZ being removed\n",
  784. &CurrentAccount->Name ));
  785. }
  786. }
  787. }
  788. #if DBG
  789. if ( !NT_SUCCESS( Status ) ) {
  790. LsapDsDebugOut(( DEB_FIXUP, "Fixup of %ws failed with 0x%lx\n",
  791. LsapDsNameFromDsName( TrustObject ), Status ));
  792. }
  793. #endif
  794. //
  795. // The DS transaction should remain open at this point.
  796. //
  797. ASSERT(SampExistsDsTransaction());
  798. ASSERT(THVerifyCount(1));
  799. return( Status );
  800. }
  801. NTSTATUS
  802. LsapDsTrustRenameObject(
  803. IN PDSNAME TrustObject,
  804. IN PUNICODE_STRING NewDns,
  805. OUT PDSNAME *NewObjectName
  806. )
  807. /*++
  808. Routine Description:
  809. This routine will rename an existing trusted domain object
  810. Arguments:
  811. Return Values:
  812. STATUS_SUCCESS -- Success
  813. --*/
  814. {
  815. NTSTATUS Status = STATUS_SUCCESS;
  816. PDSNAME NewObject = NULL;
  817. ULONG Len = 0;
  818. //
  819. // Build a new object name
  820. //
  821. if ( NewObjectName != NULL ) {
  822. Len = LsapDsLengthAppendRdnLength( LsaDsStateInfo.DsSystemContainer,
  823. NewDns->Length + sizeof( WCHAR ) );
  824. *NewObjectName = LsapAllocateLsaHeap( Len );
  825. if ( *NewObjectName == NULL ) {
  826. Status = STATUS_INSUFFICIENT_RESOURCES;
  827. } else {
  828. Status = LsapDsMapDsReturnToStatus( AppendRDN( LsaDsStateInfo.DsSystemContainer,
  829. *NewObjectName,
  830. Len,
  831. NewDns->Buffer,
  832. NewDns->Length / sizeof( WCHAR ),
  833. ATT_COMMON_NAME ) );
  834. }
  835. }
  836. if ( NT_SUCCESS( Status ) ) {
  837. //
  838. // Do the rename
  839. //
  840. Status = LsapDsRenameObject( TrustObject,
  841. NULL,
  842. ATT_COMMON_NAME,
  843. NewDns );
  844. if ( !NT_SUCCESS( Status ) ) {
  845. LsapDsDebugOut(( DEB_FIXUP,
  846. "Rename of %ws to %wZ failed with 0x%lx\n",
  847. LsapDsNameFromDsName( TrustObject ),
  848. NewDns,
  849. Status ));
  850. if ( NewObjectName != NULL ) {
  851. LsapFreeLsaHeap( *NewObjectName );
  852. *NewObjectName = NULL;
  853. }
  854. }
  855. }
  856. return( Status );
  857. }
  858. NTSTATUS
  859. LsaIDsNotifiedObjectChange(
  860. IN ULONG Class,
  861. IN PVOID ObjectPath,
  862. IN SECURITY_DB_DELTA_TYPE DeltaType,
  863. IN PSID UserSid,
  864. IN LUID AuthenticationId,
  865. IN BOOLEAN ReplicatedInChange,
  866. IN BOOLEAN ChangeOriginatedInLSA
  867. )
  868. /*++
  869. Routine Description:
  870. This routine is called by the Ds when an object that the Lsa cares about is modified.
  871. This call is made synchronously to the Ds commit thread, and so must spend as little
  872. time doing stuff as possible. Used only as a dispatch mechanism.
  873. Arguments:
  874. Class -- Class Id of the object being modified
  875. ObjectPath -- Full Ds path to the object that has been modified
  876. DeltaType -- Type of the modification
  877. UserSid -- The SID of the user who made this change, if known
  878. AuthenticationId -- ?? authentication ID of the user who made this change
  879. ReplicatedInChange -- TRUE if this is a replicated-in change
  880. ChangeOriginatedInLSA -- TRUE if the change originated in LSA
  881. Return Values:
  882. STATUS_SUCCESS -- Success
  883. STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed
  884. --*/
  885. {
  886. NTSTATUS Status = STATUS_SUCCESS;
  887. PLSAP_DSFU_NOTIFICATION_NODE NotificationNode;
  888. PDSNAME Object = ( PDSNAME )ObjectPath;
  889. BOOLEAN TrustedDomainChangeQueued;
  890. //
  891. // Queue the item to be processed
  892. //
  893. LsapDsDebugOut(( DEB_DSNOTIFY,
  894. "LsaIDsNotifiedObjectChange called for 0x%lx / %lu / %ws\n",
  895. Class,
  896. DeltaType,
  897. LsapDsNameFromDsName( Object ) ));
  898. //
  899. // If this is notification of the NTDS-DSA object, the only action we care about
  900. // is a rename. All others we eat. This notification actually gets passed on to
  901. // Netlogon, and that's all it cares about
  902. //
  903. if ( Class == CLASS_NTDS_DSA && DeltaType != SecurityDbRename ) {
  904. LsapDsDebugOut(( DEB_DSNOTIFY,
  905. "Notification for class NTDS_DSA ( %ws )was not a rename. Eating change\n",
  906. LsapDsNameFromDsName( Object ) ));
  907. return( STATUS_SUCCESS );
  908. }
  909. //
  910. // If class is TRUSTED_DOMAIN or CROSS_REF then this means the trusted domain change
  911. // is not queued yet. So when we negate the statement above, the trusted domain change
  912. // is queued if class is not TRUSTED_DOMAIN and is not CROSS_REF.
  913. //
  914. TrustedDomainChangeQueued = ( Class != CLASS_TRUSTED_DOMAIN ) &&
  915. ( Class != CLASS_CROSS_REF );
  916. NotificationNode = LsapAllocateLsaHeap( sizeof( LSAP_DSFU_NOTIFICATION_NODE ) );
  917. if ( NotificationNode == NULL ) {
  918. Status = STATUS_INSUFFICIENT_RESOURCES;
  919. } else {
  920. RtlZeroMemory( NotificationNode, sizeof( LSAP_DSFU_NOTIFICATION_NODE ) );
  921. if ( RtlValidSid( UserSid ) ) {
  922. LSAPDS_ALLOC_AND_COPY_SID_ON_SUCCESS( Status, NotificationNode->UserSid, UserSid );
  923. }
  924. if ( NT_SUCCESS( Status ) ) {
  925. Status = LsapDsCopyDsNameLsa( &NotificationNode->ObjectPath,
  926. Object );
  927. if (NT_SUCCESS(Status))
  928. {
  929. NotificationNode->Class = Class;
  930. NotificationNode->DeltaType = DeltaType;
  931. NotificationNode->AuthenticationId = AuthenticationId;
  932. NotificationNode->ReplicatedInChange = ReplicatedInChange;
  933. NotificationNode->ChangeOriginatedInLSA = ChangeOriginatedInLSA;
  934. //
  935. // If this is an originating change,
  936. // get the TrustDirection that existed before the change.
  937. //
  938. if ( !ReplicatedInChange ) {
  939. PLSADS_PER_THREAD_INFO CurrentThreadInfo;
  940. CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
  941. // ASSERT( CurrentThreadInfo != NULL )
  942. if ( CurrentThreadInfo != NULL ) {
  943. NotificationNode->OldTrustDirection = CurrentThreadInfo->OldTrustDirection;
  944. NotificationNode->OldTrustType = CurrentThreadInfo->OldTrustType;
  945. }
  946. }
  947. //
  948. // Queue the request to another thread
  949. //
  950. if ( LsapDsQueueFixupRequest( NotificationNode ) ) {
  951. TrustedDomainChangeQueued = TRUE;
  952. NotificationNode = NULL;
  953. } else {
  954. Status = STATUS_INSUFFICIENT_RESOURCES ;
  955. }
  956. }
  957. }
  958. if ( !NT_SUCCESS( Status ) ) {
  959. LsapFreeNotificationNode( NotificationNode );
  960. }
  961. }
  962. //
  963. // Only notify netlogon on non-replicated-in changes
  964. // Replicated-in changes are handled by the fixup routine
  965. // (LsapDsFixupCallback)
  966. //
  967. // We need to notify Netlogon as soon as the changes are in the
  968. // database, so DsEnumerateDomainTrusts returns up-to-date
  969. // information. Delaying notification until the callback routine
  970. // means that there would be a window during which netlogon cache
  971. // would not contain the correct information
  972. //
  973. // In the future, we'd like to have a single trusted domain cache
  974. // and this entire logic should go away.
  975. //
  976. if ( !ReplicatedInChange &&
  977. Class == LsapDsClassIds[LsapDsClassTrustedDomain] ) {
  978. NTSTATUS Status2;
  979. Status2 = LsapNotifyNetlogonOfTrustChange(
  980. NULL,
  981. DeltaType
  982. );
  983. if ( !NT_SUCCESS( Status2 ) ) {
  984. LsapDsDebugOut(( DEB_DSNOTIFY,
  985. "LsapNotifyNetlogonOfTrustChange failed with 0x%lx\n",
  986. Status2 ));
  987. }
  988. LsapDbSetStatusFromSecondary( Status, Status2 );
  989. }
  990. //
  991. // If there is an error, we need to invalidate the cache.
  992. //
  993. if( !TrustedDomainChangeQueued ) {
  994. if( NT_SUCCESS( LsapDbAcquireWriteLockTrustedDomainList() ) ) {
  995. LsapDbMakeCacheInvalid( TrustedDomainObject );
  996. LsapDbReleaseLockTrustedDomainList();
  997. }
  998. }
  999. return( Status );
  1000. }
  1001. NTSTATUS
  1002. LsaIKerberosRegisterTrustNotification(
  1003. IN pfLsaTrustChangeNotificationCallback Callback,
  1004. IN LSAP_REGISTER Register
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. This routine is provided so that in process logon packages, such as Kerberos, can
  1009. get notification of trust changes. Currently, only one such package is supported.
  1010. Arguments:
  1011. Callback -- Address of callback function to make
  1012. Register -- Whether to register or unregister the notification
  1013. Return Values:
  1014. STATUS_SUCCESS -- Success
  1015. STATUS_INVALID_PARAMETER -- A request was made to register a NULL callback
  1016. STATUS_UNCSUCCESSFUL -- The operation couldn't be compeleted. Either a callback is
  1017. already registered or no call back is registered.
  1018. --*/
  1019. {
  1020. NTSTATUS Status = STATUS_SUCCESS;
  1021. switch ( Register ) {
  1022. case LsaRegister:
  1023. if ( LsapKerberosTrustNotificationFunction == NULL ) {
  1024. if ( Callback == NULL ) {
  1025. Status = STATUS_INVALID_PARAMETER;
  1026. } else {
  1027. LsapKerberosTrustNotificationFunction = Callback;
  1028. }
  1029. } else {
  1030. Status = STATUS_UNSUCCESSFUL;
  1031. }
  1032. break;
  1033. case LsaUnregister:
  1034. if ( LsapKerberosTrustNotificationFunction == NULL ) {
  1035. Status = STATUS_UNSUCCESSFUL;
  1036. } else {
  1037. LsapKerberosTrustNotificationFunction = NULL;
  1038. }
  1039. break;
  1040. default:
  1041. Status = STATUS_INVALID_PARAMETER;
  1042. break;
  1043. }
  1044. return( Status );
  1045. }
  1046. VOID
  1047. LsapFreeNotificationNode(
  1048. IN PLSAP_DSFU_NOTIFICATION_NODE NotificationNode
  1049. )
  1050. /*++
  1051. Routine Description:
  1052. This routine frees a notification node
  1053. Arguments:
  1054. NotificationNode -- Node to be freed
  1055. Return Values:
  1056. VOID
  1057. --*/
  1058. {
  1059. if ( NotificationNode ) {
  1060. LsapFreeLsaHeap( NotificationNode->UserSid );
  1061. LsapFreeLsaHeap( NotificationNode->ObjectPath );
  1062. LsapFreeLsaHeap( NotificationNode );
  1063. }
  1064. }
  1065. NTSTATUS
  1066. LsapDsFixupChangeNotificationForReplicator(
  1067. LSAP_DB_OBJECT_TYPE_ID ObjectType,
  1068. PSID Sid,
  1069. PUNICODE_STRING FlatName,
  1070. PDSNAME ObjectPath,
  1071. SECURITY_DB_DELTA_TYPE DeltaType,
  1072. BOOLEAN ReplicatedInChange
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. This routine provides change notifications to netlogon on trust/global secret changes. This handles replicated in changes in a multimaster system and also
  1077. secret object changes ( needed for NT4 ) when outbound trust changes.
  1078. Parameters:
  1079. Sid -- The SID of the trusted domain object
  1080. FlatName -- The flat name/netbios name of the domain
  1081. ObjectPath -- The DSNAME of the object. identifies the object in the DS
  1082. DeltaType -- Type of change, add/modify/delete
  1083. Return Values
  1084. --*/
  1085. {
  1086. NTSTATUS Status = STATUS_SUCCESS;
  1087. LARGE_INTEGER One = {1,0};
  1088. PBYTE Buffer;
  1089. UNICODE_STRING SecretName;
  1090. BOOLEAN SerialNumberChanged = FALSE;
  1091. //
  1092. // Lock the LSA database.
  1093. //
  1094. // We need at least the following locks:
  1095. // PolicyLock: protect policy cache
  1096. // RegistryLock: protects LsapDbState.PolicyModificationInfo (and registry transaction)
  1097. // Registry lock is acquired later, if we decide that the modification info
  1098. // is going to change
  1099. //
  1100. LsapDbAcquireLockEx( PolicyObject, LSAP_DB_READ_ONLY_TRANSACTION );
  1101. //
  1102. // Handle TDO notification.
  1103. //
  1104. if (TrustedDomainObject==ObjectType) {
  1105. //
  1106. // Give one notification for the trusted domain object
  1107. //
  1108. LsapDbLockAcquire( &LsapDbState.RegistryLock );
  1109. LsapDbState.PolicyModificationInfo.ModifiedId.QuadPart+=One.QuadPart;
  1110. SerialNumberChanged = TRUE;
  1111. LsapNetNotifyDelta(
  1112. SecurityDbLsa,
  1113. LsapDbState.PolicyModificationInfo.ModifiedId,
  1114. DeltaType,
  1115. SecurityDbObjectLsaTDomain,
  1116. 0,
  1117. Sid,
  1118. NULL,
  1119. TRUE, // Replicate immediately
  1120. NULL
  1121. );
  1122. //
  1123. // Give a second notification for the secret object, corresponding to the trusted
  1124. // domain object. NT4 stores the auth info in a global secret, while NT5 stored it
  1125. // in the TDO itself. The TDO is exposed as global secret also for NT4.
  1126. //
  1127. SafeAllocaAllocate( Buffer, FlatName->Length + sizeof( LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX ));
  1128. if ( Buffer == NULL ) {
  1129. Status = STATUS_INSUFFICIENT_RESOURCES;
  1130. goto Cleanup;
  1131. }
  1132. RtlZeroMemory(Buffer, FlatName->Length +
  1133. sizeof( LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX ) );
  1134. RtlCopyMemory( Buffer, LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX,
  1135. sizeof( LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX ) );
  1136. RtlCopyMemory( Buffer +
  1137. sizeof( LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX ) -
  1138. sizeof(WCHAR),
  1139. FlatName->Buffer,
  1140. FlatName->Length);
  1141. RtlInitUnicodeString( &SecretName, (PWSTR)Buffer );
  1142. LsapDbState.PolicyModificationInfo.ModifiedId.QuadPart+=One.QuadPart;
  1143. SerialNumberChanged = TRUE;
  1144. LsapNetNotifyDelta(
  1145. SecurityDbLsa,
  1146. LsapDbState.PolicyModificationInfo.ModifiedId,
  1147. DeltaType,
  1148. SecurityDbObjectLsaSecret,
  1149. 0,
  1150. NULL,
  1151. &SecretName,
  1152. TRUE, // Replicate immediately
  1153. NULL
  1154. );
  1155. SafeAllocaFree( Buffer );
  1156. Buffer = NULL;
  1157. }
  1158. else if ((SecretObject==ObjectType) )
  1159. {
  1160. WCHAR RdnStart[ MAX_RDN_SIZE + 1 ];
  1161. ULONG Len;
  1162. ATTRTYP AttrType;
  1163. BOOLEAN SkipNotification = FALSE;
  1164. Status = LsapDsMapDsReturnToStatus( GetRDNInfoExternal(
  1165. ObjectPath,
  1166. RdnStart,
  1167. &Len,
  1168. &AttrType ) );
  1169. if ( NT_SUCCESS( Status ) ) {
  1170. ULONG UnmangledLen;
  1171. //
  1172. // The RDN is mangled on a delete, however the first 75 chars
  1173. // of the RDN is prserved ( and we use upto 64 Chars ) so we
  1174. // are O.K wrt to character loss ( fortunately ).
  1175. // So just adjust the size accordingly.
  1176. //
  1177. if ((SecurityDbDelete==DeltaType) &&
  1178. (IsMangledRDNExternal(RdnStart,Len,&UnmangledLen)))
  1179. {
  1180. Len = UnmangledLen;
  1181. }
  1182. //
  1183. // Allocate a buffer to hold the name
  1184. //
  1185. SafeAllocaAllocate( Buffer, Len * sizeof( WCHAR ) + sizeof( LSA_GLOBAL_SECRET_PREFIX ));
  1186. if ( Buffer == NULL ) {
  1187. Status = STATUS_INSUFFICIENT_RESOURCES;
  1188. goto Cleanup;
  1189. }
  1190. //
  1191. // If the LSA created the global secret, we appended a postfix... Remove
  1192. // that here.
  1193. //
  1194. RdnStart[ Len ] = UNICODE_NULL;
  1195. if ( Len > LSAP_DS_SECRET_POSTFIX_LEN &&
  1196. _wcsicmp( &RdnStart[Len-LSAP_DS_SECRET_POSTFIX_LEN],
  1197. LSAP_DS_SECRET_POSTFIX ) == 0 ) {
  1198. Len -= LSAP_DS_SECRET_POSTFIX_LEN;
  1199. RdnStart[ Len ] = UNICODE_NULL;
  1200. }
  1201. RtlCopyMemory( Buffer,
  1202. LSA_GLOBAL_SECRET_PREFIX,
  1203. sizeof( LSA_GLOBAL_SECRET_PREFIX ) );
  1204. RtlCopyMemory( Buffer + sizeof( LSA_GLOBAL_SECRET_PREFIX ) - sizeof(WCHAR),
  1205. RdnStart,
  1206. ( Len + 1 ) * sizeof( WCHAR ) );
  1207. RtlInitUnicodeString( &SecretName, (PWSTR)Buffer );
  1208. //
  1209. // If this is a secret object deletion,
  1210. // Skip the notification if the secret was simply morphed into a TDO.
  1211. //
  1212. if ( DeltaType == SecurityDbDelete ) {
  1213. BOOLEAN DsTrustedDomainSecret;
  1214. (VOID) LsapDsIsSecretDsTrustedDomain(
  1215. &SecretName,
  1216. NULL, // No object info since not openning handle
  1217. 0, // No options since not openning handle
  1218. 0, // No access since not openning handle
  1219. NULL, // Don't return a handle to the object
  1220. &DsTrustedDomainSecret );
  1221. if ( DsTrustedDomainSecret ) {
  1222. SkipNotification = TRUE;
  1223. }
  1224. }
  1225. //
  1226. // Do the actual notification.
  1227. //
  1228. if ( !SkipNotification ) {
  1229. LsapDbLockAcquire( &LsapDbState.RegistryLock );
  1230. LsapDbState.PolicyModificationInfo.ModifiedId.QuadPart+=One.QuadPart;
  1231. SerialNumberChanged = TRUE;
  1232. LsapNetNotifyDelta(
  1233. SecurityDbLsa,
  1234. LsapDbState.PolicyModificationInfo.ModifiedId,
  1235. DeltaType,
  1236. SecurityDbObjectLsaSecret,
  1237. 0,
  1238. NULL,
  1239. &SecretName,
  1240. TRUE, // Replicate immediately
  1241. NULL
  1242. );
  1243. }
  1244. SafeAllocaFree( Buffer );
  1245. Buffer = NULL;
  1246. }
  1247. }
  1248. //
  1249. // If the serial number changed,
  1250. // write it to the registry.
  1251. //
  1252. // Don't do this by going through the policy object since we want to
  1253. // avoid any side effects when writing this non-replicated attribute.
  1254. //
  1255. if ( SerialNumberChanged ) {
  1256. //
  1257. // Invalidate the cache for the Policy Modification Information
  1258. //
  1259. LsapDbMakeInvalidInformationPolicy( PolicyModificationInformation );
  1260. //
  1261. // Open the transaction
  1262. //
  1263. Status = LsapRegOpenTransaction();
  1264. if ( NT_SUCCESS(Status) ) {
  1265. //
  1266. // Write the attribute
  1267. Status = LsapDbWriteAttributeObject(
  1268. LsapDbHandle,
  1269. &LsapDbNames[ PolMod ],
  1270. (PVOID) &LsapDbState.PolicyModificationInfo,
  1271. (ULONG) sizeof (POLICY_MODIFICATION_INFO)
  1272. );
  1273. if ( NT_SUCCESS(Status) ) {
  1274. Status = LsapRegApplyTransaction();
  1275. } else {
  1276. Status = LsapRegAbortTransaction();
  1277. }
  1278. }
  1279. }
  1280. Cleanup:
  1281. LsapDbReleaseLockEx( PolicyObject, LSAP_DB_READ_ONLY_TRANSACTION );
  1282. if ( SerialNumberChanged ) {
  1283. LsapDbLockRelease( &LsapDbState.RegistryLock );
  1284. }
  1285. return (Status);
  1286. }
  1287. DWORD
  1288. WINAPI LsapDsFixupCallback(
  1289. LPVOID ParameterBlock
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. This is the worker thread for the fixup code. Whenever notification of an object change
  1294. comes from the Ds, it ends up routing through here, which will dispatch it as appropriate.
  1295. Arguments:
  1296. ParameterBlock -- NotificationNode of information sufficient to determine what
  1297. operation should be taken
  1298. Passed Class must be one of the followings;
  1299. CLASS_TRUSTED_DOMAIN
  1300. CLASS_SECRET
  1301. CLASS_CROSS_REF
  1302. CLASS_USER
  1303. or ERROR_INVALID_PARAMETER is returned.
  1304. Return Values:
  1305. ERROR_SUCCESS -- Success
  1306. ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  1307. ERROR_INVALID_PARAMETER -- An unexpected parameter was encountered
  1308. --*/
  1309. {
  1310. NTSTATUS Status = STATUS_SUCCESS;
  1311. PLSAP_DSFU_NOTIFICATION_NODE NotificationNode = ( PLSAP_DSFU_NOTIFICATION_NODE )ParameterBlock;
  1312. LSAPR_TRUSTED_DOMAIN_FULL_INFORMATION2 TrustInfo2;
  1313. BOOLEAN CloseTransaction = FALSE, RollbackTransaction = FALSE, ActiveThreadState = FALSE;
  1314. LSAP_DB_OBJECT_TYPE_ID ObjType = NullObject;
  1315. BOOLEAN TrustedDomainCacheIsUpToDate;
  1316. LsapDsDebugOut(( DEB_DSNOTIFY | DEB_FTRACE,
  1317. "LsapDsFixupCallback called for 0x%lx / %lu / %ws\n",
  1318. NotificationNode->Class,
  1319. NotificationNode->DeltaType,
  1320. LsapDsNameFromDsName( NotificationNode->ObjectPath ) ));
  1321. switch ( NotificationNode->Class ) {
  1322. case CLASS_TRUSTED_DOMAIN:
  1323. ObjType = TrustedDomainObject;
  1324. break;
  1325. case CLASS_SECRET:
  1326. ObjType = SecretObject;
  1327. break;
  1328. }
  1329. RtlZeroMemory(&TrustInfo2, sizeof(TrustInfo2));
  1330. //
  1331. // If class is TRUSTED_DOMAIN or CROSS_REF then this means the trusted domain change
  1332. // is not reflected to the TrustedDomainCache so it is not upto date. Therefore when we negate
  1333. // the statement above, the trusted domain cache is upto date if class is not TRUSTED_DOMAIN
  1334. // and is not CROSS_REF.
  1335. //
  1336. TrustedDomainCacheIsUpToDate = ( NotificationNode->Class != CLASS_TRUSTED_DOMAIN ) &&
  1337. ( NotificationNode->Class != CLASS_CROSS_REF );
  1338. //
  1339. // Initialize the DS allocator and create a DS thread state at this point.
  1340. //
  1341. if ( ObjType != NullObject ) {
  1342. Status = LsapDsInitAllocAsNeededEx( 0,
  1343. ObjType,
  1344. &CloseTransaction );
  1345. if ( !NT_SUCCESS( Status ) ) {
  1346. goto FixupCallbackCleanup;
  1347. }
  1348. ActiveThreadState = TRUE;
  1349. }
  1350. //
  1351. // Handle a TDO changing.
  1352. //
  1353. if ( NotificationNode->Class == LsapDsClassIds[ LsapDsClassTrustedDomain ] ) {
  1354. //
  1355. // Get a description of the TDO as it appears in the DS.
  1356. //
  1357. Status = LsapDsGetTrustedDomainInfoEx( NotificationNode->ObjectPath,
  1358. NotificationNode->DeltaType == SecurityDbDelete ?
  1359. LSAPDS_READ_DELETED : 0,
  1360. TrustedDomainFullInformation2Internal,
  1361. (PLSAPR_TRUSTED_DOMAIN_INFO)&TrustInfo2,
  1362. NULL );
  1363. if ( !NT_SUCCESS(Status) ) {
  1364. //
  1365. // Before a deletion notification to a trusted domain, a change notification is sent. We don't
  1366. // want/expect this notification. So, skip it! After all we are not interested in a change in a
  1367. // deleted trusted domain object.
  1368. //
  1369. if( NotificationNode->DeltaType == SecurityDbChange &&
  1370. Status == STATUS_OBJECT_NAME_NOT_FOUND &&
  1371. DsIsMangledDn(
  1372. LsapDsNameFromDsName( NotificationNode->ObjectPath ),
  1373. DS_MANGLE_OBJECT_RDN_FOR_DELETION ) ) {
  1374. TrustedDomainCacheIsUpToDate = TRUE;
  1375. }
  1376. goto FixupCallbackCleanup;
  1377. }
  1378. //
  1379. // Our DS Transaction State should not be altered by LsapDsGetTrustedDomainInfoEx
  1380. //
  1381. ASSERT(SampExistsDsTransaction());
  1382. ASSERT(THVerifyCount(1));
  1383. //
  1384. // If this is a replicated in change,
  1385. // get the previous trust direction from the cache entry on this machine.
  1386. //
  1387. if ( NotificationNode->ReplicatedInChange ) {
  1388. //
  1389. // Default the old direction to the new direction.
  1390. //
  1391. NotificationNode->OldTrustDirection = TrustInfo2.Information.TrustDirection;
  1392. NotificationNode->OldTrustType = TrustInfo2.Information.TrustType;
  1393. //
  1394. // Grab the GUID of the real TDO for this named trust.
  1395. //
  1396. Status = LsapDbAcquireReadLockTrustedDomainList();
  1397. if ( NT_SUCCESS(Status)) {
  1398. PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY TrustEntry;
  1399. //
  1400. // Lookup the information in the trusted domain list
  1401. //
  1402. Status = LsapDbLookupNameTrustedDomainListEx(
  1403. &TrustInfo2.Information.Name,
  1404. &TrustEntry );
  1405. if ( NT_SUCCESS(Status)) {
  1406. ASSERT(NULL!=TrustEntry);
  1407. NotificationNode->OldTrustDirection = TrustEntry->TrustInfoEx.TrustDirection;
  1408. NotificationNode->OldTrustType = TrustEntry->TrustInfoEx.TrustType;
  1409. }
  1410. LsapDbReleaseLockTrustedDomainList();
  1411. }
  1412. }
  1413. //
  1414. // Any failure to update the cache is handled by LsapDsFixupTrustByInfo
  1415. //
  1416. TrustedDomainCacheIsUpToDate = TRUE;
  1417. //
  1418. // Fix the TDL to match the actual object.
  1419. //
  1420. Status = LsapDsFixupTrustByInfo( NotificationNode->ObjectPath,
  1421. &TrustInfo2.Information,
  1422. TrustInfo2.PosixOffset.Offset,
  1423. NotificationNode->DeltaType,
  1424. NotificationNode->UserSid,
  1425. NotificationNode->AuthenticationId,
  1426. NotificationNode->ReplicatedInChange,
  1427. NotificationNode->ChangeOriginatedInLSA
  1428. );
  1429. //
  1430. // Only notify netlogon on a replicated-in change
  1431. // Non-replicated-in changes are handled by the commit callback routine
  1432. // (LsaIDsNotifiedObjectChange)
  1433. //
  1434. if ( NotificationNode->ReplicatedInChange ) {
  1435. NTSTATUS Status2;
  1436. Status2 = LsapNotifyNetlogonOfTrustChange(
  1437. NULL,
  1438. NotificationNode->DeltaType
  1439. );
  1440. if ( !NT_SUCCESS( Status2 ) ) {
  1441. LsapDsDebugOut(( DEB_DSNOTIFY,
  1442. "LsapNotifyNetlogonOfTrustChange failed with 0x%lx\n",
  1443. Status2 ));
  1444. }
  1445. LsapDbSetStatusFromSecondary( Status, Status2 );
  1446. }
  1447. } else if ( NotificationNode->Class == LsapDsClassIds[ LsapDsClassSecret ] ) {
  1448. //
  1449. // Currently, there is nothing to do...
  1450. //
  1451. } else if ( NotificationNode->Class == LsapDsClassIds[ LsapDsClassXRef ] ){
  1452. //
  1453. // New Cross ref has replicated in, look at corresponding TDO and see if it needs
  1454. // to be renamed
  1455. //
  1456. Status = LsapDsFixupTrustForXrefChange(
  1457. NotificationNode->ObjectPath,
  1458. FALSE // will begin and end its own transaction
  1459. );
  1460. //
  1461. // Since a cross-ref has changed, repopulate the cross-forest trust cache
  1462. // with local forest trust information
  1463. //
  1464. Status = LsapDbAcquireWriteLockTrustedDomainList();
  1465. if ( NT_SUCCESS( Status )) {
  1466. Status = LsapForestTrustInsertLocalInfo();
  1467. if ( !NT_SUCCESS( Status )) {
  1468. //
  1469. // Had trouble inserting forest trust info into the cache!!!
  1470. // Mark the trusted domain list as invalid so it can get rebuilt.
  1471. //
  1472. LsapDbPurgeTrustedDomainCache();
  1473. }
  1474. LsapDbReleaseLockTrustedDomainList();
  1475. }
  1476. TrustedDomainCacheIsUpToDate = TRUE;
  1477. //
  1478. // Notify netlogon and kerberos of the possibility of the trust tree having changed
  1479. //
  1480. if ( LsapKerberosTrustNotificationFunction ) {
  1481. LsaIRegisterNotification( ( SEC_THREAD_START )LsapKerberosTrustNotificationFunction,
  1482. ( PVOID ) NotificationNode->DeltaType,
  1483. NOTIFIER_TYPE_IMMEDIATE,
  1484. 0,
  1485. NOTIFIER_FLAG_ONE_SHOT,
  1486. 0,
  1487. 0 );
  1488. }
  1489. Status = I_NetNotifyDsChange( NlOrgChanged );
  1490. if ( !NT_SUCCESS( Status ) ) {
  1491. LsapDsDebugOut(( DEB_ERROR,
  1492. "I_NetNotifyDsChange( NlOrgChange ) failed with 0x%lx\n" ));
  1493. }
  1494. } else if ( NotificationNode->Class == CLASS_USER ) {
  1495. //
  1496. // Nothing really to do out here. We do not take any change notifications to user
  1497. // objects.
  1498. //
  1499. } else {
  1500. Status = STATUS_INVALID_PARAMETER;
  1501. }
  1502. FixupCallbackCleanup:
  1503. RollbackTransaction = (NT_SUCCESS(Status))?FALSE:TRUE;
  1504. //
  1505. // Destruction of the thread state will delete the memory alloced by the SearchNonUnique call
  1506. //
  1507. if (ActiveThreadState)
  1508. {
  1509. LsapDsDeleteAllocAsNeededEx2( 0,
  1510. ObjType,
  1511. CloseTransaction,
  1512. RollbackTransaction
  1513. );
  1514. }
  1515. //
  1516. // Assert that we have cleaned up the DS properly
  1517. //
  1518. ASSERT(!SampExistsDsTransaction());
  1519. ASSERT(THVerifyCount(0));
  1520. if (NT_SUCCESS(Status))
  1521. {
  1522. //
  1523. // We need to provide netlogon notifications on trust/secret changes
  1524. // for replication to NT4
  1525. //
  1526. if ((TrustedDomainObject==ObjType) &&
  1527. (NULL!=TrustInfo2.Information.Sid) &&
  1528. (TrustInfo2.Information.FlatName.Length>0))
  1529. {
  1530. BOOLEAN NotifyNetlogon = TRUE;
  1531. SECURITY_DB_DELTA_TYPE DeltaTypeToUse = NotificationNode->DeltaType;
  1532. //
  1533. // If this object need not be replicated to NT 4,
  1534. // be careful about giving spurious notifications.
  1535. //
  1536. if ( !LsapReplicateTdoNt4( TrustInfo2.Information.TrustDirection,
  1537. TrustInfo2.Information.TrustType ) ) {
  1538. //
  1539. // If the object is just being created or deleted,
  1540. // then NT 4 isn't interested in this trust.
  1541. //
  1542. if ( DeltaTypeToUse == SecurityDbNew ||
  1543. DeltaTypeToUse == SecurityDbDelete ) {
  1544. NotifyNetlogon = FALSE;
  1545. //
  1546. // If the object didn't used to be replicated to NT 4,
  1547. // then this change simply isn't interesting to NT 4 replication.
  1548. //
  1549. } else if ( !LsapReplicateTdoNt4( NotificationNode->OldTrustDirection,
  1550. NotificationNode->OldTrustType ) ) {
  1551. NotifyNetlogon = FALSE;
  1552. //
  1553. // If this object used to replicated to NT 4,
  1554. // then this is really an object deletion as far as NT 4 replication
  1555. // is concerned.
  1556. //
  1557. } else {
  1558. DeltaTypeToUse = SecurityDbDelete;
  1559. }
  1560. }
  1561. //
  1562. // Now notify netlogon
  1563. //
  1564. if ( NotifyNetlogon ) {
  1565. //
  1566. // If we knew that the Outbound password property has been changed,
  1567. // then and only then should we notify netlogon that the underlying global
  1568. // secret has changed.
  1569. // However, the change is probably not worth making, because the cost
  1570. // of not making it is a few extra bytes on the wire.
  1571. //
  1572. LsapDsFixupChangeNotificationForReplicator(
  1573. TrustedDomainObject,
  1574. TrustInfo2.Information.Sid,
  1575. (PUNICODE_STRING) &TrustInfo2.Information.FlatName,
  1576. NotificationNode->ObjectPath,
  1577. DeltaTypeToUse,
  1578. NotificationNode->ReplicatedInChange
  1579. );
  1580. }
  1581. }
  1582. else if (SecretObject == ObjType)
  1583. {
  1584. LsapDsFixupChangeNotificationForReplicator(
  1585. SecretObject,
  1586. NULL,
  1587. NULL,
  1588. NotificationNode->ObjectPath,
  1589. NotificationNode->DeltaType,
  1590. NotificationNode->ReplicatedInChange
  1591. );
  1592. }
  1593. }
  1594. //
  1595. // Free the allocations...
  1596. //
  1597. _fgu__LSAPR_TRUSTED_DOMAIN_INFO( (PLSAPR_TRUSTED_DOMAIN_INFO)&TrustInfo2,
  1598. TrustedDomainFullInformation2Internal );
  1599. LsapFreeNotificationNode( NotificationNode );
  1600. if( !TrustedDomainCacheIsUpToDate ) {
  1601. if( NT_SUCCESS( LsapDbAcquireWriteLockTrustedDomainList() ) ) {
  1602. LsapDbMakeCacheInvalid( TrustedDomainObject );
  1603. LsapDbReleaseLockTrustedDomainList();
  1604. }
  1605. }
  1606. return( RtlNtStatusToDosError( Status ) );
  1607. }
  1608. NTSTATUS
  1609. LsapDsFixupTrustByInfo(
  1610. IN PDSNAME ObjectPath,
  1611. IN PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX2 TrustInfo2,
  1612. IN ULONG PosixOffset,
  1613. IN SECURITY_DB_DELTA_TYPE DeltaType,
  1614. IN PSID UserSid,
  1615. IN LUID AuthenticationId,
  1616. IN BOOLEAN ReplicatedInChange,
  1617. IN BOOLEAN ChangeOriginatedInLSA
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. This function does the fixup of trusted domain objects following notification from the
  1622. Ds. For created and deleted objects, it involves updating the trust list and notifying
  1623. netlogon and kerberos of changes. For modifications, verification of correctness is done.
  1624. Upon an object creaton the corresponding SAM account is created. Upon an object deletion
  1625. the corresponding SAM account is delted.
  1626. Arguments:
  1627. ObjectPath -- The Ds name of the object that changed
  1628. TrustInfo2 -- The information that is currently available about the trust
  1629. PosixOffset -- Posix offset of the domain.
  1630. DeltaType -- Type of change that happened
  1631. UserSid -- The user that was responsible for making this change
  1632. AuthenticationId -- AuthenticationId of the user making the change
  1633. ReplicatedInChange -- Indicates that the change replicated in instead of being an originating
  1634. change
  1635. ChangeOriginatedInLSA -- Indicates that the change has originated in LSA as opposed to DS/LDAP
  1636. Return Values:
  1637. ERROR_SUCCESS -- Success
  1638. ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  1639. --*/
  1640. {
  1641. NTSTATUS Status = STATUS_SUCCESS;
  1642. LSAPR_TRUST_INFORMATION TrustInformation;
  1643. BOOLEAN AcquiredListWriteLock = FALSE;
  1644. BOOLEAN TrustLockAcquired = FALSE;
  1645. LsapDsDebugOut(( DEB_FTRACE,
  1646. "LsapDsFixupTrustByInfo( %ws, %x, %x, ...)\n",
  1647. ObjectPath ? LsapDsNameFromDsName( ObjectPath ) : L"<null>",
  1648. TrustInfo2,
  1649. DeltaType ));
  1650. //
  1651. // If this is a replicated in change,
  1652. // make sure the TDO has a valid Posix Offset in it.
  1653. //
  1654. if ( ReplicatedInChange &&
  1655. (DeltaType == SecurityDbNew || DeltaType == SecurityDbChange ) ) {
  1656. DOMAIN_SERVER_ROLE ServerRole;
  1657. //
  1658. // Only change the Posix Offset on the PDC.
  1659. //
  1660. Status = SamIQueryServerRole(
  1661. LsapAccountDomainHandle,
  1662. &ServerRole
  1663. );
  1664. if ( NT_SUCCESS(Status) && ServerRole == DomainServerRolePrimary ) {
  1665. BOOLEAN PosixOffsetChanged = FALSE;
  1666. if ( LsapDbDcInRootDomain()) {
  1667. //
  1668. // On a root domain PDC, acquire the trust lock before
  1669. // the rest to ensure no deadlocks if forest trust data
  1670. // needs to be written back to the DS
  1671. //
  1672. LsapDbAcquireLockEx( TrustedDomainObject, LSAP_DB_LOCK );
  1673. TrustLockAcquired = TRUE;
  1674. }
  1675. //
  1676. // If we should have a Posix Offset,
  1677. // ensure we have one.
  1678. //
  1679. if ( LsapNeedPosixOffset( TrustInfo2->TrustDirection,
  1680. TrustInfo2->TrustType ) ) {
  1681. if ( PosixOffset == 0 ) {
  1682. //
  1683. // Need to grab the TDL write lock while allocating a Posix Offset
  1684. //
  1685. Status = LsapDbAcquireWriteLockTrustedDomainList();
  1686. if ( NT_SUCCESS(Status)) {
  1687. AcquiredListWriteLock = TRUE;
  1688. //
  1689. // Allocate the next available Posix Offset.
  1690. //
  1691. Status = LsapDbAllocatePosixOffsetTrustedDomainList(
  1692. &PosixOffset );
  1693. if ( NT_SUCCESS(Status)) {
  1694. PosixOffsetChanged = TRUE;
  1695. }
  1696. }
  1697. }
  1698. //
  1699. // If we shouldn't have a Posix Offset,
  1700. // ensure we don't have one.
  1701. //
  1702. } else {
  1703. if ( PosixOffset != 0 ) {
  1704. PosixOffset = 0;
  1705. PosixOffsetChanged = TRUE;
  1706. }
  1707. }
  1708. //
  1709. // If we're forcing the Posix Offset to change,
  1710. // do it now.
  1711. //
  1712. if ( PosixOffsetChanged ) {
  1713. ATTRVAL TDOWriteAttVals[] = {
  1714. { sizeof(ULONG), (PUCHAR)&PosixOffset},
  1715. };
  1716. ATTR TDOWriteAttrs[] = {
  1717. { ATT_TRUST_POSIX_OFFSET, {1, &TDOWriteAttVals[0] } },
  1718. };
  1719. ATTRBLOCK TDOWriteAttrBlock = {sizeof(TDOWriteAttrs)/sizeof(TDOWriteAttrs[0]),TDOWriteAttrs};
  1720. //
  1721. // Set the Posix Offset on the TDO
  1722. //
  1723. Status = LsapDsWriteByDsName(
  1724. ObjectPath,
  1725. LSAPDS_REPLACE_ATTRIBUTE,
  1726. &TDOWriteAttrBlock
  1727. );
  1728. if (!NT_SUCCESS(Status)) {
  1729. Status = STATUS_SUCCESS; // This isn't fatal
  1730. }
  1731. }
  1732. }
  1733. }
  1734. switch ( DeltaType ) {
  1735. case SecurityDbNew:
  1736. if (ReplicatedInChange)
  1737. {
  1738. //
  1739. // On a replicated in change notification, insert the trusted domain
  1740. // object into the trusted domain list. This need not be done for the
  1741. // case of an originating change as this is done within the LSA call to
  1742. // create the trusted domain object.
  1743. //
  1744. if ( NT_SUCCESS( LsapDbAcquireWriteLockTrustedDomainList())) {
  1745. if( LsapDbIsValidTrustedDomainList() ) {
  1746. Status = LsapDbInsertTrustedDomainList(
  1747. TrustInfo2,
  1748. PosixOffset
  1749. );
  1750. if ( !NT_SUCCESS( Status ) ) {
  1751. LsapDsDebugOut(( DEB_ERROR,
  1752. "LsapDbInsertTrustedDomainList for %wZ failed with 0x%lx\n",
  1753. &TrustInfo2->FlatName,
  1754. Status ));
  1755. }
  1756. }
  1757. LsapDbReleaseLockTrustedDomainList();
  1758. }
  1759. }
  1760. break;
  1761. case SecurityDbChange:
  1762. //
  1763. // On a replicated in change update the trusted domain List
  1764. //
  1765. if (ReplicatedInChange)
  1766. {
  1767. Status = LsapDbFixupTrustedDomainListEntry(
  1768. TrustInfo2->Sid,
  1769. &TrustInfo2->Name,
  1770. &TrustInfo2->FlatName,
  1771. TrustInfo2,
  1772. &PosixOffset );
  1773. if ( !NT_SUCCESS( Status ) ) {
  1774. LsapDsDebugOut(( DEB_ERROR,
  1775. "LsapDbFixupTrustedDomainList for %wZ failed with 0x%lx\n",
  1776. &TrustInfo2->FlatName,
  1777. Status ));
  1778. }
  1779. }
  1780. break;
  1781. case SecurityDbDelete:
  1782. if ( ReplicatedInChange || !ChangeOriginatedInLSA) {
  1783. PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY TrustEntry;
  1784. GUID RealTdoGuid;
  1785. //
  1786. // Check to see that the object path is not a mangled name.
  1787. // If it is drop the notification on the floor.
  1788. //
  1789. // If a set of duplicate trusts exist,
  1790. // we must delete only the good one from the cache
  1791. //
  1792. //
  1793. // Grab the GUID of the real TDO for this named trust.
  1794. //
  1795. Status = LsapDbAcquireReadLockTrustedDomainList();
  1796. if (!NT_SUCCESS(Status)) {
  1797. break;
  1798. }
  1799. //
  1800. // Lookup the information in the trusted domain list
  1801. //
  1802. Status = LsapDbLookupNameTrustedDomainListEx(
  1803. &TrustInfo2->Name,
  1804. &TrustEntry
  1805. );
  1806. if (!NT_SUCCESS(Status)) {
  1807. LsapDbReleaseLockTrustedDomainList();
  1808. break;
  1809. }
  1810. ASSERT(NULL!=TrustEntry);
  1811. RealTdoGuid = TrustEntry->ObjectGuidInDs;
  1812. LsapDbReleaseLockTrustedDomainList();
  1813. //
  1814. // If this TDO isn't the TDO that we've selected to represent this trust,
  1815. // then it is the mangled TDO.
  1816. //
  1817. // Totally ignore changes to this mangled TDO.
  1818. //
  1819. if ((!LsapNullUuid(&RealTdoGuid))
  1820. && (0!=memcmp(&RealTdoGuid, &ObjectPath->Guid, sizeof(GUID))))
  1821. {
  1822. //
  1823. // Error out. This will cause us to not update the trusted domain list and not
  1824. // provide netlogon notifications
  1825. //
  1826. Status = STATUS_OBJECT_NAME_COLLISION;
  1827. break;
  1828. }
  1829. TrustInformation.Sid = TrustInfo2->Sid;
  1830. RtlCopyMemory( &TrustInformation.Name, &TrustInfo2->FlatName, sizeof( UNICODE_STRING ) );
  1831. if ( NT_SUCCESS( LsapDbAcquireWriteLockTrustedDomainList() ) ) {
  1832. Status = LsapDbDeleteTrustedDomainList( &TrustInformation );
  1833. if ( !NT_SUCCESS( Status ) ) {
  1834. ASSERTMSG( "We checked that it was in the list. Who deleted it before we do?",
  1835. Status != STATUS_NO_SUCH_DOMAIN );
  1836. LsapDsDebugOut(( DEB_ERROR,
  1837. "LsapDbDeleteTrustedDomainList for %wZ failed with 0x%lx\n",
  1838. &TrustInfo2->FlatName,
  1839. Status ));
  1840. }
  1841. LsapDbReleaseLockTrustedDomainList();
  1842. }
  1843. }
  1844. //
  1845. // if a TDO is deleted by LSA, the audit will be generated in
  1846. // the main thread (LsarDeleteObject). However, if a TDO
  1847. // is deleted by LDAP, DS does not call LsarDeleteObject
  1848. // to effect the change in LSA, it simply deletes object
  1849. // and sends a notification. We generate the audit here
  1850. // if the change did not originate in LSA (indicated by
  1851. // the value of ChangeOriginatedInLSA).
  1852. //
  1853. if ((UserSid && LsapAdtAuditingEnabledHint(AuditCategoryPolicyChange, EVENTLOG_AUDIT_SUCCESS)) &&
  1854. (!ReplicatedInChange) &&
  1855. (!ChangeOriginatedInLSA)) {
  1856. Status = LsapAdtTrustedDomainRem(
  1857. EVENTLOG_AUDIT_SUCCESS,
  1858. (PUNICODE_STRING) &TrustInfo2->Name,
  1859. (PSID) TrustInfo2->Sid,
  1860. UserSid,
  1861. &AuthenticationId
  1862. );
  1863. }
  1864. break;
  1865. default:
  1866. //
  1867. // Unsupported delta type
  1868. //
  1869. LsapDsDebugOut(( DEB_ERROR,
  1870. "LsapDsFixupTrustByInfo received an unsupported delta type of %lu\n",
  1871. DeltaType ));
  1872. }
  1873. //
  1874. // If necessary, release the Trusted Domain List Write Lock.
  1875. //
  1876. if (AcquiredListWriteLock) {
  1877. LsapDbReleaseLockTrustedDomainList();
  1878. AcquiredListWriteLock = FALSE;
  1879. }
  1880. if ( TrustLockAcquired ) {
  1881. LsapDbReleaseLockEx( TrustedDomainObject, LSAP_DB_LOCK );
  1882. }
  1883. return( Status );
  1884. }
  1885. NTSTATUS
  1886. LsapDsInitFixupQueue(
  1887. VOID
  1888. )
  1889. {
  1890. InitializeListHead( &LsapFixupList );
  1891. return SafeInitializeCriticalSection( &LsapFixupLock, ( DWORD )LSAP_FIXUP_LOCK_ENUM );
  1892. }
  1893. DWORD
  1894. LsapDsFixupQueueWorker(
  1895. PVOID Ignored
  1896. )
  1897. {
  1898. PLSAP_DSFU_NOTIFICATION_NODE Node ;
  1899. PLIST_ENTRY List ;
  1900. SafeEnterCriticalSection( &LsapFixupLock );
  1901. if ( LsapFixupThreadActive )
  1902. {
  1903. SafeLeaveCriticalSection( &LsapFixupLock );
  1904. return 0 ;
  1905. }
  1906. LsapFixupThreadActive = TRUE ;
  1907. while ( !IsListEmpty( &LsapFixupList ) )
  1908. {
  1909. List = RemoveHeadList( &LsapFixupList );
  1910. SafeLeaveCriticalSection( &LsapFixupLock );
  1911. Node = CONTAINING_RECORD( List, LSAP_DSFU_NOTIFICATION_NODE, List );
  1912. LsapDsFixupCallback( Node );
  1913. SafeEnterCriticalSection( &LsapFixupLock );
  1914. }
  1915. LsapFixupThreadActive = FALSE ;
  1916. SafeLeaveCriticalSection( &LsapFixupLock );
  1917. return 0 ;
  1918. }
  1919. BOOL
  1920. LsapDsQueueFixupRequest(
  1921. PLSAP_DSFU_NOTIFICATION_NODE Node
  1922. )
  1923. {
  1924. BOOL Ret = TRUE ;
  1925. SafeEnterCriticalSection( &LsapFixupLock );
  1926. if ( LsapFixupThreadActive == FALSE )
  1927. {
  1928. Ret = QueueUserWorkItem( LsapDsFixupQueueWorker, NULL, 0 );
  1929. }
  1930. if ( Ret )
  1931. {
  1932. InsertTailList( &LsapFixupList, &Node->List );
  1933. }
  1934. SafeLeaveCriticalSection( &LsapFixupLock );
  1935. return Ret ;
  1936. }
  1937. NTSTATUS
  1938. LsapNotifyNetlogonOfTrustWithParent(
  1939. VOID
  1940. )
  1941. /*++
  1942. Routine Description:
  1943. Notifies Netlogon of trust relationship with the parent domain.
  1944. Arguments:
  1945. None
  1946. Returns:
  1947. STATUS_SUCCESS if happy
  1948. STATUS_ error code otherwise
  1949. --*/
  1950. {
  1951. NTSTATUS Status;
  1952. PLSAPR_FOREST_TRUST_INFO ForestTrustInfo = NULL;
  1953. ASSERT( SamIIsRebootAfterPromotion());
  1954. //
  1955. // Locate the trust link to the parent
  1956. //
  1957. Status = LsaIQueryForestTrustInfo(
  1958. LsapPolicyHandle,
  1959. &ForestTrustInfo
  1960. );
  1961. if ( !NT_SUCCESS( Status )) {
  1962. LsapDsDebugOut(( DEB_ERROR,
  1963. "LsapNotifyNetlogonOfTrustWithParent got error 0x%lx back from LsaIQueryForestTrustInfo\n",
  1964. Status ));
  1965. goto Cleanup;
  1966. }
  1967. ASSERT( ForestTrustInfo );
  1968. if ( ForestTrustInfo->ParentDomainReference == NULL ) {
  1969. //
  1970. // We're the root domain of the forest. Nothing to do.
  1971. //
  1972. Status = STATUS_SUCCESS;
  1973. goto Cleanup;
  1974. }
  1975. //
  1976. // Notify netlogon of the trust relationship changing.
  1977. // Nothing changed, but this will force the necessary replication.
  1978. //
  1979. Status = LsapDsFixupChangeNotificationForReplicator(
  1980. TrustedDomainObject,
  1981. ForestTrustInfo->ParentDomainReference->DomainSid,
  1982. &ForestTrustInfo->ParentDomainReference->FlatName,
  1983. NULL,
  1984. SecurityDbChange,
  1985. FALSE
  1986. );
  1987. if ( !NT_SUCCESS( Status )) {
  1988. LsapDsDebugOut(( DEB_ERROR,
  1989. "LsapNotifyNetlogonOfTrustWithParent got error 0x%lx back from LsapDsFixupChangeNotificationForReplicator\n",
  1990. Status ));
  1991. goto Cleanup;
  1992. }
  1993. Cleanup:
  1994. LsaIFreeForestTrustInfo( ForestTrustInfo );
  1995. return Status;
  1996. }