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.

1515 lines
37 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. dbadmin.c
  5. Abstract:
  6. Local Security Authority - Database Administration
  7. This file contains routines that perform general Lsa Database
  8. administration functions
  9. Author:
  10. Scott Birrell (ScottBi) August 27, 1991
  11. Environment:
  12. Revision History:
  13. --*/
  14. #include <lsapch2.h>
  15. #include "dbp.h"
  16. #include "adtp.h"
  17. #if DBG
  18. LSADS_THREAD_INFO_NODE LsapDsThreadInfoList[ LSAP_THREAD_INFO_LIST_MAX ];
  19. SAFE_RESOURCE LsapDsThreadInfoListResource;
  20. #endif
  21. LSADS_INIT_STATE LsaDsInitState;
  22. NTSTATUS
  23. LsapDbSetStates(
  24. IN ULONG DesiredStatesSet,
  25. IN LSAPR_HANDLE ObjectHandle,
  26. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId
  27. )
  28. /*++
  29. Routine Description:
  30. This routine turns on special states in the Lsa Database. These
  31. states can be turned off using LsapDbResetStates.
  32. Arguments:
  33. DesiredStatesSet - Specifies the states to be set.
  34. LSAP_DB_LOCK - Acquire the Lsa Database lock.
  35. LSAP_DB_LOG_QUEUE_LOCK - Acquire the Lsa Audit Log
  36. Queue Lock.
  37. LSAP_DB_START_TRANSACTION - Start an Lsa Database transaction. There
  38. must not already be one in progress.
  39. LSAP_DB_READ_ONLY_TRANSACTION - Open a transaction for read only
  40. LSAP_DB_DS_OP_TRANSACTION - Perform a single Ds operation per transaction
  41. ObjectHandle - Pointer to handle to be validated and referenced.
  42. ObjectTypeId - Specifies the expected object type to which the handle
  43. relates. An error is returned if this type does not match the
  44. type contained in the handle.
  45. Return Value:
  46. NTSTATUS - Standard Nt Result Code
  47. STATUS_INVALID_STATE - The Database is not in the correct state
  48. to allow this state change.
  49. --*/
  50. {
  51. NTSTATUS Status = STATUS_SUCCESS;
  52. NTSTATUS SecondaryStatus = STATUS_SUCCESS;
  53. ULONG StatesSetHere = 0;
  54. LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )ObjectHandle;
  55. LsapDsDebugOut(( DEB_FTRACE, "LsapDbSetStates\n" ));
  56. //
  57. // If we have an object type that doesn't write to the Ds, make sure we have
  58. // the options set appropriately
  59. //
  60. if ( ObjectTypeId == PolicyObject ||
  61. ObjectTypeId == AccountObject ) {
  62. DesiredStatesSet |= LSAP_DB_NO_DS_OP_TRANSACTION;
  63. }
  64. if ( ObjectTypeId == TrustedDomainObject ) {
  65. DesiredStatesSet |= LSAP_DB_READ_ONLY_TRANSACTION;
  66. }
  67. //
  68. // If requested, lock the Audit Log Queue
  69. //
  70. if (DesiredStatesSet & LSAP_DB_LOG_QUEUE_LOCK) {
  71. Status = LsapAdtAcquireLogFullLock();
  72. if (!NT_SUCCESS(Status)) {
  73. goto SetStatesError;
  74. }
  75. StatesSetHere |= LSAP_DB_LOG_QUEUE_LOCK;
  76. }
  77. //
  78. // If requested, lock the Lsa database
  79. //
  80. if (DesiredStatesSet & LSAP_DB_LOCK) {
  81. LsapDbAcquireLockEx( ObjectTypeId,
  82. DesiredStatesSet );
  83. StatesSetHere |= LSAP_DB_LOCK;
  84. }
  85. //
  86. // If requested, open a database update transaction.
  87. //
  88. if ( FLAG_ON( DesiredStatesSet, LSAP_DB_READ_ONLY_TRANSACTION |
  89. LSAP_DB_NO_DS_OP_TRANSACTION |
  90. LSAP_DB_DS_OP_TRANSACTION |
  91. LSAP_DB_START_TRANSACTION ) ) {
  92. Status = LsapDbOpenTransaction( DesiredStatesSet );
  93. if (!NT_SUCCESS(Status)) {
  94. goto SetStatesError;
  95. }
  96. StatesSetHere |= LSAP_DB_START_TRANSACTION;
  97. }
  98. SetStatesFinish:
  99. LsapDsDebugOut(( DEB_FTRACE, "LsapDbSetStates: 0x%lx\n", Status ));
  100. return( Status );
  101. SetStatesError:
  102. //
  103. // If we started a transaction, abort it.
  104. //
  105. if (StatesSetHere & LSAP_DB_START_TRANSACTION) {
  106. SecondaryStatus = LsapDbAbortTransaction( DesiredStatesSet );
  107. }
  108. //
  109. // If we locked the database, unlock it.
  110. //
  111. if (StatesSetHere & LSAP_DB_LOCK) {
  112. LsapDbReleaseLockEx( ObjectTypeId,
  113. DesiredStatesSet );
  114. }
  115. //
  116. // If we locked the Audit Log Queue, unlock it.
  117. //
  118. if (StatesSetHere & LSAP_DB_LOG_QUEUE_LOCK) {
  119. LsapAdtReleaseLogFullLock();
  120. }
  121. goto SetStatesFinish;
  122. }
  123. NTSTATUS
  124. LsapDbResetStates(
  125. IN LSAPR_HANDLE ObjectHandle,
  126. IN ULONG Options,
  127. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  128. IN SECURITY_DB_DELTA_TYPE SecurityDbDeltaType,
  129. IN NTSTATUS PreliminaryStatus
  130. )
  131. /*++
  132. Routine Description:
  133. This function resets the Lsa Database states specified. It is used
  134. to reset states set by LsapDbSetStates.
  135. Arguments:
  136. ObjectHandle - Handle to an LSA object. This is expected to have
  137. already been validated.
  138. Options - Specifies optional actions, including states to be reset
  139. LSAP_DB_LOCK - Lsa Database lock to be released
  140. LSAP_DB_LOG_QUEUE_LOCK - Lsa Audit Log Queue Lock to
  141. be released.
  142. LSAP_DB_FINISH_TRANSACTION - Lsa database transaction open.
  143. LSAP_DB_OMIT_REPLICATOR_NOTIFICATION - Omit notification to
  144. Replicators.
  145. ObjectTypeId - Specifies the expected object type to which the handle
  146. relates.
  147. PreliminaryStatus - Indicates the preliminary result code of the
  148. calling routine. Allows reset action to vary depending on the
  149. result code, for example, apply or abort transaction.
  150. Return Value:
  151. NTSTATUS - Standard Nt Result Code. This is the final status to be used
  152. by the caller and is equal to the Preliminary status except in the
  153. case where that is as success status and this routine fails.
  154. --*/
  155. {
  156. NTSTATUS Status = STATUS_SUCCESS;
  157. LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )ObjectHandle;
  158. LsapDsDebugOut(( DEB_FTRACE, "LsapDbResetStates (Prelim: 0x%lx )\n", PreliminaryStatus ));
  159. //
  160. // If we have an object type that doesn't write to the Ds, make sure we have
  161. // the options set appropriately
  162. //
  163. if ( ObjectTypeId == PolicyObject ||
  164. ObjectTypeId == AccountObject ) {
  165. Options |= LSAP_DB_NO_DS_OP_TRANSACTION;
  166. }
  167. if ( ObjectTypeId == TrustedDomainObject ) {
  168. Options |= LSAP_DB_READ_ONLY_TRANSACTION;
  169. }
  170. //
  171. // If requested, finish a database update transaction.
  172. //
  173. if ( !FLAG_ON( Options, LSAP_DB_STANDALONE_REFERENCE ) &&
  174. FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION |
  175. LSAP_DB_NO_DS_OP_TRANSACTION |
  176. LSAP_DB_DS_OP_TRANSACTION |
  177. LSAP_DB_FINISH_TRANSACTION ) ) {
  178. if (NT_SUCCESS(PreliminaryStatus)) {
  179. Status = LsapDbApplyTransaction(
  180. ObjectHandle,
  181. Options,
  182. SecurityDbDeltaType
  183. );
  184. } else {
  185. Status = LsapDbAbortTransaction( Options );
  186. }
  187. }
  188. //
  189. // If unlocking requested, unlock the Lsa Database.
  190. //
  191. if (Options & LSAP_DB_LOCK) {
  192. LsapDbReleaseLockEx( ObjectTypeId,
  193. Options );
  194. }
  195. //
  196. // If unlocking if the Audit Log Queue requested, unlock the queue.
  197. //
  198. if (Options & LSAP_DB_LOG_QUEUE_LOCK) {
  199. LsapAdtReleaseLogFullLock();
  200. }
  201. //
  202. // The requested reset operations were performed successfully.
  203. // Propagate the preliminary status back to the caller.
  204. //
  205. if ( NT_SUCCESS( Status ))
  206. {
  207. Status = PreliminaryStatus;
  208. }
  209. LsapDsDebugOut(( DEB_FTRACE, "LsapDbResetStates: 0x%lx\n", Status ));
  210. return( Status );
  211. }
  212. NTSTATUS
  213. LsapDbOpenTransaction(
  214. IN ULONG Options
  215. )
  216. /*++
  217. Routine Description:
  218. This function starts a transaction within the LSA Database.
  219. WARNING: The Lsa Database must be in the locked state when this function
  220. is called.
  221. Arguments:
  222. Options - Options to apply when opening the transaction. Valid values are:
  223. LSAP_DB_READ_ONLY_TRANSACTION - Open a transaction for read only
  224. Return Value:
  225. NTSTATUS - Standard Nt Result Code
  226. Result codes are those returned from the Registry Transaction
  227. Package.
  228. --*/
  229. {
  230. NTSTATUS Status = STATUS_SUCCESS;
  231. BOOLEAN RegTransactionOpened = FALSE;
  232. if ( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) ) {
  233. Status = LsapRegOpenTransaction();
  234. if (NT_SUCCESS(Status))
  235. {
  236. RegTransactionOpened = TRUE;
  237. }
  238. }
  239. if ( NT_SUCCESS( Status ) && LsapDsIsFunctionTableValid() ) {
  240. ASSERT( LsaDsStateInfo.DsFuncTable.pOpenTransaction );
  241. Status = (*LsaDsStateInfo.DsFuncTable.pOpenTransaction) ( Options );
  242. if ((!NT_SUCCESS(Status)) && RegTransactionOpened)
  243. {
  244. NTSTATUS IgnoreStatus;
  245. IgnoreStatus = LsapRegAbortTransaction();
  246. }
  247. }
  248. return Status;
  249. }
  250. NTSTATUS
  251. LsapDbApplyTransaction(
  252. IN LSAPR_HANDLE ObjectHandle,
  253. IN ULONG Options,
  254. IN SECURITY_DB_DELTA_TYPE SecurityDbDeltaType
  255. )
  256. /*++
  257. Routine Description:
  258. This function applies a transaction within the LSA Database.
  259. WARNING: The Lsa Database must be in the locked state when this function
  260. is called.
  261. Arguments:
  262. ObjectHandle - Handle to an LSA object. This is expected to have
  263. already been validated.
  264. Options - Specifies optional actions to be taken. The following
  265. options are recognized, other options relevant to calling routines
  266. are ignored.
  267. LSAP_DB_OMIT_REPLICATOR_NOTIFICATION - Omit notification to
  268. Replicator.
  269. Return Value:
  270. NTSTATUS - Standard Nt Result Code
  271. Result codes are those returned from the Registry Transaction
  272. Package.
  273. --*/
  274. {
  275. NTSTATUS Status;
  276. LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )ObjectHandle;
  277. BOOLEAN RegApplied = FALSE, Notify = FALSE;
  278. BOOLEAN RestoreModifiedId = FALSE;
  279. BOOLEAN RegistryLocked = FALSE;
  280. LARGE_INTEGER Increment = {1,0},
  281. OriginalModifiedId = { 0 };
  282. PLSADS_PER_THREAD_INFO CurrentThreadInfo;
  283. ULONG SavedDsOperationCount = 0;
  284. //
  285. // Reference the thread state so it doesn't disappear in the middle of this
  286. // routine.
  287. //
  288. CurrentThreadInfo = LsapQueryThreadInfo();
  289. if ( CurrentThreadInfo ) {
  290. SavedDsOperationCount = CurrentThreadInfo->DsOperationCount;
  291. LsapCreateThreadInfo();
  292. }
  293. //
  294. // Verify that the LSA Database is locked
  295. // One of many locks is locked
  296. //
  297. //ASSERT (LsapDbIsLocked());
  298. //
  299. // Apply the DS transaction before grabbing any more locks.
  300. //
  301. // Note that this applies the transaction before updating the modified ID.
  302. // If we crash before updateing the modified ID, NT 4 BDCs won't be notified
  303. // of this change.
  304. //
  305. if ( LsapDsIsFunctionTableValid() ) {
  306. ASSERT( LsaDsStateInfo.DsFuncTable.pApplyTransaction );
  307. Status = (*LsaDsStateInfo.DsFuncTable.pApplyTransaction)( Options );
  308. if (!NT_SUCCESS(Status)) {
  309. goto Cleanup;
  310. }
  311. }
  312. //
  313. // Notify the replicator unless:
  314. // We are to omit replicator (e.g. for creation of a local secret), OR
  315. // we are installing the Policy Object,
  316. // notification globally disabled.
  317. //
  318. if ((!(Options & LSAP_DB_OMIT_REPLICATOR_NOTIFICATION)) &&
  319. (LsapDbHandle != NULL) &&
  320. (LsapDbState.ReplicatorNotificationEnabled )) {
  321. BOOLEAN DbChanged = FALSE;
  322. //
  323. // If the object is in the DS,
  324. // determine if the DS changed.
  325. //
  326. if ( LsapDsIsHandleDsHandle( InternalHandle )) {
  327. //
  328. // Netlogon notification of DS object change is *ALWAYS* handled
  329. // in the DS notification callback routine. That's the easiest
  330. // way to handle things like TDO changes result in both TDO notifications
  331. // and the corresponding global secret notification.
  332. //
  333. ASSERT( InternalHandle->ObjectTypeId == TrustedDomainObject ||
  334. InternalHandle->ObjectTypeId == SecretObject );
  335. //
  336. // If the object is a registry object,
  337. // determine if the registry has changed.
  338. //
  339. } else {
  340. //
  341. // Grab the registry lock.
  342. // It serializes access to the global ModifiedId
  343. //
  344. LsapDbLockAcquire( &LsapDbState.RegistryLock );
  345. RegistryLocked = TRUE;
  346. ASSERT( SavedDsOperationCount == 0 ||
  347. InternalHandle->ObjectTypeId == PolicyObject );
  348. if ( LsapDbState.RegistryModificationCount > 0 ) {
  349. DbChanged = TRUE;
  350. //
  351. // No one should change the database on a read only transaction.
  352. //
  353. ASSERT( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION) );
  354. }
  355. }
  356. //
  357. // If the DbChanged,
  358. // increment the NT 4 change serial number.
  359. //
  360. if ( DbChanged ) {
  361. OriginalModifiedId = LsapDbState.PolicyModificationInfo.ModifiedId;
  362. RestoreModifiedId = TRUE;
  363. //
  364. // Increment Modification Count.
  365. //
  366. //
  367. // we want to increment the modification count only if we
  368. // are running on a DC
  369. //
  370. // see bug# 327474
  371. //
  372. if (LsapProductType == NtProductLanManNt)
  373. {
  374. LsapDbState.PolicyModificationInfo.ModifiedId.QuadPart +=
  375. Increment.QuadPart;
  376. }
  377. if ( FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) ) {
  378. Status = LsapRegOpenTransaction();
  379. if ( !NT_SUCCESS( Status ) ) {
  380. goto Cleanup;
  381. }
  382. Options &= ~LSAP_DB_READ_ONLY_TRANSACTION;
  383. }
  384. Status = LsapDbWriteAttributeObject( LsapDbHandle,
  385. &LsapDbNames[ PolMod ],
  386. &LsapDbState.PolicyModificationInfo,
  387. (ULONG) sizeof (POLICY_MODIFICATION_INFO) );
  388. if (!NT_SUCCESS(Status)) {
  389. goto Cleanup;
  390. }
  391. Notify = TRUE;
  392. //
  393. // Invalidate the cache for the Policy Modification Information
  394. //
  395. LsapDbMakeInvalidInformationPolicy( PolicyModificationInformation );
  396. }
  397. } else {
  398. Notify = FALSE;
  399. }
  400. //
  401. // If there is a registry transaction in progress,
  402. // apply it.
  403. //
  404. if ( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) ) {
  405. // Either we locked it or our caller did
  406. ASSERT( LsapDbIsLocked( &LsapDbState.RegistryLock ));
  407. //
  408. // Apply the Registry Transaction.
  409. //
  410. Status = LsapRegApplyTransaction( );
  411. if ( !NT_SUCCESS( Status ) ) {
  412. goto Cleanup;
  413. }
  414. RegApplied = TRUE;
  415. }
  416. //
  417. // Notify the Replicator
  418. //
  419. if ( Notify ) {
  420. Status = LsapDbNotifyChangeObject( ObjectHandle, SecurityDbDeltaType );
  421. if (!NT_SUCCESS(Status)) {
  422. goto Cleanup;
  423. }
  424. }
  425. Status = STATUS_SUCCESS;
  426. Cleanup:
  427. if ( !NT_SUCCESS(Status) ) {
  428. //
  429. // Transaction failed. Adjust in-memory copy of the Modification
  430. // Count, noting that backing store copy is unaltered.
  431. //
  432. if ( RestoreModifiedId ) {
  433. LsapDbState.PolicyModificationInfo.ModifiedId = OriginalModifiedId;
  434. }
  435. //
  436. // Abort the registry transaction
  437. // (Unless the isn't one or it has already been applied.)
  438. //
  439. if ( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) && !RegApplied ) {
  440. (VOID) LsapRegAbortTransaction( );
  441. }
  442. }
  443. if ( RegistryLocked ) {
  444. LsapDbLockRelease( &LsapDbState.RegistryLock );
  445. }
  446. if ( CurrentThreadInfo ) {
  447. LsapClearThreadInfo();
  448. }
  449. return( Status );
  450. }
  451. NTSTATUS
  452. LsapDbAbortTransaction(
  453. IN ULONG Options
  454. )
  455. /*++
  456. Routine Description:
  457. This function aborts a transaction within the LSA Database.
  458. WARNING: The Lsa Database must be in the locked state when this function
  459. is called.
  460. Arguments:
  461. None.
  462. Return Value:
  463. NTSTATUS - Standard Nt Result Code
  464. Result codes are those returned from the Registry Transaction
  465. Package.
  466. --*/
  467. {
  468. NTSTATUS Status = STATUS_SUCCESS;
  469. //
  470. // Verify that the LSA Database is locked
  471. // (One of many locks is locked.)
  472. // ASSERT (LsapDbIsLocked());
  473. //
  474. // Abort the Registry Transaction
  475. //
  476. if ( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) ) {
  477. ASSERT( LsapDbIsLocked( &LsapDbState.RegistryLock ));
  478. Status = LsapRegAbortTransaction( );
  479. ASSERT( NT_SUCCESS( Status ) );
  480. }
  481. if ( NT_SUCCESS( Status ) && LsapDsIsFunctionTableValid() ) {
  482. ASSERT( LsaDsStateInfo.DsFuncTable.pAbortTransaction );
  483. Status = (*LsaDsStateInfo.DsFuncTable.pAbortTransaction)( Options );
  484. ASSERT( NT_SUCCESS( Status ) );
  485. }
  486. return ( Status );
  487. }
  488. BOOLEAN
  489. LsapDbIsServerInitialized(
  490. )
  491. /*++
  492. Routine Description:
  493. This function indicates whether the Lsa Database Server is initialized.
  494. Arguments:
  495. None.
  496. Return Value:
  497. BOOLEAN - TRUE if the LSA Database Server is initialized, else FALSE.
  498. --*/
  499. {
  500. if (LsapDbState.DbServerInitialized) {
  501. return TRUE;
  502. } else {
  503. return FALSE;
  504. }
  505. }
  506. VOID
  507. LsapDbEnableReplicatorNotification(
  508. )
  509. /*++
  510. Routine Description:
  511. This function turns on Replicator Notification.
  512. Arguments:
  513. None.
  514. Return Value:
  515. None.
  516. --*/
  517. {
  518. LsapDbState.ReplicatorNotificationEnabled = TRUE;
  519. }
  520. VOID
  521. LsapDbDisableReplicatorNotification(
  522. )
  523. /*++
  524. Routine Description:
  525. This function turns off Replicator Notification.
  526. Arguments:
  527. None.
  528. Return Value:
  529. None.
  530. --*/
  531. {
  532. LsapDbState.ReplicatorNotificationEnabled = FALSE;
  533. }
  534. VOID
  535. LsapDbAcquireLockEx(
  536. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  537. IN ULONG Options
  538. )
  539. /*++
  540. Routine Description:
  541. This function manages the lock status of the LSA database for a given operation.
  542. The LSA no longer grabs a global lock for all operations. Instead, access locking only
  543. occurs for operations involving a write. Locks can be obtained for read or write, or
  544. converted between the two.
  545. Arguments:
  546. ObjectTypeId - Specifies the expected object type to which the handle
  547. relates. An error is returned if this type does not match the
  548. type contained in the handle.
  549. Options - Specifies optional additional actions including database state
  550. changes to be made, or actions not to be performed.
  551. LSAP_DB_READ_ONLY_TRANSACTION do not lock the registry lock
  552. Return Value:
  553. None
  554. --*/
  555. {
  556. BOOLEAN RegLock = FALSE;
  557. LsapDsDebugOut(( DEB_FTRACE, "LsapDbAcquireLockEx(%x,%x)\n",
  558. ObjectTypeId, Options ));
  559. ASSERT( ObjectTypeId == PolicyObject ||
  560. ObjectTypeId == TrustedDomainObject ||
  561. ObjectTypeId == AccountObject ||
  562. ObjectTypeId == SecretObject ||
  563. ObjectTypeId == NullObject ||
  564. ObjectTypeId == AllObject );
  565. //
  566. // Determine what lock we're talking about
  567. //
  568. switch ( ObjectTypeId ) {
  569. case PolicyObject:
  570. LsapDbLockAcquire( &LsapDbState.PolicyLock );
  571. RegLock = TRUE;
  572. break;
  573. case TrustedDomainObject:
  574. LsapDbAcquireWriteLockTrustedDomainList();
  575. break;
  576. case AccountObject:
  577. LsapDbLockAcquire( &LsapDbState.AccountLock );
  578. RegLock = TRUE;
  579. break;
  580. case SecretObject:
  581. LsapDbAcquireWriteLockTrustedDomainList();
  582. LsapDbLockAcquire( &LsapDbState.SecretLock );
  583. RegLock = TRUE;
  584. break;
  585. case NullObject:
  586. break;
  587. case AllObject:
  588. LsapDbLockAcquire( &LsapDbState.PolicyLock );
  589. LsapDbAcquireWriteLockTrustedDomainList();
  590. LsapDbLockAcquire( &LsapDbState.AccountLock );
  591. LsapDbLockAcquire( &LsapDbState.SecretLock );
  592. RegLock = TRUE;
  593. break;
  594. default:
  595. goto AcquireLockExExit;
  596. }
  597. //
  598. // See about the registry lock. Only take it after holding an object type lock.
  599. //
  600. if ( RegLock &&
  601. !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) ) {
  602. LsapDbLockAcquire( &LsapDbState.RegistryLock );
  603. }
  604. AcquireLockExExit:
  605. LsapDsDebugOut(( DEB_FTRACE, "LsapDbAcquireLockEx\n" ));
  606. return;
  607. }
  608. VOID
  609. LsapDbReleaseLockEx(
  610. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  611. IN ULONG Options
  612. )
  613. /*++
  614. Routine Description:
  615. This function releases the lock obtained in the previous function. Depending on the
  616. state of the preliminary status, the potentially opened transaction is either aborted or
  617. applied
  618. Arguments:
  619. ObjectTypeId - Specifies the expected object type to which the handle
  620. relates. An error is returned if this type does not match the
  621. type contained in the handle.
  622. Options - Specifies optional additional actions including database state
  623. changes to be made, or actions not to be performed.
  624. LSAP_DB_READ_ONLY_TRANSACTION do not release the registry lock
  625. Return Value:
  626. None
  627. --*/
  628. {
  629. BOOLEAN RegLock = FALSE;
  630. LsapDsDebugOut(( DEB_FTRACE, "LsapDbReleaseLockEx(%x,%x)\n",
  631. ObjectTypeId, Options ));
  632. //
  633. // Special-case check until reference count handling logic is fixed,
  634. // then it should go away.
  635. //
  636. if ( FLAG_ON( Options, LSAP_DB_NO_LOCK ) && !FLAG_ON( Options, LSAP_DB_LOCK ) ) {
  637. goto ReleaseLockExExit;
  638. }
  639. ASSERT( ObjectTypeId == PolicyObject ||
  640. ObjectTypeId == TrustedDomainObject ||
  641. ObjectTypeId == AccountObject ||
  642. ObjectTypeId == SecretObject ||
  643. ObjectTypeId == NullObject ||
  644. ObjectTypeId == AllObject );
  645. //
  646. // Determine what lock we're talking about
  647. //
  648. switch ( ObjectTypeId ) {
  649. case PolicyObject:
  650. LsapDbLockRelease( &LsapDbState.PolicyLock );
  651. RegLock = TRUE;
  652. break;
  653. case TrustedDomainObject:
  654. LsapDbReleaseLockTrustedDomainList();
  655. break;
  656. case AccountObject:
  657. LsapDbLockRelease( &LsapDbState.AccountLock );
  658. RegLock = TRUE;
  659. break;
  660. case SecretObject:
  661. LsapDbReleaseLockTrustedDomainList();
  662. LsapDbLockRelease( &LsapDbState.SecretLock );
  663. RegLock = TRUE;
  664. break;
  665. case NullObject:
  666. break;
  667. case AllObject:
  668. LsapDbLockRelease( &LsapDbState.PolicyLock );
  669. LsapDbReleaseLockTrustedDomainList();
  670. LsapDbLockRelease( &LsapDbState.AccountLock );
  671. LsapDbLockRelease( &LsapDbState.SecretLock );
  672. RegLock = TRUE;
  673. break;
  674. default:
  675. goto ReleaseLockExExit;
  676. }
  677. //
  678. // See about the registry lock
  679. //
  680. if ( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) && RegLock ) {
  681. #if DBG
  682. HANDLE CurrentThread =(HANDLE) (NtCurrentTeb())->ClientId.UniqueThread;
  683. ASSERT( LsapDbState.RegistryLock.CriticalSection.OwningThread==CurrentThread);
  684. ASSERT( LsapDbIsLocked(&LsapDbState.RegistryLock));
  685. #endif
  686. ASSERT( LsapDbState.RegistryTransactionOpen == FALSE );
  687. LsapDbLockRelease( &LsapDbState.RegistryLock );
  688. }
  689. ReleaseLockExExit:
  690. LsapDsDebugOut(( DEB_FTRACE, "LsapDbReleaseLockEx\n" ));
  691. return;
  692. }
  693. PLSADS_PER_THREAD_INFO
  694. LsapCreateThreadInfo(
  695. VOID
  696. )
  697. /*++
  698. Routine Description:
  699. This function will create a thread info structure to be used to maintain state on
  700. the current operation while a ds/registry operation is happening
  701. If a thread info is currently active on the thread, it's ref count is incremented
  702. Arguments:
  703. NONE
  704. Return Value:
  705. Created thread info on success
  706. NULL on failure
  707. --*/
  708. {
  709. PLSADS_PER_THREAD_INFO CurrentThreadInfo = NULL;
  710. CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
  711. //
  712. // If we have a current operation state, increment it's use count so we know how many
  713. // times we have been called...
  714. //
  715. if ( CurrentThreadInfo ) {
  716. CurrentThreadInfo->UseCount++;
  717. } else {
  718. //
  719. // Have to allocate one
  720. //
  721. CurrentThreadInfo = LsapAllocateLsaHeap( sizeof( LSADS_PER_THREAD_INFO ) );
  722. if ( CurrentThreadInfo ) {
  723. if ( TlsSetValue( LsapDsThreadState, CurrentThreadInfo ) == FALSE ) {
  724. LsapDsDebugOut(( DEB_ERROR,
  725. "TlsSetValue for %p on %lu failed with %lu\n",
  726. CurrentThreadInfo,
  727. GetCurrentThreadId(),
  728. GetLastError() ));
  729. LsapFreeLsaHeap( CurrentThreadInfo );
  730. CurrentThreadInfo = NULL;
  731. } else {
  732. RtlZeroMemory( CurrentThreadInfo, sizeof( LSADS_PER_THREAD_INFO ) );
  733. CurrentThreadInfo->UseCount++;
  734. #if DBG
  735. //
  736. // Add ourselves to the list
  737. //
  738. SafeAcquireResourceExclusive( &LsapDsThreadInfoListResource, TRUE );
  739. {
  740. ULONG i;
  741. BOOLEAN Inserted = FALSE;
  742. for (i = 0; i < LSAP_THREAD_INFO_LIST_MAX; i++ ) {
  743. ASSERT( LsapDsThreadInfoList[ i ].ThreadId != GetCurrentThreadId( ));
  744. if ( LsapDsThreadInfoList[ i ].ThreadInfo == NULL ) {
  745. LsapDsThreadInfoList[ i ].ThreadInfo = CurrentThreadInfo;
  746. LsapDsThreadInfoList[ i ].ThreadId = GetCurrentThreadId( );
  747. Inserted = TRUE;
  748. break;
  749. }
  750. }
  751. if ( !Inserted ) {
  752. LsapDsDebugOut(( DEB_ERROR,
  753. "Failed to insert THREAD_INFO %p in list for %lu: "
  754. "List full\n",
  755. CurrentThreadInfo,
  756. GetCurrentThreadId() ));
  757. }
  758. }
  759. SafeReleaseResource( &LsapDsThreadInfoListResource );
  760. #endif
  761. }
  762. }
  763. }
  764. return( CurrentThreadInfo );
  765. }
  766. VOID
  767. LsapClearThreadInfo(
  768. VOID
  769. )
  770. /*++
  771. Routine Description:
  772. This function will remove a thread info structure to be used to maintain state on
  773. the current operation while a ds/registry operation is happening
  774. If a thread info's ref count is greater than 1, the ref count is decremented, but the
  775. thread info remains
  776. Arguments:
  777. NONE
  778. Return Value:
  779. VOID
  780. --*/
  781. {
  782. PLSADS_PER_THREAD_INFO CurrentThreadInfo = NULL;
  783. NTSTATUS Status;
  784. CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
  785. //
  786. // No thread info, nothing to do
  787. //
  788. if ( CurrentThreadInfo ) {
  789. if ( CurrentThreadInfo->UseCount > 1 ) {
  790. CurrentThreadInfo->UseCount--;
  791. } else {
  792. ASSERT( CurrentThreadInfo->UseCount == 1 );
  793. if ( CurrentThreadInfo->DsTransUseCount != 0 ) {
  794. ASSERT( CurrentThreadInfo->DsTransUseCount == 0 );
  795. LsapDsDebugOut(( DEB_ERROR,
  796. "Aborting transaction inside cleanup!\n" ));
  797. LsapDsCauseTransactionToCommitOrAbort( FALSE );
  798. }
  799. if ( CurrentThreadInfo->DsThreadStateUseCount != 0 ) {
  800. ASSERT( CurrentThreadInfo->DsThreadStateUseCount == 0 );
  801. LsapDsDebugOut(( DEB_ERROR,
  802. "Clear DS thread state inside cleanup!\n" ));
  803. Status = LsapDsMapDsReturnToStatus( THDestroy( ) );
  804. ASSERT( NT_SUCCESS( Status ) );
  805. THRestore( CurrentThreadInfo->InitialThreadState );
  806. CurrentThreadInfo->InitialThreadState = NULL;
  807. CurrentThreadInfo->DsThreadStateUseCount = 0;
  808. }
  809. #if DBG
  810. //
  811. // Remove ourselves from the list
  812. //
  813. SafeAcquireResourceExclusive( &LsapDsThreadInfoListResource, TRUE );
  814. {
  815. ULONG i;
  816. for (i = 0; i < LSAP_THREAD_INFO_LIST_MAX; i++ ) {
  817. if ( LsapDsThreadInfoList[ i ].ThreadId == GetCurrentThreadId( ) ) {
  818. ASSERT( LsapDsThreadInfoList[ i ].ThreadInfo == CurrentThreadInfo );
  819. LsapDsThreadInfoList[ i ].ThreadInfo = NULL;
  820. LsapDsThreadInfoList[ i ].ThreadId = 0;
  821. break;
  822. }
  823. }
  824. }
  825. SafeReleaseResource( &LsapDsThreadInfoListResource );
  826. #endif
  827. //
  828. // Clear the entry out of the thread local storage
  829. //
  830. if ( TlsSetValue( LsapDsThreadState, NULL ) == FALSE ) {
  831. LsapDsDebugOut(( DEB_ERROR,
  832. "Failed to remove %p for thread %lu: %lu\n",
  833. CurrentThreadInfo,
  834. GetCurrentThreadId(),
  835. GetLastError() ));
  836. }
  837. LsapFreeLsaHeap( CurrentThreadInfo );
  838. }
  839. }
  840. }
  841. VOID
  842. LsapSaveDsThreadState(
  843. VOID
  844. )
  845. /*++
  846. Routine Description:
  847. This function will save off the current DS thread state that may exist at the time
  848. the function is called. It does not distinguish between a thread state created by
  849. an outside caller (say SAM), or one created by Lsa itself
  850. If a thread info block does not exist at the time this function is called, nothing
  851. is done
  852. Calling this function refcounts the thread info
  853. Arguments:
  854. NONE
  855. Return Value:
  856. VOID
  857. --*/
  858. {
  859. PLSADS_PER_THREAD_INFO CurrentThreadInfo = NULL;
  860. CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
  861. //
  862. // No thread info, nothing to do
  863. //
  864. if ( CurrentThreadInfo ) {
  865. ASSERT( CurrentThreadInfo->UseCount > 0 );
  866. CurrentThreadInfo->UseCount++;
  867. ASSERT( !CurrentThreadInfo->SavedTransactionValid );
  868. CurrentThreadInfo->SavedTransactionValid = TRUE;
  869. CurrentThreadInfo->SavedThreadState = THSave();
  870. }
  871. }
  872. VOID
  873. LsapRestoreDsThreadState(
  874. VOID
  875. )
  876. /*++
  877. Routine Description:
  878. This function will restore a previously saved DS thread state
  879. If a thread info block does not exist at the time this function is called or there is
  880. no previously saved state exists, nothing is done
  881. Calling this function refcounts the thread info
  882. Arguments:
  883. NONE
  884. Return Value:
  885. VOID
  886. --*/
  887. {
  888. PLSADS_PER_THREAD_INFO CurrentThreadInfo = NULL;
  889. CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
  890. //
  891. // No thread info, nothing to do
  892. //
  893. if ( CurrentThreadInfo ) {
  894. CurrentThreadInfo->UseCount--;
  895. ASSERT( CurrentThreadInfo->UseCount > 0 );
  896. if ( CurrentThreadInfo->SavedTransactionValid == TRUE ) {
  897. CurrentThreadInfo->SavedTransactionValid = FALSE;
  898. if ( CurrentThreadInfo->SavedThreadState ) {
  899. THRestore( CurrentThreadInfo->SavedThreadState );
  900. }
  901. CurrentThreadInfo->SavedThreadState = NULL;
  902. }
  903. }
  904. }
  905. VOID
  906. LsapServerRpcThreadReturnNotify(
  907. LPWSTR CallingFunction
  908. )
  909. /*++
  910. Routine Description:
  911. This API is called when an RPC thread which has a notify routine specified in the servers
  912. ACF file.
  913. Arguments:
  914. NONE
  915. Return Values:
  916. NONE
  917. --*/
  918. {
  919. #if DBG
  920. static BOOLEAN CleanAsRequired = TRUE;
  921. PLSADS_PER_THREAD_INFO CurrentThreadInfo = NULL;
  922. NTSTATUS Status;
  923. HANDLE ThreadHandle = GetCurrentThread();
  924. if ( ( LsaDsInitState == LsapDsNoDs ) ||
  925. ( LsaDsInitState == LsapDsUnknown ) )
  926. {
  927. return ;
  928. }
  929. CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
  930. ASSERT( CurrentThreadInfo == NULL );
  931. if ( CurrentThreadInfo ) {
  932. LsapDsDebugOut(( DEB_ERROR, "ThreadInfo left by %ws\n", CallingFunction ));
  933. LsapClearThreadInfo();
  934. }
  935. ASSERT( !THQuery() );
  936. if ( THQuery() ) {
  937. LsapDsDebugOut(( DEB_ERROR,
  938. "Open threadstate in cleanup. Aborting...\n" ));
  939. if ( SampExistsDsTransaction() ) {
  940. LsapDsDebugOut(( DEB_ERROR, "Ds transaction left by %ws\n", CallingFunction ));
  941. LsapDsCauseTransactionToCommitOrAbort( FALSE );
  942. THDestroy( );
  943. }
  944. }
  945. //
  946. // Make sure we are not holding any of the locks when we exit
  947. //
  948. #if 0
  949. ASSERT( ThreadHandle != LsapDbState.AccountLock.ExclusiveOwnerThread );
  950. ASSERT( ThreadHandle != LsapDbState.PolicyLock.ExclusiveOwnerThread );
  951. ASSERT( ThreadHandle != LsapDbState.SecretLock.ExclusiveOwnerThread );
  952. ASSERT( ThreadHandle != LsapDbState.RegistryLock.ExclusiveOwnerThread );
  953. #endif
  954. #endif
  955. UNREFERENCED_PARAMETER( CallingFunction );
  956. }
  957. NTSTATUS
  958. LsaIHealthCheck(
  959. IN OPTIONAL LSAPR_HANDLE DomainHandle,
  960. IN ULONG StateChange,
  961. IN OUT PVOID StateChangeData,
  962. IN OUT PULONG StateChangeDataLength
  963. )
  964. /*++
  965. Routine Description:
  966. This function is actually invoked by Sam to indicate that state of interest to the Lsa
  967. has changed, and provide that state to the Lsa. Specifically, currently, it is the Sam
  968. SessionKey
  969. This function USED to perform sanity checks within LSA. It was invoked from
  970. SAM on a regular basis. However, it was no longer needed. Instead, we took the
  971. function, leaving the appropriate export from lsasrv.dll, to obsfucate the fact that
  972. we are now using to pass the Sam encryption key back and forth...
  973. Arguments:
  974. DomainHandle - What domain this refers to. Null means the root domain
  975. StateChange - What Sam/other in process client state changed that LSA cares about. Can be:
  976. LSAI_SAM_STATE_SESS_KEY - SAM's session key has changed
  977. StateChangeData - What data has changed. Dependent on the type of the state change. The
  978. data format must be pre-agreed upon by the Lsa and the invoker.
  979. Return Values:
  980. None.
  981. --*/
  982. {
  983. NTSTATUS Status = STATUS_SUCCESS;
  984. UNICODE_STRING CipherKey;
  985. LsapEnterFunc( "LsaIHealthCheck" );
  986. UNREFERENCED_PARAMETER( DomainHandle );
  987. switch ( StateChange ) {
  988. case LSAI_SAM_STATE_SESS_KEY:
  989. //
  990. // Copy the syskey into memory
  991. //
  992. ASSERT(LSAP_SYSKEY_SIZE==*StateChangeDataLength);
  993. LsapDbSetSyskey(StateChangeData, LSAP_SYSKEY_SIZE);
  994. //
  995. // Now do a database upgrade if necessary
  996. //
  997. Status = LsapDbUpgradeRevision(TRUE, FALSE);
  998. break;
  999. case LSAI_SAM_STATE_UNROLL_SP4_ENCRYPTION:
  1000. CipherKey.Length = CipherKey.MaximumLength = (USHORT)*StateChangeDataLength;
  1001. CipherKey.Buffer = StateChangeData;
  1002. Status = LsapDbInitializeCipherKey( &CipherKey,
  1003. &LsapDbSP4SecretCipherKey );
  1004. break;
  1005. case LSAI_SAM_STATE_RETRIEVE_SESS_KEY:
  1006. //
  1007. // Return the syskey as part of state change data
  1008. //
  1009. if (NULL!=LsapDbSysKey)
  1010. {
  1011. RtlCopyMemory(StateChangeData, LsapDbSysKey, LSAP_SYSKEY_SIZE);
  1012. *StateChangeDataLength = LSAP_SYSKEY_SIZE;
  1013. }
  1014. else
  1015. {
  1016. Status = STATUS_UNSUCCESSFUL;
  1017. }
  1018. break;
  1019. case LSAI_SAM_STATE_CLEAR_SESS_KEY:
  1020. //
  1021. // Clear the syskey in memory
  1022. //
  1023. RtlZeroMemory(LsapDbSysKey,LSAP_SYSKEY_SIZE);
  1024. LsapDbSysKey = NULL;
  1025. break;
  1026. case LSAI_SAM_GENERATE_SESS_KEY:
  1027. //
  1028. // Generate a new syskey and perform the database upgrade
  1029. //
  1030. Status = LsapDbUpgradeRevision(TRUE,TRUE);
  1031. break;
  1032. case LSAI_SAM_STATE_OLD_SESS_KEY:
  1033. //
  1034. // Return the old syskey as part of state change data
  1035. //
  1036. if (NULL!=LsapDbOldSysKey)
  1037. {
  1038. RtlCopyMemory(StateChangeData, LsapDbOldSysKey, LSAP_SYSKEY_SIZE);
  1039. *StateChangeDataLength = LSAP_SYSKEY_SIZE;
  1040. }
  1041. else
  1042. {
  1043. Status = STATUS_UNSUCCESSFUL;
  1044. }
  1045. break;
  1046. default:
  1047. LsapDsDebugOut(( DEB_ERROR,
  1048. "Unhandled state change %lu\n", StateChange ));
  1049. break;
  1050. }
  1051. LsapExitFunc( "LsaIHealthCheck", Status );
  1052. return(Status);
  1053. }